xref: /petsc/src/ts/impls/implicit/discgrad/tsdiscgrad.c (revision f4f49eeac7efa77fffa46b7ff95a3ed169f659ed)
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;
273*f4f49eeaSPierre Jolivet   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));
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35440be0ff1SMatthew G. Knepley }
35540be0ff1SMatthew G. Knepley 
356d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_DiscGrad(SNES snes, Vec x, Mat A, Mat B, TS ts)
357d71ae5a4SJacob Faibussowitsch {
35840be0ff1SMatthew G. Knepley   TS_DiscGrad *dg    = (TS_DiscGrad *)ts->data;
35940be0ff1SMatthew G. Knepley   PetscReal    shift = 1 / (0.5 * ts->time_step);
36040be0ff1SMatthew G. Knepley   Vec          Xdot;
36140be0ff1SMatthew G. Knepley   DM           dm, dmsave;
36240be0ff1SMatthew G. Knepley 
36340be0ff1SMatthew G. Knepley   PetscFunctionBegin;
3649566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
36540be0ff1SMatthew G. Knepley   /* Xdot has already been computed in SNESTSFormFunction_DiscGrad (SNES guarantees this) */
3669566063dSJacob Faibussowitsch   PetscCall(TSDiscGradGetX0AndXdot(ts, dm, NULL, &Xdot));
36740be0ff1SMatthew G. Knepley 
36840be0ff1SMatthew G. Knepley   dmsave = ts->dm;
36940be0ff1SMatthew G. Knepley   ts->dm = dm;
3709566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, dg->stage_time, x, Xdot, shift, A, B, PETSC_FALSE));
37140be0ff1SMatthew G. Knepley   ts->dm = dmsave;
3729566063dSJacob Faibussowitsch   PetscCall(TSDiscGradRestoreX0AndXdot(ts, dm, NULL, &Xdot));
3733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37440be0ff1SMatthew G. Knepley }
37540be0ff1SMatthew G. Knepley 
376d71ae5a4SJacob 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)
377d71ae5a4SJacob Faibussowitsch {
37840be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
37940be0ff1SMatthew G. Knepley 
38040be0ff1SMatthew G. Knepley   PetscFunctionBegin;
38140be0ff1SMatthew G. Knepley   *Sfunc = dg->Sfunc;
38240be0ff1SMatthew G. Knepley   *Ffunc = dg->Ffunc;
38340be0ff1SMatthew G. Knepley   *Gfunc = dg->Gfunc;
3843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38540be0ff1SMatthew G. Knepley }
38640be0ff1SMatthew G. Knepley 
387d71ae5a4SJacob 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)
388d71ae5a4SJacob Faibussowitsch {
38940be0ff1SMatthew G. Knepley   TS_DiscGrad *dg = (TS_DiscGrad *)ts->data;
39040be0ff1SMatthew G. Knepley 
39140be0ff1SMatthew G. Knepley   PetscFunctionBegin;
39240be0ff1SMatthew G. Knepley   dg->Sfunc   = Sfunc;
39340be0ff1SMatthew G. Knepley   dg->Ffunc   = Ffunc;
39440be0ff1SMatthew G. Knepley   dg->Gfunc   = Gfunc;
395db4653c2SDaniel Finn   dg->funcCtx = ctx;
3963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39740be0ff1SMatthew G. Knepley }
39840be0ff1SMatthew G. Knepley 
39940be0ff1SMatthew G. Knepley /*MC
40040be0ff1SMatthew G. Knepley   TSDISCGRAD - ODE solver using the discrete gradients version of the implicit midpoint method
40140be0ff1SMatthew G. Knepley 
402bcf0153eSBarry Smith   Level: intermediate
403bcf0153eSBarry Smith 
4042ceb51e8SPatrick Sanan   Notes:
40514d0ab18SJacob Faibussowitsch   This is the implicit midpoint rule, with an optional term that guarantees the discrete
40614d0ab18SJacob Faibussowitsch   gradient property. This timestepper applies to systems of the form $u_t = S(u) \nabla F(u)$
40714d0ab18SJacob Faibussowitsch   where $S(u)$ is a linear operator, and $F$ is a functional of $u$.
40840be0ff1SMatthew G. Knepley 
4091cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TSSetType()`, `TS`, `TSDISCGRAD`, `TSDiscGradSetFormulation()`
41040be0ff1SMatthew G. Knepley M*/
411d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_DiscGrad(TS ts)
412d71ae5a4SJacob Faibussowitsch {
41340be0ff1SMatthew G. Knepley   TS_DiscGrad *th;
41440be0ff1SMatthew G. Knepley 
41540be0ff1SMatthew G. Knepley   PetscFunctionBegin;
4169566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(DGCitation, &DGCite));
41740be0ff1SMatthew G. Knepley   ts->ops->reset          = TSReset_DiscGrad;
41840be0ff1SMatthew G. Knepley   ts->ops->destroy        = TSDestroy_DiscGrad;
41940be0ff1SMatthew G. Knepley   ts->ops->view           = TSView_DiscGrad;
42040be0ff1SMatthew G. Knepley   ts->ops->setfromoptions = TSSetFromOptions_DiscGrad;
42140be0ff1SMatthew G. Knepley   ts->ops->setup          = TSSetUp_DiscGrad;
42240be0ff1SMatthew G. Knepley   ts->ops->step           = TSStep_DiscGrad;
42340be0ff1SMatthew G. Knepley   ts->ops->interpolate    = TSInterpolate_DiscGrad;
42440be0ff1SMatthew G. Knepley   ts->ops->getstages      = TSGetStages_DiscGrad;
42540be0ff1SMatthew G. Knepley   ts->ops->snesfunction   = SNESTSFormFunction_DiscGrad;
42640be0ff1SMatthew G. Knepley   ts->ops->snesjacobian   = SNESTSFormJacobian_DiscGrad;
42740be0ff1SMatthew G. Knepley   ts->default_adapt_type  = TSADAPTNONE;
42840be0ff1SMatthew G. Knepley 
42940be0ff1SMatthew G. Knepley   ts->usessnes = PETSC_TRUE;
43040be0ff1SMatthew G. Knepley 
4314dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&th));
43240be0ff1SMatthew G. Knepley   ts->data = (void *)th;
433db4653c2SDaniel Finn 
434db4653c2SDaniel Finn   th->gonzalez = PETSC_FALSE;
435db4653c2SDaniel Finn 
4369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradGetFormulation_C", TSDiscGradGetFormulation_DiscGrad));
4379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradSetFormulation_C", TSDiscGradSetFormulation_DiscGrad));
4389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradIsGonzalez_C", TSDiscGradIsGonzalez_DiscGrad));
4399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSDiscGradUseGonzalez_C", TSDiscGradUseGonzalez_DiscGrad));
4403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44140be0ff1SMatthew G. Knepley }
44240be0ff1SMatthew G. Knepley 
44340be0ff1SMatthew G. Knepley /*@C
44414d0ab18SJacob Faibussowitsch   TSDiscGradGetFormulation - Get the construction method for S, F, and grad F from the
44514d0ab18SJacob Faibussowitsch   formulation $u_t = S \nabla F$ for `TSDISCGRAD`
44640be0ff1SMatthew G. Knepley 
44740be0ff1SMatthew G. Knepley   Not Collective
44840be0ff1SMatthew G. Knepley 
44940be0ff1SMatthew G. Knepley   Input Parameter:
45040be0ff1SMatthew G. Knepley . ts - timestepping context
45140be0ff1SMatthew G. Knepley 
45240be0ff1SMatthew G. Knepley   Output Parameters:
45340be0ff1SMatthew G. Knepley + Sfunc - constructor for the S matrix from the formulation
45440be0ff1SMatthew G. Knepley . Ffunc - functional F from the formulation
455f1a722f8SMatthew G. Knepley . Gfunc - constructor for the gradient of F from the formulation
456f1a722f8SMatthew G. Knepley - ctx   - the user context
45740be0ff1SMatthew G. Knepley 
45820f4b53cSBarry Smith   Calling sequence of `Sfunc`:
4598847d985SBarry Smith + ts   - the integrator
4608847d985SBarry Smith . time - the current time
4618847d985SBarry Smith . u    - the solution
4628847d985SBarry Smith . S    - the S-matrix from the formulation
4638847d985SBarry Smith - ctx  - the user context
46440be0ff1SMatthew G. Knepley 
46520f4b53cSBarry Smith   Calling sequence of `Ffunc`:
4668847d985SBarry Smith + ts   - the integrator
4678847d985SBarry Smith . time - the current time
4688847d985SBarry Smith . u    - the solution
4698847d985SBarry Smith . F    - the computed function from the formulation
4708847d985SBarry Smith - ctx  - the user context
47140be0ff1SMatthew G. Knepley 
47220f4b53cSBarry Smith   Calling sequence of `Gfunc`:
4738847d985SBarry Smith + ts   - the integrator
4748847d985SBarry Smith . time - the current time
4758847d985SBarry Smith . u    - the solution
4768847d985SBarry Smith . G    - the gradient of the computed function from the formulation
4778847d985SBarry Smith - ctx  - the user context
47840be0ff1SMatthew G. Knepley 
47940be0ff1SMatthew G. Knepley   Level: intermediate
48040be0ff1SMatthew G. Knepley 
4811cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSDISCGRAD`, `TSDiscGradSetFormulation()`
48240be0ff1SMatthew G. Knepley @*/
4838847d985SBarry Smith PetscErrorCode TSDiscGradGetFormulation(TS ts, PetscErrorCode (**Sfunc)(TS ts, PetscReal time, Vec u, Mat S, void *ctx), PetscErrorCode (**Ffunc)(TS ts, PetscReal time, Vec u, PetscScalar *F, void *ctx), PetscErrorCode (**Gfunc)(TS ts, PetscReal time, Vec u, Vec G, void *ctx), void *ctx)
484d71ae5a4SJacob Faibussowitsch {
48540be0ff1SMatthew G. Knepley   PetscFunctionBegin;
48640be0ff1SMatthew G. Knepley   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4874f572ea9SToby Isaac   PetscAssertPointer(Sfunc, 2);
4884f572ea9SToby Isaac   PetscAssertPointer(Ffunc, 3);
4894f572ea9SToby Isaac   PetscAssertPointer(Gfunc, 4);
490cac4c232SBarry 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));
4913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49240be0ff1SMatthew G. Knepley }
49340be0ff1SMatthew G. Knepley 
49440be0ff1SMatthew G. Knepley /*@C
49514d0ab18SJacob Faibussowitsch   TSDiscGradSetFormulation - Set the construction method for S, F, and grad F from the
49614d0ab18SJacob Faibussowitsch   formulation $u_t = S(u) \nabla F(u)$ for `TSDISCGRAD`
49740be0ff1SMatthew G. Knepley 
49840be0ff1SMatthew G. Knepley   Not Collective
49940be0ff1SMatthew G. Knepley 
50040be0ff1SMatthew G. Knepley   Input Parameters:
50140be0ff1SMatthew G. Knepley + ts    - timestepping context
50240be0ff1SMatthew G. Knepley . Sfunc - constructor for the S matrix from the formulation
50340be0ff1SMatthew G. Knepley . Ffunc - functional F from the formulation
5042fe279fdSBarry Smith . Gfunc - constructor for the gradient of F from the formulation
5052fe279fdSBarry Smith - ctx   - optional context for the functions
50640be0ff1SMatthew G. Knepley 
50720f4b53cSBarry Smith   Calling sequence of `Sfunc`:
5088847d985SBarry Smith + ts   - the integrator
5098847d985SBarry Smith . time - the current time
5108847d985SBarry Smith . u    - the solution
5118847d985SBarry Smith . S    - the S-matrix from the formulation
5128847d985SBarry Smith - ctx  - the user context
51340be0ff1SMatthew G. Knepley 
51420f4b53cSBarry Smith   Calling sequence of `Ffunc`:
5158847d985SBarry Smith + ts   - the integrator
5168847d985SBarry Smith . time - the current time
5178847d985SBarry Smith . u    - the solution
5188847d985SBarry Smith . F    - the computed function from the formulation
5198847d985SBarry Smith - ctx  - the user context
52020f4b53cSBarry Smith 
52120f4b53cSBarry Smith   Calling sequence of `Gfunc`:
5228847d985SBarry Smith + ts   - the integrator
5238847d985SBarry Smith . time - the current time
5248847d985SBarry Smith . u    - the solution
5258847d985SBarry Smith . G    - the gradient of the computed function from the formulation
5268847d985SBarry Smith - ctx  - the user context
52740be0ff1SMatthew G. Knepley 
528b43aa488SJacob Faibussowitsch   Level: intermediate
52940be0ff1SMatthew G. Knepley 
5301cc06b55SBarry Smith .seealso: [](ch_ts), `TSDISCGRAD`, `TSDiscGradGetFormulation()`
53140be0ff1SMatthew G. Knepley @*/
5328847d985SBarry Smith PetscErrorCode TSDiscGradSetFormulation(TS ts, PetscErrorCode (*Sfunc)(TS ts, PetscReal time, Vec u, Mat S, void *ctx), PetscErrorCode (*Ffunc)(TS ts, PetscReal time, Vec u, PetscScalar *F, void *ctx), PetscErrorCode (*Gfunc)(TS ts, PetscReal time, Vec u, Vec G, void *ctx), void *ctx)
533d71ae5a4SJacob Faibussowitsch {
53440be0ff1SMatthew G. Knepley   PetscFunctionBegin;
53540be0ff1SMatthew G. Knepley   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
53640be0ff1SMatthew G. Knepley   PetscValidFunction(Sfunc, 2);
53740be0ff1SMatthew G. Knepley   PetscValidFunction(Ffunc, 3);
53840be0ff1SMatthew G. Knepley   PetscValidFunction(Gfunc, 4);
539cac4c232SBarry 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));
5403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
541db4653c2SDaniel Finn }
542db4653c2SDaniel Finn 
543db4653c2SDaniel Finn /*@
54414d0ab18SJacob Faibussowitsch   TSDiscGradIsGonzalez - Checks flag for whether to use additional conservative terms in
54514d0ab18SJacob Faibussowitsch   discrete gradient formulation for `TSDISCGRAD`
546db4653c2SDaniel Finn 
547db4653c2SDaniel Finn   Not Collective
548db4653c2SDaniel Finn 
549db4653c2SDaniel Finn   Input Parameter:
550db4653c2SDaniel Finn . ts - timestepping context
551db4653c2SDaniel Finn 
552db4653c2SDaniel Finn   Output Parameter:
553bcf0153eSBarry Smith . gonzalez - `PETSC_TRUE` when using the Gonzalez term
554db4653c2SDaniel Finn 
555b43aa488SJacob Faibussowitsch   Level: advanced
556db4653c2SDaniel Finn 
557b43aa488SJacob Faibussowitsch .seealso: [](ch_ts), `TSDISCGRAD`, `TSDiscGradUseGonzalez()`
558db4653c2SDaniel Finn @*/
559d71ae5a4SJacob Faibussowitsch PetscErrorCode TSDiscGradIsGonzalez(TS ts, PetscBool *gonzalez)
560d71ae5a4SJacob Faibussowitsch {
561db4653c2SDaniel Finn   PetscFunctionBegin;
562db4653c2SDaniel Finn   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5634f572ea9SToby Isaac   PetscAssertPointer(gonzalez, 2);
564cac4c232SBarry Smith   PetscUseMethod(ts, "TSDiscGradIsGonzalez_C", (TS, PetscBool *), (ts, gonzalez));
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566db4653c2SDaniel Finn }
567db4653c2SDaniel Finn 
568db4653c2SDaniel Finn /*@
56914d0ab18SJacob Faibussowitsch   TSDiscGradUseGonzalez - Sets discrete gradient formulation with or without additional
57014d0ab18SJacob Faibussowitsch   conservative terms.
571db4653c2SDaniel Finn 
572db4653c2SDaniel Finn   Not Collective
573db4653c2SDaniel Finn 
574f1a722f8SMatthew G. Knepley   Input Parameters:
575db4653c2SDaniel Finn + ts  - timestepping context
576bcf0153eSBarry Smith - flg - `PETSC_TRUE` to use the Gonzalez term
577db4653c2SDaniel Finn 
578bcf0153eSBarry Smith   Options Database Key:
57967b8a455SSatish Balay . -ts_discgrad_gonzalez <flg> - use the Gonzalez term for the discrete gradient formulation
580db4653c2SDaniel Finn 
581b43aa488SJacob Faibussowitsch   Level: intermediate
582db4653c2SDaniel Finn 
58314d0ab18SJacob Faibussowitsch   Notes:
58414d0ab18SJacob Faibussowitsch   Without `flg`, the discrete gradients timestepper is just backwards Euler.
58514d0ab18SJacob Faibussowitsch 
5861cc06b55SBarry Smith .seealso: [](ch_ts), `TSDISCGRAD`
587db4653c2SDaniel Finn @*/
588d71ae5a4SJacob Faibussowitsch PetscErrorCode TSDiscGradUseGonzalez(TS ts, PetscBool flg)
589d71ae5a4SJacob Faibussowitsch {
590db4653c2SDaniel Finn   PetscFunctionBegin;
591db4653c2SDaniel Finn   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
592cac4c232SBarry Smith   PetscTryMethod(ts, "TSDiscGradUseGonzalez_C", (TS, PetscBool), (ts, flg));
5933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59440be0ff1SMatthew G. Knepley }
595