xref: /petsc/src/ts/impls/implicit/discgrad/tsdiscgrad.c (revision 20f4b53cbb5e9bd9ef12b76a8697d60d197cda17)
140be0ff1SMatthew G. Knepley /*
240be0ff1SMatthew G. Knepley   Code for timestepping with discrete gradient integrators
340be0ff1SMatthew G. Knepley */
440be0ff1SMatthew G. Knepley #include <petsc/private/tsimpl.h> /*I   "petscts.h"   I*/
540be0ff1SMatthew G. Knepley #include <petscdm.h>
640be0ff1SMatthew G. Knepley 
740be0ff1SMatthew G. Knepley PetscBool  DGCite       = PETSC_FALSE;
840be0ff1SMatthew G. Knepley const char DGCitation[] = "@article{Gonzalez1996,\n"
940be0ff1SMatthew G. Knepley                           "  title   = {Time integration and discrete Hamiltonian systems},\n"
1040be0ff1SMatthew G. Knepley                           "  author  = {Oscar Gonzalez},\n"
1140be0ff1SMatthew G. Knepley                           "  journal = {Journal of Nonlinear Science},\n"
1240be0ff1SMatthew G. Knepley                           "  volume  = {6},\n"
1340be0ff1SMatthew G. Knepley                           "  pages   = {449--467},\n"
1440be0ff1SMatthew G. Knepley                           "  doi     = {10.1007/978-1-4612-1246-1_10},\n"
1540be0ff1SMatthew G. Knepley                           "  year    = {1996}\n}\n";
1640be0ff1SMatthew G. Knepley 
1740be0ff1SMatthew G. Knepley typedef struct {
1840be0ff1SMatthew G. Knepley   PetscReal stage_time;
1940be0ff1SMatthew G. Knepley   Vec       X0, X, Xdot;
20db4653c2SDaniel Finn   void     *funcCtx;
21db4653c2SDaniel Finn   PetscBool gonzalez;
2240be0ff1SMatthew G. Knepley   PetscErrorCode (*Sfunc)(TS, PetscReal, Vec, Mat, void *);
2340be0ff1SMatthew G. Knepley   PetscErrorCode (*Ffunc)(TS, PetscReal, Vec, PetscScalar *, void *);
2440be0ff1SMatthew G. Knepley   PetscErrorCode (*Gfunc)(TS, PetscReal, Vec, Vec, void *);
2540be0ff1SMatthew G. Knepley } TS_DiscGrad;
2640be0ff1SMatthew G. Knepley 
27d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDiscGradGetX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
28d71ae5a4SJacob Faibussowitsch {
2940be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
3040be0ff1SMatthew G. Knepley 
3140be0ff1SMatthew G. Knepley   PetscFunctionBegin;
3240be0ff1SMatthew G. Knepley   if (X0) {
339566063dSJacob Faibussowitsch     if (dm && dm != ts->dm) PetscCall(DMGetNamedGlobalVector(dm, "TSDiscGrad_X0", X0));
34ad540459SPierre Jolivet     else *X0 = ts->vec_sol;
3540be0ff1SMatthew G. Knepley   }
3640be0ff1SMatthew G. Knepley   if (Xdot) {
379566063dSJacob Faibussowitsch     if (dm && dm != ts->dm) PetscCall(DMGetNamedGlobalVector(dm, "TSDiscGrad_Xdot", Xdot));
38ad540459SPierre Jolivet     else *Xdot = dg->Xdot;
3940be0ff1SMatthew G. Knepley   }
403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4140be0ff1SMatthew G. Knepley }
4240be0ff1SMatthew G. Knepley 
43d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDiscGradRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
44d71ae5a4SJacob Faibussowitsch {
4540be0ff1SMatthew G. Knepley   PetscFunctionBegin;
4640be0ff1SMatthew G. Knepley   if (X0) {
479566063dSJacob Faibussowitsch     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSDiscGrad_X0", X0));
4840be0ff1SMatthew G. Knepley   }
4940be0ff1SMatthew G. Knepley   if (Xdot) {
509566063dSJacob Faibussowitsch     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSDiscGrad_Xdot", Xdot));
5140be0ff1SMatthew G. Knepley   }
523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5340be0ff1SMatthew G. Knepley }
5440be0ff1SMatthew G. Knepley 
55d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_TSDiscGrad(DM fine, DM coarse, void *ctx)
56d71ae5a4SJacob Faibussowitsch {
5740be0ff1SMatthew G. Knepley   PetscFunctionBegin;
583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5940be0ff1SMatthew G. Knepley }
6040be0ff1SMatthew G. Knepley 
61d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_TSDiscGrad(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
62d71ae5a4SJacob Faibussowitsch {
6340be0ff1SMatthew G. Knepley   TS  ts = (TS)ctx;
6440be0ff1SMatthew G. Knepley   Vec X0, Xdot, X0_c, Xdot_c;
6540be0ff1SMatthew G. Knepley 
6640be0ff1SMatthew G. Knepley   PetscFunctionBegin;
679566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, fine, &X0, &Xdot));
689566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
699566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, X0, X0_c));
709566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, Xdot, Xdot_c));
719566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(X0_c, rscale, X0_c));
729566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(Xdot_c, rscale, Xdot_c));
739566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, fine, &X0, &Xdot));
749566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7640be0ff1SMatthew G. Knepley }
7740be0ff1SMatthew G. Knepley 
78d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_TSDiscGrad(DM dm, DM subdm, void *ctx)
79d71ae5a4SJacob Faibussowitsch {
8040be0ff1SMatthew G. Knepley   PetscFunctionBegin;
813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8240be0ff1SMatthew G. Knepley }
8340be0ff1SMatthew G. Knepley 
84d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_TSDiscGrad(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
85d71ae5a4SJacob Faibussowitsch {
8640be0ff1SMatthew G. Knepley   TS  ts = (TS)ctx;
8740be0ff1SMatthew G. Knepley   Vec X0, Xdot, X0_sub, Xdot_sub;
8840be0ff1SMatthew G. Knepley 
8940be0ff1SMatthew G. Knepley   PetscFunctionBegin;
909566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, dm, &X0, &Xdot));
919566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
9240be0ff1SMatthew G. Knepley 
939566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
949566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
9540be0ff1SMatthew G. Knepley 
969566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
979566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
9840be0ff1SMatthew G. Knepley 
999566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, dm, &X0, &Xdot));
1009566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
1013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10240be0ff1SMatthew G. Knepley }
10340be0ff1SMatthew G. Knepley 
104d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_DiscGrad(TS ts)
105d71ae5a4SJacob Faibussowitsch {
10640be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
10740be0ff1SMatthew G. Knepley   DM           dm;
10840be0ff1SMatthew G. Knepley 
10940be0ff1SMatthew G. Knepley   PetscFunctionBegin;
1109566063dSJacob Faibussowitsch   if (!dg->X) PetscCall(VecDuplicate(ts->vec_sol, &dg->X));
1119566063dSJacob Faibussowitsch   if (!dg->X0) PetscCall(VecDuplicate(ts->vec_sol, &dg->X0));
1129566063dSJacob Faibussowitsch   if (!dg->Xdot) PetscCall(VecDuplicate(ts->vec_sol, &dg->Xdot));
11340be0ff1SMatthew G. Knepley 
1149566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
1159566063dSJacob Faibussowitsch   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSDiscGrad, DMRestrictHook_TSDiscGrad, ts));
1169566063dSJacob Faibussowitsch   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSDiscGrad, DMSubDomainRestrictHook_TSDiscGrad, ts));
1173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11840be0ff1SMatthew G. Knepley }
11940be0ff1SMatthew G. Knepley 
120d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetFromOptions_DiscGrad(TS ts, PetscOptionItems *PetscOptionsObject)
121d71ae5a4SJacob Faibussowitsch {
122db4653c2SDaniel Finn   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
12340be0ff1SMatthew G. Knepley 
12440be0ff1SMatthew G. Knepley   PetscFunctionBegin;
125d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Discrete Gradients ODE solver options");
126d71ae5a4SJacob Faibussowitsch   {
127d71ae5a4SJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_discgrad_gonzalez", "Use Gonzalez term in discrete gradients formulation", "TSDiscGradUseGonzalez", dg->gonzalez, &dg->gonzalez, NULL));
128d71ae5a4SJacob Faibussowitsch   }
129d0609cedSBarry Smith   PetscOptionsHeadEnd();
1303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13140be0ff1SMatthew G. Knepley }
13240be0ff1SMatthew G. Knepley 
133d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_DiscGrad(TS ts, PetscViewer viewer)
134d71ae5a4SJacob Faibussowitsch {
13540be0ff1SMatthew G. Knepley   PetscBool iascii;
13640be0ff1SMatthew G. Knepley 
13740be0ff1SMatthew G. Knepley   PetscFunctionBegin;
1389566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
13948a46eb9SPierre Jolivet   if (iascii) PetscCall(PetscViewerASCIIPrintf(viewer, "  Discrete Gradients\n"));
1403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14140be0ff1SMatthew G. Knepley }
14240be0ff1SMatthew G. Knepley 
143d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDiscGradIsGonzalez_DiscGrad(TS ts, PetscBool *gonzalez)
144d71ae5a4SJacob Faibussowitsch {
145db4653c2SDaniel Finn   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
146db4653c2SDaniel Finn 
147db4653c2SDaniel Finn   PetscFunctionBegin;
148db4653c2SDaniel Finn   *gonzalez = dg->gonzalez;
1493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
150db4653c2SDaniel Finn }
151db4653c2SDaniel Finn 
152d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDiscGradUseGonzalez_DiscGrad(TS ts, PetscBool flg)
153d71ae5a4SJacob Faibussowitsch {
154db4653c2SDaniel Finn   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
155db4653c2SDaniel Finn 
156db4653c2SDaniel Finn   PetscFunctionBegin;
157db4653c2SDaniel Finn   dg->gonzalez = flg;
1583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159db4653c2SDaniel Finn }
160db4653c2SDaniel Finn 
161d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_DiscGrad(TS ts)
162d71ae5a4SJacob Faibussowitsch {
16340be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
16440be0ff1SMatthew G. Knepley 
16540be0ff1SMatthew G. Knepley   PetscFunctionBegin;
1669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dg->X));
1679566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dg->X0));
1689566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&dg->Xdot));
1693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17040be0ff1SMatthew G. Knepley }
17140be0ff1SMatthew G. Knepley 
172d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_DiscGrad(TS ts)
173d71ae5a4SJacob Faibussowitsch {
17440be0ff1SMatthew G. Knepley   DM dm;
17540be0ff1SMatthew G. Knepley 
17640be0ff1SMatthew G. Knepley   PetscFunctionBegin;
1779566063dSJacob Faibussowitsch   PetscCall(TSReset_DiscGrad(ts));
1789566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
17940be0ff1SMatthew G. Knepley   if (dm) {
1809566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookRemove(dm, DMCoarsenHook_TSDiscGrad, DMRestrictHook_TSDiscGrad, ts));
1819566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookRemove(dm, DMSubDomainHook_TSDiscGrad, DMSubDomainRestrictHook_TSDiscGrad, ts));
18240be0ff1SMatthew G. Knepley   }
1839566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
1849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradGetFormulation_C", NULL));
1859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradSetFormulation_C", NULL));
1862e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradIsGonzalez_C", NULL));
1872e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradUseGonzalez_C", NULL));
1883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18940be0ff1SMatthew G. Knepley }
19040be0ff1SMatthew G. Knepley 
191d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_DiscGrad(TS ts, PetscReal t, Vec X)
192d71ae5a4SJacob Faibussowitsch {
19340be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
19440be0ff1SMatthew G. Knepley   PetscReal    dt = t - ts->ptime;
19540be0ff1SMatthew G. Knepley 
19640be0ff1SMatthew G. Knepley   PetscFunctionBegin;
1979566063dSJacob Faibussowitsch   PetscCall(VecCopy(ts->vec_sol, dg->X));
1989566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(X, dt, dg->Xdot, dg->X));
1993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20040be0ff1SMatthew G. Knepley }
20140be0ff1SMatthew G. Knepley 
202d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDiscGrad_SNESSolve(TS ts, Vec b, Vec x)
203d71ae5a4SJacob Faibussowitsch {
20440be0ff1SMatthew G. Knepley   SNES     snes;
20540be0ff1SMatthew G. Knepley   PetscInt nits, lits;
20640be0ff1SMatthew G. Knepley 
20740be0ff1SMatthew G. Knepley   PetscFunctionBegin;
2089566063dSJacob Faibussowitsch   PetscCall(TSGetSNES(ts, &snes));
2099566063dSJacob Faibussowitsch   PetscCall(SNESSolve(snes, b, x));
2109566063dSJacob Faibussowitsch   PetscCall(SNESGetIterationNumber(snes, &nits));
2119566063dSJacob Faibussowitsch   PetscCall(SNESGetLinearSolveIterations(snes, &lits));
21240be0ff1SMatthew G. Knepley   ts->snes_its += nits;
21340be0ff1SMatthew G. Knepley   ts->ksp_its += lits;
2143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21540be0ff1SMatthew G. Knepley }
21640be0ff1SMatthew G. Knepley 
217d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_DiscGrad(TS ts)
218d71ae5a4SJacob Faibussowitsch {
21940be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
22040be0ff1SMatthew G. Knepley   TSAdapt      adapt;
22140be0ff1SMatthew G. Knepley   TSStepStatus status     = TS_STEP_INCOMPLETE;
22240be0ff1SMatthew G. Knepley   PetscInt     rejections = 0;
22340be0ff1SMatthew G. Knepley   PetscBool    stageok, accept = PETSC_TRUE;
22440be0ff1SMatthew G. Knepley   PetscReal    next_time_step = ts->time_step;
22540be0ff1SMatthew G. Knepley 
22640be0ff1SMatthew G. Knepley   PetscFunctionBegin;
2279566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts, &adapt));
2289566063dSJacob Faibussowitsch   if (!ts->steprollback) PetscCall(VecCopy(ts->vec_sol, dg->X0));
22940be0ff1SMatthew G. Knepley 
23040be0ff1SMatthew G. Knepley   while (!ts->reason && status != TS_STEP_COMPLETE) {
23140be0ff1SMatthew G. Knepley     PetscReal shift = 1 / (0.5 * ts->time_step);
23240be0ff1SMatthew G. Knepley 
23340be0ff1SMatthew G. Knepley     dg->stage_time = ts->ptime + 0.5 * ts->time_step;
23440be0ff1SMatthew G. Knepley 
2359566063dSJacob Faibussowitsch     PetscCall(VecCopy(dg->X0, dg->X));
2369566063dSJacob Faibussowitsch     PetscCall(TSPreStage(ts, dg->stage_time));
2379566063dSJacob Faibussowitsch     PetscCall(TSDiscGrad_SNESSolve(ts, NULL, dg->X));
2389566063dSJacob Faibussowitsch     PetscCall(TSPostStage(ts, dg->stage_time, 0, &dg->X));
2399566063dSJacob Faibussowitsch     PetscCall(TSAdaptCheckStage(adapt, ts, dg->stage_time, dg->X, &stageok));
24040be0ff1SMatthew G. Knepley     if (!stageok) goto reject_step;
24140be0ff1SMatthew G. Knepley 
24240be0ff1SMatthew G. Knepley     status = TS_STEP_PENDING;
2439566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(dg->Xdot, -shift, shift, 0, dg->X0, dg->X));
2449566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ts->vec_sol, ts->time_step, dg->Xdot));
2459566063dSJacob Faibussowitsch     PetscCall(TSAdaptChoose(adapt, ts, ts->time_step, NULL, &next_time_step, &accept));
24640be0ff1SMatthew G. Knepley     status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
24740be0ff1SMatthew G. Knepley     if (!accept) {
2489566063dSJacob Faibussowitsch       PetscCall(VecCopy(dg->X0, ts->vec_sol));
24940be0ff1SMatthew G. Knepley       ts->time_step = next_time_step;
25040be0ff1SMatthew G. Knepley       goto reject_step;
25140be0ff1SMatthew G. Knepley     }
25240be0ff1SMatthew G. Knepley     ts->ptime += ts->time_step;
25340be0ff1SMatthew G. Knepley     ts->time_step = next_time_step;
25440be0ff1SMatthew G. Knepley     break;
25540be0ff1SMatthew G. Knepley 
25640be0ff1SMatthew G. Knepley   reject_step:
2579371c9d4SSatish Balay     ts->reject++;
2589371c9d4SSatish Balay     accept = PETSC_FALSE;
25940be0ff1SMatthew G. Knepley     if (!ts->reason && ts->max_reject >= 0 && ++rejections > ts->max_reject) {
26040be0ff1SMatthew G. Knepley       ts->reason = TS_DIVERGED_STEP_REJECTED;
26163a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections));
26240be0ff1SMatthew G. Knepley     }
26340be0ff1SMatthew G. Knepley   }
2643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26540be0ff1SMatthew G. Knepley }
26640be0ff1SMatthew G. Knepley 
267d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGetStages_DiscGrad(TS ts, PetscInt *ns, Vec **Y)
268d71ae5a4SJacob Faibussowitsch {
26940be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
27040be0ff1SMatthew G. Knepley 
27140be0ff1SMatthew G. Knepley   PetscFunctionBegin;
27240be0ff1SMatthew G. Knepley   if (ns) *ns = 1;
27340be0ff1SMatthew G. Knepley   if (Y) *Y = &(dg->X);
2743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27540be0ff1SMatthew G. Knepley }
27640be0ff1SMatthew G. Knepley 
27740be0ff1SMatthew G. Knepley /*
27840be0ff1SMatthew G. Knepley   This defines the nonlinear equation that is to be solved with SNES
27940be0ff1SMatthew G. Knepley     G(U) = F[t0 + 0.5*dt, U, (U-U0)/dt] = 0
28040be0ff1SMatthew G. Knepley */
281db4653c2SDaniel Finn 
282db4653c2SDaniel Finn /* x = (x+x')/2 */
283db4653c2SDaniel Finn /* NEED TO CALCULATE x_{n+1} from x and x_{n}*/
284d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_DiscGrad(SNES snes, Vec x, Vec y, TS ts)
285d71ae5a4SJacob Faibussowitsch {
28640be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
287db4653c2SDaniel Finn   PetscReal    norm, shift = 1 / (0.5 * ts->time_step);
288db4653c2SDaniel Finn   PetscInt     n;
289db4653c2SDaniel Finn   Vec          X0, Xdot, Xp, Xdiff;
290db4653c2SDaniel Finn   Mat          S;
291db4653c2SDaniel Finn   PetscScalar  F = 0, F0 = 0, Gp;
292db4653c2SDaniel Finn   Vec          G, SgF;
29340be0ff1SMatthew G. Knepley   DM           dm, dmsave;
29440be0ff1SMatthew G. Knepley 
29540be0ff1SMatthew G. Knepley   PetscFunctionBegin;
2969566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
29740be0ff1SMatthew G. Knepley 
2989566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &Xp));
2999566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &Xdiff));
3009566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &SgF));
3019566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &G));
302db4653c2SDaniel Finn 
3039566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(y, &n));
3049566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, &S));
3059566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(S, PETSC_DECIDE, PETSC_DECIDE, n, n));
3069566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(S));
3079566063dSJacob Faibussowitsch   PetscCall(MatSetUp(S));
3089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY));
3099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY));
310db4653c2SDaniel Finn 
3119566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, dm, &X0, &Xdot));
3129566063dSJacob Faibussowitsch   PetscCall(VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x)); /* Xdot = shift (x - X0) */
313db4653c2SDaniel Finn 
3149566063dSJacob Faibussowitsch   PetscCall(VecAXPBYPCZ(Xp, -1, 2, 0, X0, x));     /* Xp = 2*x - X0 + (0)*Xmid */
3159566063dSJacob Faibussowitsch   PetscCall(VecAXPBYPCZ(Xdiff, -1, 1, 0, X0, Xp)); /* Xdiff = xp - X0 + (0)*Xdiff */
316db4653c2SDaniel Finn 
317db4653c2SDaniel Finn   if (dg->gonzalez) {
3189566063dSJacob Faibussowitsch     PetscCall((*dg->Sfunc)(ts, dg->stage_time, x, S, dg->funcCtx));
3199566063dSJacob Faibussowitsch     PetscCall((*dg->Ffunc)(ts, dg->stage_time, Xp, &F, dg->funcCtx));
3209566063dSJacob Faibussowitsch     PetscCall((*dg->Ffunc)(ts, dg->stage_time, X0, &F0, dg->funcCtx));
3219566063dSJacob Faibussowitsch     PetscCall((*dg->Gfunc)(ts, dg->stage_time, x, G, dg->funcCtx));
322db4653c2SDaniel Finn 
323db4653c2SDaniel Finn     /* Adding Extra Gonzalez Term */
3249566063dSJacob Faibussowitsch     PetscCall(VecDot(Xdiff, G, &Gp));
3259566063dSJacob Faibussowitsch     PetscCall(VecNorm(Xdiff, NORM_2, &norm));
326db4653c2SDaniel Finn     if (norm < PETSC_SQRT_MACHINE_EPSILON) {
327db4653c2SDaniel Finn       Gp = 0;
328db4653c2SDaniel Finn     } else {
329db4653c2SDaniel Finn       /* Gp = (1/|xn+1 - xn|^2) * (F(xn+1) - F(xn) - Gp) */
330db4653c2SDaniel Finn       Gp = (F - F0 - Gp) / PetscSqr(norm);
331db4653c2SDaniel Finn     }
3329566063dSJacob Faibussowitsch     PetscCall(VecAXPY(G, Gp, Xdiff));
3339566063dSJacob Faibussowitsch     PetscCall(MatMult(S, G, SgF)); /* S*gradF */
334db4653c2SDaniel Finn 
335db4653c2SDaniel Finn   } else {
3369566063dSJacob Faibussowitsch     PetscCall((*dg->Sfunc)(ts, dg->stage_time, x, S, dg->funcCtx));
3379566063dSJacob Faibussowitsch     PetscCall((*dg->Gfunc)(ts, dg->stage_time, x, G, dg->funcCtx));
338db4653c2SDaniel Finn 
3399566063dSJacob Faibussowitsch     PetscCall(MatMult(S, G, SgF)); /* Xdot = S*gradF */
340db4653c2SDaniel Finn   }
34140be0ff1SMatthew G. Knepley   /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
34240be0ff1SMatthew G. Knepley   dmsave = ts->dm;
34340be0ff1SMatthew G. Knepley   ts->dm = dm;
3449566063dSJacob Faibussowitsch   PetscCall(VecAXPBYPCZ(y, 1, -1, 0, Xdot, SgF));
34540be0ff1SMatthew G. Knepley   ts->dm = dmsave;
3469566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, dm, &X0, &Xdot));
347db4653c2SDaniel Finn 
3489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Xp));
3499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Xdiff));
3509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&SgF));
3519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&G));
3529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&S));
353db4653c2SDaniel Finn 
3543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35540be0ff1SMatthew G. Knepley }
35640be0ff1SMatthew G. Knepley 
357d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_DiscGrad(SNES snes, Vec x, Mat A, Mat B, TS ts)
358d71ae5a4SJacob Faibussowitsch {
35940be0ff1SMatthew G. Knepley   TS_DiscGrad *dg    = (TS_DiscGrad *)ts->data;
36040be0ff1SMatthew G. Knepley   PetscReal    shift = 1 / (0.5 * ts->time_step);
36140be0ff1SMatthew G. Knepley   Vec          Xdot;
36240be0ff1SMatthew G. Knepley   DM           dm, dmsave;
36340be0ff1SMatthew G. Knepley 
36440be0ff1SMatthew G. Knepley   PetscFunctionBegin;
3659566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
36640be0ff1SMatthew G. Knepley   /* Xdot has already been computed in SNESTSFormFunction_DiscGrad (SNES guarantees this) */
3679566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, dm, NULL, &Xdot));
36840be0ff1SMatthew G. Knepley 
36940be0ff1SMatthew G. Knepley   dmsave = ts->dm;
37040be0ff1SMatthew G. Knepley   ts->dm = dm;
3719566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, dg->stage_time, x, Xdot, shift, A, B, PETSC_FALSE));
37240be0ff1SMatthew G. Knepley   ts->dm = dmsave;
3739566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, dm, NULL, &Xdot));
3743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37540be0ff1SMatthew G. Knepley }
37640be0ff1SMatthew G. Knepley 
377d71ae5a4SJacob Faibussowitsch 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)
378d71ae5a4SJacob Faibussowitsch {
37940be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
38040be0ff1SMatthew G. Knepley 
38140be0ff1SMatthew G. Knepley   PetscFunctionBegin;
38240be0ff1SMatthew G. Knepley   *Sfunc = dg->Sfunc;
38340be0ff1SMatthew G. Knepley   *Ffunc = dg->Ffunc;
38440be0ff1SMatthew G. Knepley   *Gfunc = dg->Gfunc;
3853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38640be0ff1SMatthew G. Knepley }
38740be0ff1SMatthew G. Knepley 
388d71ae5a4SJacob Faibussowitsch 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)
389d71ae5a4SJacob Faibussowitsch {
39040be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
39140be0ff1SMatthew G. Knepley 
39240be0ff1SMatthew G. Knepley   PetscFunctionBegin;
39340be0ff1SMatthew G. Knepley   dg->Sfunc   = Sfunc;
39440be0ff1SMatthew G. Knepley   dg->Ffunc   = Ffunc;
39540be0ff1SMatthew G. Knepley   dg->Gfunc   = Gfunc;
396db4653c2SDaniel Finn   dg->funcCtx = ctx;
3973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39840be0ff1SMatthew G. Knepley }
39940be0ff1SMatthew G. Knepley 
40040be0ff1SMatthew G. Knepley /*MC
40140be0ff1SMatthew G. Knepley   TSDISCGRAD - ODE solver using the discrete gradients version of the implicit midpoint method
40240be0ff1SMatthew G. Knepley 
403bcf0153eSBarry Smith   Level: intermediate
404bcf0153eSBarry Smith 
4052ceb51e8SPatrick Sanan   Notes:
4062ceb51e8SPatrick Sanan   This is the implicit midpoint rule, with an optional term that guarantees the discrete gradient property. This
40740be0ff1SMatthew G. Knepley   timestepper applies to systems of the form
40840be0ff1SMatthew G. Knepley $ u_t = S(u) grad F(u)
40940be0ff1SMatthew G. Knepley   where S(u) is a linear operator, and F is a functional of u.
41040be0ff1SMatthew G. Knepley 
411bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSCreate()`, `TSSetType()`, `TS`, `TSDISCGRAD`, `TSDiscGradSetFormulation()`
41240be0ff1SMatthew G. Knepley M*/
413d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_DiscGrad(TS ts)
414d71ae5a4SJacob Faibussowitsch {
41540be0ff1SMatthew G. Knepley   TS_DiscGrad *th;
41640be0ff1SMatthew G. Knepley 
41740be0ff1SMatthew G. Knepley   PetscFunctionBegin;
4189566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(DGCitation, &DGCite));
41940be0ff1SMatthew G. Knepley   ts->ops->reset          = TSReset_DiscGrad;
42040be0ff1SMatthew G. Knepley   ts->ops->destroy        = TSDestroy_DiscGrad;
42140be0ff1SMatthew G. Knepley   ts->ops->view           = TSView_DiscGrad;
42240be0ff1SMatthew G. Knepley   ts->ops->setfromoptions = TSSetFromOptions_DiscGrad;
42340be0ff1SMatthew G. Knepley   ts->ops->setup          = TSSetUp_DiscGrad;
42440be0ff1SMatthew G. Knepley   ts->ops->step           = TSStep_DiscGrad;
42540be0ff1SMatthew G. Knepley   ts->ops->interpolate    = TSInterpolate_DiscGrad;
42640be0ff1SMatthew G. Knepley   ts->ops->getstages      = TSGetStages_DiscGrad;
42740be0ff1SMatthew G. Knepley   ts->ops->snesfunction   = SNESTSFormFunction_DiscGrad;
42840be0ff1SMatthew G. Knepley   ts->ops->snesjacobian   = SNESTSFormJacobian_DiscGrad;
42940be0ff1SMatthew G. Knepley   ts->default_adapt_type  = TSADAPTNONE;
43040be0ff1SMatthew G. Knepley 
43140be0ff1SMatthew G. Knepley   ts->usessnes = PETSC_TRUE;
43240be0ff1SMatthew G. Knepley 
4334dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&th));
43440be0ff1SMatthew G. Knepley   ts->data = (void *)th;
435db4653c2SDaniel Finn 
436db4653c2SDaniel Finn   th->gonzalez = PETSC_FALSE;
437db4653c2SDaniel Finn 
4389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradGetFormulation_C", TSDiscGradGetFormulation_DiscGrad));
4399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradSetFormulation_C", TSDiscGradSetFormulation_DiscGrad));
4409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradIsGonzalez_C", TSDiscGradIsGonzalez_DiscGrad));
4419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradUseGonzalez_C", TSDiscGradUseGonzalez_DiscGrad));
4423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44340be0ff1SMatthew G. Knepley }
44440be0ff1SMatthew G. Knepley 
44540be0ff1SMatthew G. Knepley /*@C
446bcf0153eSBarry Smith   TSDiscGradGetFormulation - Get the construction method for S, F, and grad F from the formulation u_t = S grad F for `TSDISCGRAD`
44740be0ff1SMatthew G. Knepley 
44840be0ff1SMatthew G. Knepley   Not Collective
44940be0ff1SMatthew G. Knepley 
45040be0ff1SMatthew G. Knepley   Input Parameter:
45140be0ff1SMatthew G. Knepley . ts - timestepping context
45240be0ff1SMatthew G. Knepley 
45340be0ff1SMatthew G. Knepley   Output Parameters:
45440be0ff1SMatthew G. Knepley + Sfunc - constructor for the S matrix from the formulation
45540be0ff1SMatthew G. Knepley . Ffunc - functional F from the formulation
456f1a722f8SMatthew G. Knepley . Gfunc - constructor for the gradient of F from the formulation
457f1a722f8SMatthew G. Knepley - ctx   - the user context
45840be0ff1SMatthew G. Knepley 
459*20f4b53cSBarry Smith   Calling sequence of `Sfunc`:
460*20f4b53cSBarry Smith $ PetscErrorCode Sfunc(TS ts, PetscReal time, Vec u, Mat S, void *ctx)
46140be0ff1SMatthew G. Knepley 
462*20f4b53cSBarry Smith   Calling sequence of `Ffunc`:
463*20f4b53cSBarry Smith $ PetscErrorCode Ffunc(TS ts, PetscReal time, Vec u, PetscScalar *F, void *ctx)
46440be0ff1SMatthew G. Knepley 
465*20f4b53cSBarry Smith   Calling sequence of `Gfunc`:
466*20f4b53cSBarry Smith $ PetscErrorCode Gfunc(TS ts, PetscReal time, Vec u, Vec G, void *ctx)
46740be0ff1SMatthew G. Knepley 
46840be0ff1SMatthew G. Knepley   Level: intermediate
46940be0ff1SMatthew G. Knepley 
470bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSDISCGRAD`, `TSDiscGradSetFormulation()`
47140be0ff1SMatthew G. Knepley @*/
472d71ae5a4SJacob Faibussowitsch 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)
473d71ae5a4SJacob Faibussowitsch {
47440be0ff1SMatthew G. Knepley   PetscFunctionBegin;
47540be0ff1SMatthew G. Knepley   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
47640be0ff1SMatthew G. Knepley   PetscValidPointer(Sfunc, 2);
47740be0ff1SMatthew G. Knepley   PetscValidPointer(Ffunc, 3);
47840be0ff1SMatthew G. Knepley   PetscValidPointer(Gfunc, 4);
479cac4c232SBarry Smith   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));
4803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48140be0ff1SMatthew G. Knepley }
48240be0ff1SMatthew G. Knepley 
48340be0ff1SMatthew G. Knepley /*@C
484bcf0153eSBarry Smith   TSDiscGradSetFormulation - Set the construction method for S, F, and grad F from the formulation u_t = S(u) grad F(u) for `TSDISCGRAD`
48540be0ff1SMatthew G. Knepley 
48640be0ff1SMatthew G. Knepley   Not Collective
48740be0ff1SMatthew G. Knepley 
48840be0ff1SMatthew G. Knepley   Input Parameters:
48940be0ff1SMatthew G. Knepley + ts    - timestepping context
49040be0ff1SMatthew G. Knepley . Sfunc - constructor for the S matrix from the formulation
49140be0ff1SMatthew G. Knepley . Ffunc - functional F from the formulation
49240be0ff1SMatthew G. Knepley - Gfunc - constructor for the gradient of F from the formulation
49340be0ff1SMatthew G. Knepley 
494*20f4b53cSBarry Smith   Calling sequence of `Sfunc`:
495*20f4b53cSBarry Smith $ PetscErrorCode Sfunc(TS ts, PetscReal time, Vec u, Mat S, void *ctx)
49640be0ff1SMatthew G. Knepley 
497*20f4b53cSBarry Smith   Calling sequence of `Ffunc`:
498*20f4b53cSBarry Smith $ PetscErrorCode Ffunc(TS ts, PetscReal time, Vec u, PetscScalar *F, void *ctx)
499*20f4b53cSBarry Smith 
500*20f4b53cSBarry Smith   Calling sequence of `Gfunc`:
501*20f4b53cSBarry Smith $ PetscErrorCode Gfunc(TS ts, PetscReal time, Vec u, Vec G, void *ctx)
50240be0ff1SMatthew G. Knepley 
50340be0ff1SMatthew G. Knepley   Level: Intermediate
50440be0ff1SMatthew G. Knepley 
505bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSDISCGRAD`, `TSDiscGradGetFormulation()`
50640be0ff1SMatthew G. Knepley @*/
507d71ae5a4SJacob Faibussowitsch 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)
508d71ae5a4SJacob Faibussowitsch {
50940be0ff1SMatthew G. Knepley   PetscFunctionBegin;
51040be0ff1SMatthew G. Knepley   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
51140be0ff1SMatthew G. Knepley   PetscValidFunction(Sfunc, 2);
51240be0ff1SMatthew G. Knepley   PetscValidFunction(Ffunc, 3);
51340be0ff1SMatthew G. Knepley   PetscValidFunction(Gfunc, 4);
514cac4c232SBarry Smith   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));
5153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
516db4653c2SDaniel Finn }
517db4653c2SDaniel Finn 
518db4653c2SDaniel Finn /*@
519bcf0153eSBarry Smith   TSDiscGradIsGonzalez - Checks flag for whether to use additional conservative terms in discrete gradient formulation for `TSDISCGRAD`
520db4653c2SDaniel Finn 
521db4653c2SDaniel Finn   Not Collective
522db4653c2SDaniel Finn 
523db4653c2SDaniel Finn   Input Parameter:
524db4653c2SDaniel Finn .  ts - timestepping context
525db4653c2SDaniel Finn 
526db4653c2SDaniel Finn   Output Parameter:
527bcf0153eSBarry Smith .  gonzalez - `PETSC_TRUE` when using the Gonzalez term
528db4653c2SDaniel Finn 
529db4653c2SDaniel Finn   Level: Advanced
530db4653c2SDaniel Finn 
531bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSDISCGRAD`, `TSDiscGradUseGonzalez()`, `TSDISCGRAD`
532db4653c2SDaniel Finn @*/
533d71ae5a4SJacob Faibussowitsch PetscErrorCode TSDiscGradIsGonzalez(TS ts, PetscBool *gonzalez)
534d71ae5a4SJacob Faibussowitsch {
535db4653c2SDaniel Finn   PetscFunctionBegin;
536db4653c2SDaniel Finn   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
537dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(gonzalez, 2);
538cac4c232SBarry Smith   PetscUseMethod(ts, "TSDiscGradIsGonzalez_C", (TS, PetscBool *), (ts, gonzalez));
5393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
540db4653c2SDaniel Finn }
541db4653c2SDaniel Finn 
542db4653c2SDaniel Finn /*@
543*20f4b53cSBarry Smith   TSDiscGradUseGonzalez - Sets discrete gradient formulation with or without additional conservative terms.
544*20f4b53cSBarry Smith   Without the flag, the discrete gradients timestepper is just backwards Euler
545db4653c2SDaniel Finn 
546db4653c2SDaniel Finn   Not Collective
547db4653c2SDaniel Finn 
548f1a722f8SMatthew G. Knepley   Input Parameters:
549db4653c2SDaniel Finn + ts - timestepping context
550bcf0153eSBarry Smith - flg - `PETSC_TRUE` to use the Gonzalez term
551db4653c2SDaniel Finn 
552bcf0153eSBarry Smith   Options Database Key:
55367b8a455SSatish Balay . -ts_discgrad_gonzalez <flg> - use the Gonzalez term for the discrete gradient formulation
554db4653c2SDaniel Finn 
555db4653c2SDaniel Finn   Level: Intermediate
556db4653c2SDaniel Finn 
557bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSDISCGRAD`
558db4653c2SDaniel Finn @*/
559d71ae5a4SJacob Faibussowitsch PetscErrorCode TSDiscGradUseGonzalez(TS ts, PetscBool flg)
560d71ae5a4SJacob Faibussowitsch {
561db4653c2SDaniel Finn   PetscFunctionBegin;
562db4653c2SDaniel Finn   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
563cac4c232SBarry Smith   PetscTryMethod(ts, "TSDiscGradUseGonzalez_C", (TS, PetscBool), (ts, flg));
5643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56540be0ff1SMatthew G. Knepley }
566