Actual source code: tsdiscgrad.c
1: /*
2: Code for timestepping with discrete gradient integrators
3: */
4: #include <petsc/private/tsimpl.h>
5: #include <petscdm.h>
7: PetscBool DGCite = PETSC_FALSE;
8: const char DGCitation[] = "@article{Gonzalez1996,\n"
9: " title = {Time integration and discrete Hamiltonian systems},\n"
10: " author = {Oscar Gonzalez},\n"
11: " journal = {Journal of Nonlinear Science},\n"
12: " volume = {6},\n"
13: " pages = {449--467},\n"
14: " doi = {10.1007/978-1-4612-1246-1_10},\n"
15: " year = {1996}\n}\n";
17: typedef struct {
18: PetscReal stage_time;
19: Vec X0, X, Xdot;
20: void *funcCtx;
21: PetscBool gonzalez;
22: PetscErrorCode (*Sfunc)(TS, PetscReal, Vec, Mat, void *);
23: PetscErrorCode (*Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *);
24: PetscErrorCode (*Gfunc)(TS, PetscReal, Vec, Vec, void *);
25: } TS_DiscGrad;
27: static PetscErrorCode TSDiscGradGetX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
28: {
29: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
31: if (X0) {
32: if (dm && dm != ts->dm) DMGetNamedGlobalVector(dm, "TSDiscGrad_X0", X0);
33: else *X0 = ts->vec_sol;
34: }
35: if (Xdot) {
36: if (dm && dm != ts->dm) DMGetNamedGlobalVector(dm, "TSDiscGrad_Xdot", Xdot);
37: else *Xdot = dg->Xdot;
38: }
39: return 0;
40: }
42: static PetscErrorCode TSDiscGradRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
43: {
44: if (X0) {
45: if (dm && dm != ts->dm) DMRestoreNamedGlobalVector(dm, "TSDiscGrad_X0", X0);
46: }
47: if (Xdot) {
48: if (dm && dm != ts->dm) DMRestoreNamedGlobalVector(dm, "TSDiscGrad_Xdot", Xdot);
49: }
50: return 0;
51: }
53: static PetscErrorCode DMCoarsenHook_TSDiscGrad(DM fine, DM coarse, void *ctx)
54: {
55: return 0;
56: }
58: static PetscErrorCode DMRestrictHook_TSDiscGrad(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
59: {
60: TS ts = (TS)ctx;
61: Vec X0, Xdot, X0_c, Xdot_c;
63: TSDiscGradGetX0AndXdot(ts, fine, &X0, &Xdot);
64: TSDiscGradGetX0AndXdot(ts, coarse, &X0_c, &Xdot_c);
65: MatRestrict(restrct, X0, X0_c);
66: MatRestrict(restrct, Xdot, Xdot_c);
67: VecPointwiseMult(X0_c, rscale, X0_c);
68: VecPointwiseMult(Xdot_c, rscale, Xdot_c);
69: TSDiscGradRestoreX0AndXdot(ts, fine, &X0, &Xdot);
70: TSDiscGradRestoreX0AndXdot(ts, coarse, &X0_c, &Xdot_c);
71: return 0;
72: }
74: static PetscErrorCode DMSubDomainHook_TSDiscGrad(DM dm, DM subdm, void *ctx)
75: {
76: return 0;
77: }
79: static PetscErrorCode DMSubDomainRestrictHook_TSDiscGrad(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
80: {
81: TS ts = (TS)ctx;
82: Vec X0, Xdot, X0_sub, Xdot_sub;
84: TSDiscGradGetX0AndXdot(ts, dm, &X0, &Xdot);
85: TSDiscGradGetX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub);
87: VecScatterBegin(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD);
88: VecScatterEnd(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD);
90: VecScatterBegin(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD);
91: VecScatterEnd(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD);
93: TSDiscGradRestoreX0AndXdot(ts, dm, &X0, &Xdot);
94: TSDiscGradRestoreX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub);
95: return 0;
96: }
98: static PetscErrorCode TSSetUp_DiscGrad(TS ts)
99: {
100: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
101: DM dm;
103: if (!dg->X) VecDuplicate(ts->vec_sol, &dg->X);
104: if (!dg->X0) VecDuplicate(ts->vec_sol, &dg->X0);
105: if (!dg->Xdot) VecDuplicate(ts->vec_sol, &dg->Xdot);
107: TSGetDM(ts, &dm);
108: DMCoarsenHookAdd(dm, DMCoarsenHook_TSDiscGrad, DMRestrictHook_TSDiscGrad, ts);
109: DMSubDomainHookAdd(dm, DMSubDomainHook_TSDiscGrad, DMSubDomainRestrictHook_TSDiscGrad, ts);
110: return 0;
111: }
113: static PetscErrorCode TSSetFromOptions_DiscGrad(TS ts, PetscOptionItems *PetscOptionsObject)
114: {
115: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
117: PetscOptionsHeadBegin(PetscOptionsObject, "Discrete Gradients ODE solver options");
118: {
119: PetscOptionsBool("-ts_discgrad_gonzalez", "Use Gonzalez term in discrete gradients formulation", "TSDiscGradUseGonzalez", dg->gonzalez, &dg->gonzalez, NULL);
120: }
121: PetscOptionsHeadEnd();
122: return 0;
123: }
125: static PetscErrorCode TSView_DiscGrad(TS ts, PetscViewer viewer)
126: {
127: PetscBool iascii;
129: PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);
130: if (iascii) PetscViewerASCIIPrintf(viewer, " Discrete Gradients\n");
131: return 0;
132: }
134: static PetscErrorCode TSDiscGradIsGonzalez_DiscGrad(TS ts, PetscBool *gonzalez)
135: {
136: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
138: *gonzalez = dg->gonzalez;
139: return 0;
140: }
142: static PetscErrorCode TSDiscGradUseGonzalez_DiscGrad(TS ts, PetscBool flg)
143: {
144: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
146: dg->gonzalez = flg;
147: return 0;
148: }
150: static PetscErrorCode TSReset_DiscGrad(TS ts)
151: {
152: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
154: VecDestroy(&dg->X);
155: VecDestroy(&dg->X0);
156: VecDestroy(&dg->Xdot);
157: return 0;
158: }
160: static PetscErrorCode TSDestroy_DiscGrad(TS ts)
161: {
162: DM dm;
164: TSReset_DiscGrad(ts);
165: TSGetDM(ts, &dm);
166: if (dm) {
167: DMCoarsenHookRemove(dm, DMCoarsenHook_TSDiscGrad, DMRestrictHook_TSDiscGrad, ts);
168: DMSubDomainHookRemove(dm, DMSubDomainHook_TSDiscGrad, DMSubDomainRestrictHook_TSDiscGrad, ts);
169: }
170: PetscFree(ts->data);
171: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradGetFormulation_C", NULL);
172: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradSetFormulation_C", NULL);
173: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradIsGonzalez_C", NULL);
174: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradUseGonzalez_C", NULL);
175: return 0;
176: }
178: static PetscErrorCode TSInterpolate_DiscGrad(TS ts, PetscReal t, Vec X)
179: {
180: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
181: PetscReal dt = t - ts->ptime;
183: VecCopy(ts->vec_sol, dg->X);
184: VecWAXPY(X, dt, dg->Xdot, dg->X);
185: return 0;
186: }
188: static PetscErrorCode TSDiscGrad_SNESSolve(TS ts, Vec b, Vec x)
189: {
190: SNES snes;
191: PetscInt nits, lits;
193: TSGetSNES(ts, &snes);
194: SNESSolve(snes, b, x);
195: SNESGetIterationNumber(snes, &nits);
196: SNESGetLinearSolveIterations(snes, &lits);
197: ts->snes_its += nits;
198: ts->ksp_its += lits;
199: return 0;
200: }
202: static PetscErrorCode TSStep_DiscGrad(TS ts)
203: {
204: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
205: TSAdapt adapt;
206: TSStepStatus status = TS_STEP_INCOMPLETE;
207: PetscInt rejections = 0;
208: PetscBool stageok, accept = PETSC_TRUE;
209: PetscReal next_time_step = ts->time_step;
211: TSGetAdapt(ts, &adapt);
212: if (!ts->steprollback) VecCopy(ts->vec_sol, dg->X0);
214: while (!ts->reason && status != TS_STEP_COMPLETE) {
215: PetscReal shift = 1 / (0.5 * ts->time_step);
217: dg->stage_time = ts->ptime + 0.5 * ts->time_step;
219: VecCopy(dg->X0, dg->X);
220: TSPreStage(ts, dg->stage_time);
221: TSDiscGrad_SNESSolve(ts, NULL, dg->X);
222: TSPostStage(ts, dg->stage_time, 0, &dg->X);
223: TSAdaptCheckStage(adapt, ts, dg->stage_time, dg->X, &stageok);
224: if (!stageok) goto reject_step;
226: status = TS_STEP_PENDING;
227: VecAXPBYPCZ(dg->Xdot, -shift, shift, 0, dg->X0, dg->X);
228: VecAXPY(ts->vec_sol, ts->time_step, dg->Xdot);
229: TSAdaptChoose(adapt, ts, ts->time_step, NULL, &next_time_step, &accept);
230: status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
231: if (!accept) {
232: VecCopy(dg->X0, ts->vec_sol);
233: ts->time_step = next_time_step;
234: goto reject_step;
235: }
236: ts->ptime += ts->time_step;
237: ts->time_step = next_time_step;
238: break;
240: reject_step:
241: ts->reject++;
242: accept = PETSC_FALSE;
243: if (!ts->reason && ts->max_reject >= 0 && ++rejections > ts->max_reject) {
244: ts->reason = TS_DIVERGED_STEP_REJECTED;
245: PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections);
246: }
247: }
248: return 0;
249: }
251: static PetscErrorCode TSGetStages_DiscGrad(TS ts, PetscInt *ns, Vec **Y)
252: {
253: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
255: if (ns) *ns = 1;
256: if (Y) *Y = &(dg->X);
257: return 0;
258: }
260: /*
261: This defines the nonlinear equation that is to be solved with SNES
262: G(U) = F[t0 + 0.5*dt, U, (U-U0)/dt] = 0
263: */
265: /* x = (x+x')/2 */
266: /* NEED TO CALCULATE x_{n+1} from x and x_{n}*/
267: static PetscErrorCode SNESTSFormFunction_DiscGrad(SNES snes, Vec x, Vec y, TS ts)
268: {
269: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
270: PetscReal norm, shift = 1 / (0.5 * ts->time_step);
271: PetscInt n;
272: Vec X0, Xdot, Xp, Xdiff;
273: Mat S;
274: PetscScalar F = 0, F0 = 0, Gp;
275: Vec G, SgF;
276: DM dm, dmsave;
278: SNESGetDM(snes, &dm);
280: VecDuplicate(y, &Xp);
281: VecDuplicate(y, &Xdiff);
282: VecDuplicate(y, &SgF);
283: VecDuplicate(y, &G);
285: VecGetLocalSize(y, &n);
286: MatCreate(PETSC_COMM_WORLD, &S);
287: MatSetSizes(S, PETSC_DECIDE, PETSC_DECIDE, n, n);
288: MatSetFromOptions(S);
289: MatSetUp(S);
290: MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
291: MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
293: TSDiscGradGetX0AndXdot(ts, dm, &X0, &Xdot);
294: VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x); /* Xdot = shift (x - X0) */
296: VecAXPBYPCZ(Xp, -1, 2, 0, X0, x); /* Xp = 2*x - X0 + (0)*Xmid */
297: VecAXPBYPCZ(Xdiff, -1, 1, 0, X0, Xp); /* Xdiff = xp - X0 + (0)*Xdiff */
299: if (dg->gonzalez) {
300: (*dg->Sfunc)(ts, dg->stage_time, x, S, dg->funcCtx);
301: (*dg->Ffunc)(ts, dg->stage_time, Xp, &F, dg->funcCtx);
302: (*dg->Ffunc)(ts, dg->stage_time, X0, &F0, dg->funcCtx);
303: (*dg->Gfunc)(ts, dg->stage_time, x, G, dg->funcCtx);
305: /* Adding Extra Gonzalez Term */
306: VecDot(Xdiff, G, &Gp);
307: VecNorm(Xdiff, NORM_2, &norm);
308: if (norm < PETSC_SQRT_MACHINE_EPSILON) {
309: Gp = 0;
310: } else {
311: /* Gp = (1/|xn+1 - xn|^2) * (F(xn+1) - F(xn) - Gp) */
312: Gp = (F - F0 - Gp) / PetscSqr(norm);
313: }
314: VecAXPY(G, Gp, Xdiff);
315: MatMult(S, G, SgF); /* S*gradF */
317: } else {
318: (*dg->Sfunc)(ts, dg->stage_time, x, S, dg->funcCtx);
319: (*dg->Gfunc)(ts, dg->stage_time, x, G, dg->funcCtx);
321: MatMult(S, G, SgF); /* Xdot = S*gradF */
322: }
323: /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
324: dmsave = ts->dm;
325: ts->dm = dm;
326: VecAXPBYPCZ(y, 1, -1, 0, Xdot, SgF);
327: ts->dm = dmsave;
328: TSDiscGradRestoreX0AndXdot(ts, dm, &X0, &Xdot);
330: VecDestroy(&Xp);
331: VecDestroy(&Xdiff);
332: VecDestroy(&SgF);
333: VecDestroy(&G);
334: MatDestroy(&S);
336: return 0;
337: }
339: static PetscErrorCode SNESTSFormJacobian_DiscGrad(SNES snes, Vec x, Mat A, Mat B, TS ts)
340: {
341: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
342: PetscReal shift = 1 / (0.5 * ts->time_step);
343: Vec Xdot;
344: DM dm, dmsave;
346: SNESGetDM(snes, &dm);
347: /* Xdot has already been computed in SNESTSFormFunction_DiscGrad (SNES guarantees this) */
348: TSDiscGradGetX0AndXdot(ts, dm, NULL, &Xdot);
350: dmsave = ts->dm;
351: ts->dm = dm;
352: TSComputeIJacobian(ts, dg->stage_time, x, Xdot, shift, A, B, PETSC_FALSE);
353: ts->dm = dmsave;
354: TSDiscGradRestoreX0AndXdot(ts, dm, NULL, &Xdot);
355: return 0;
356: }
358: static PetscErrorCode TSDiscGradGetFormulation_DiscGrad(TS ts, PetscErrorCode (**Sfunc)(TS, PetscReal, Vec, Mat, void *), PetscErrorCode (**Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *), PetscErrorCode (**Gfunc)(TS, PetscReal, Vec, Vec, void *), void *ctx)
359: {
360: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
362: *Sfunc = dg->Sfunc;
363: *Ffunc = dg->Ffunc;
364: *Gfunc = dg->Gfunc;
365: return 0;
366: }
368: static PetscErrorCode TSDiscGradSetFormulation_DiscGrad(TS ts, PetscErrorCode (*Sfunc)(TS, PetscReal, Vec, Mat, void *), PetscErrorCode (*Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *), PetscErrorCode (*Gfunc)(TS, PetscReal, Vec, Vec, void *), void *ctx)
369: {
370: TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
372: dg->Sfunc = Sfunc;
373: dg->Ffunc = Ffunc;
374: dg->Gfunc = Gfunc;
375: dg->funcCtx = ctx;
376: return 0;
377: }
379: /*MC
380: TSDISCGRAD - ODE solver using the discrete gradients version of the implicit midpoint method
382: Level: intermediate
384: Notes:
385: This is the implicit midpoint rule, with an optional term that guarantees the discrete gradient property. This
386: timestepper applies to systems of the form
387: $ u_t = S(u) grad F(u)
388: where S(u) is a linear operator, and F is a functional of u.
390: .seealso: [](chapter_ts), `TSCreate()`, `TSSetType()`, `TS`, `TSDISCGRAD`, `TSDiscGradSetFormulation()`
391: M*/
392: PETSC_EXTERN PetscErrorCode TSCreate_DiscGrad(TS ts)
393: {
394: TS_DiscGrad *th;
396: PetscCitationsRegister(DGCitation, &DGCite);
397: ts->ops->reset = TSReset_DiscGrad;
398: ts->ops->destroy = TSDestroy_DiscGrad;
399: ts->ops->view = TSView_DiscGrad;
400: ts->ops->setfromoptions = TSSetFromOptions_DiscGrad;
401: ts->ops->setup = TSSetUp_DiscGrad;
402: ts->ops->step = TSStep_DiscGrad;
403: ts->ops->interpolate = TSInterpolate_DiscGrad;
404: ts->ops->getstages = TSGetStages_DiscGrad;
405: ts->ops->snesfunction = SNESTSFormFunction_DiscGrad;
406: ts->ops->snesjacobian = SNESTSFormJacobian_DiscGrad;
407: ts->default_adapt_type = TSADAPTNONE;
409: ts->usessnes = PETSC_TRUE;
411: PetscNew(&th);
412: ts->data = (void *)th;
414: th->gonzalez = PETSC_FALSE;
416: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradGetFormulation_C", TSDiscGradGetFormulation_DiscGrad);
417: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradSetFormulation_C", TSDiscGradSetFormulation_DiscGrad);
418: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradIsGonzalez_C", TSDiscGradIsGonzalez_DiscGrad);
419: PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradUseGonzalez_C", TSDiscGradUseGonzalez_DiscGrad);
420: return 0;
421: }
423: /*@C
424: TSDiscGradGetFormulation - Get the construction method for S, F, and grad F from the formulation u_t = S grad F for `TSDISCGRAD`
426: Not Collective
428: Input Parameter:
429: . ts - timestepping context
431: Output Parameters:
432: + Sfunc - constructor for the S matrix from the formulation
433: . Ffunc - functional F from the formulation
434: . Gfunc - constructor for the gradient of F from the formulation
435: - ctx - the user context
437: Calling sequence of Sfunc:
438: $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Mat S, void *)
440: Calling sequence of Ffunc:
441: $ PetscErrorCode func(TS ts, PetscReal time, Vec u, PetscScalar *F, void *)
443: Calling sequence of Gfunc:
444: $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Vec G, void *)
446: Level: intermediate
448: .seealso: [](chapter_ts), `TS`, `TSDISCGRAD`, `TSDiscGradSetFormulation()`
449: @*/
450: PetscErrorCode TSDiscGradGetFormulation(TS ts, PetscErrorCode (**Sfunc)(TS, PetscReal, Vec, Mat, void *), PetscErrorCode (**Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *), PetscErrorCode (**Gfunc)(TS, PetscReal, Vec, Vec, void *), void *ctx)
451: {
456: PetscUseMethod(ts, "TSDiscGradGetFormulation_C", (TS, PetscErrorCode(**Sfunc)(TS, PetscReal, Vec, Mat, void *), PetscErrorCode(**Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *), PetscErrorCode(**Gfunc)(TS, PetscReal, Vec, Vec, void *), void *), (ts, Sfunc, Ffunc, Gfunc, ctx));
457: return 0;
458: }
460: /*@C
461: TSDiscGradSetFormulation - Set the construction method for S, F, and grad F from the formulation u_t = S(u) grad F(u) for `TSDISCGRAD`
463: Not Collective
465: Input Parameters:
466: + ts - timestepping context
467: . Sfunc - constructor for the S matrix from the formulation
468: . Ffunc - functional F from the formulation
469: - Gfunc - constructor for the gradient of F from the formulation
470: Calling sequence of Sfunc:
471: $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Mat S, void *)
473: Calling sequence of Ffunc:
474: $ PetscErrorCode func(TS ts, PetscReal time, Vec u, PetscScalar *F, void *)
476: Calling sequence of Gfunc:
477: $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Vec G, void *)
479: Level: Intermediate
481: .seealso: [](chapter_ts), `TSDISCGRAD`, `TSDiscGradGetFormulation()`
482: @*/
483: PetscErrorCode TSDiscGradSetFormulation(TS ts, PetscErrorCode (*Sfunc)(TS, PetscReal, Vec, Mat, void *), PetscErrorCode (*Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *), PetscErrorCode (*Gfunc)(TS, PetscReal, Vec, Vec, void *), void *ctx)
484: {
489: PetscTryMethod(ts, "TSDiscGradSetFormulation_C", (TS, PetscErrorCode(*Sfunc)(TS, PetscReal, Vec, Mat, void *), PetscErrorCode(*Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *), PetscErrorCode(*Gfunc)(TS, PetscReal, Vec, Vec, void *), void *), (ts, Sfunc, Ffunc, Gfunc, ctx));
490: return 0;
491: }
493: /*@
494: TSDiscGradIsGonzalez - Checks flag for whether to use additional conservative terms in discrete gradient formulation for `TSDISCGRAD`
496: Not Collective
498: Input Parameter:
499: . ts - timestepping context
501: Output Parameter:
502: . gonzalez - `PETSC_TRUE` when using the Gonzalez term
504: Level: Advanced
506: .seealso: [](chapter_ts), `TSDISCGRAD`, `TSDiscGradUseGonzalez()`, `TSDISCGRAD`
507: @*/
508: PetscErrorCode TSDiscGradIsGonzalez(TS ts, PetscBool *gonzalez)
509: {
512: PetscUseMethod(ts, "TSDiscGradIsGonzalez_C", (TS, PetscBool *), (ts, gonzalez));
513: return 0;
514: }
516: /*@
517: TSDiscGradUseGonzalez - Sets discrete gradient formulation with or without additional conservative terms. Without flag, the discrete gradients timestepper is just backwards euler
519: Not Collective
521: Input Parameters:
522: + ts - timestepping context
523: - flg - `PETSC_TRUE` to use the Gonzalez term
525: Options Database Key:
526: . -ts_discgrad_gonzalez <flg> - use the Gonzalez term for the discrete gradient formulation
528: Level: Intermediate
530: .seealso: [](chapter_ts), `TSDISCGRAD`
531: @*/
532: PetscErrorCode TSDiscGradUseGonzalez(TS ts, PetscBool flg)
533: {
535: PetscTryMethod(ts, "TSDiscGradUseGonzalez_C", (TS, PetscBool), (ts, flg));
536: return 0;
537: }