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 2740be0ff1SMatthew G. Knepley static PetscErrorCode TSDiscGradGetX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot) 2840be0ff1SMatthew G. Knepley { 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)); 3440be0ff1SMatthew G. Knepley 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)); 3840be0ff1SMatthew G. Knepley else {*Xdot = dg->Xdot;} 3940be0ff1SMatthew G. Knepley } 4040be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 4140be0ff1SMatthew G. Knepley } 4240be0ff1SMatthew G. Knepley 4340be0ff1SMatthew G. Knepley static PetscErrorCode TSDiscGradRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot) 4440be0ff1SMatthew G. Knepley { 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 } 5240be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 5340be0ff1SMatthew G. Knepley } 5440be0ff1SMatthew G. Knepley 5540be0ff1SMatthew G. Knepley static PetscErrorCode DMCoarsenHook_TSDiscGrad(DM fine, DM coarse, void *ctx) 5640be0ff1SMatthew G. Knepley { 5740be0ff1SMatthew G. Knepley PetscFunctionBegin; 5840be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 5940be0ff1SMatthew G. Knepley } 6040be0ff1SMatthew G. Knepley 6140be0ff1SMatthew G. Knepley static PetscErrorCode DMRestrictHook_TSDiscGrad(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx) 6240be0ff1SMatthew G. Knepley { 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)); 7540be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 7640be0ff1SMatthew G. Knepley } 7740be0ff1SMatthew G. Knepley 7840be0ff1SMatthew G. Knepley static PetscErrorCode DMSubDomainHook_TSDiscGrad(DM dm, DM subdm, void *ctx) 7940be0ff1SMatthew G. Knepley { 8040be0ff1SMatthew G. Knepley PetscFunctionBegin; 8140be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 8240be0ff1SMatthew G. Knepley } 8340be0ff1SMatthew G. Knepley 8440be0ff1SMatthew G. Knepley static PetscErrorCode DMSubDomainRestrictHook_TSDiscGrad(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx) 8540be0ff1SMatthew G. Knepley { 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)); 10140be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 10240be0ff1SMatthew G. Knepley } 10340be0ff1SMatthew G. Knepley 10440be0ff1SMatthew G. Knepley static PetscErrorCode TSSetUp_DiscGrad(TS ts) 10540be0ff1SMatthew G. Knepley { 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)); 11740be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 11840be0ff1SMatthew G. Knepley } 11940be0ff1SMatthew G. Knepley 12040be0ff1SMatthew G. Knepley static PetscErrorCode TSSetFromOptions_DiscGrad(PetscOptionItems *PetscOptionsObject, TS ts) 12140be0ff1SMatthew G. Knepley { 122db4653c2SDaniel Finn TS_DiscGrad *dg = (TS_DiscGrad *) ts->data; 12340be0ff1SMatthew G. Knepley 12440be0ff1SMatthew G. Knepley PetscFunctionBegin; 1259566063dSJacob Faibussowitsch PetscCall(PetscOptionsHead(PetscOptionsObject, "Discrete Gradients ODE solver options")); 12640be0ff1SMatthew G. Knepley { 1279566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-ts_discgrad_gonzalez","Use Gonzalez term in discrete gradients formulation","TSDiscGradUseGonzalez",dg->gonzalez,&dg->gonzalez,NULL)); 12840be0ff1SMatthew G. Knepley } 1299566063dSJacob Faibussowitsch PetscCall(PetscOptionsTail()); 13040be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 13140be0ff1SMatthew G. Knepley } 13240be0ff1SMatthew G. Knepley 13340be0ff1SMatthew G. Knepley static PetscErrorCode TSView_DiscGrad(TS ts,PetscViewer viewer) 13440be0ff1SMatthew G. Knepley { 13540be0ff1SMatthew G. Knepley PetscBool iascii; 13640be0ff1SMatthew G. Knepley 13740be0ff1SMatthew G. Knepley PetscFunctionBegin; 1389566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 13940be0ff1SMatthew G. Knepley if (iascii) { 1409566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer," Discrete Gradients\n")); 14140be0ff1SMatthew G. Knepley } 14240be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 14340be0ff1SMatthew G. Knepley } 14440be0ff1SMatthew G. Knepley 145db4653c2SDaniel Finn static PetscErrorCode TSDiscGradIsGonzalez_DiscGrad(TS ts,PetscBool *gonzalez) 146db4653c2SDaniel Finn { 147db4653c2SDaniel Finn TS_DiscGrad *dg = (TS_DiscGrad*)ts->data; 148db4653c2SDaniel Finn 149db4653c2SDaniel Finn PetscFunctionBegin; 150db4653c2SDaniel Finn *gonzalez = dg->gonzalez; 151db4653c2SDaniel Finn PetscFunctionReturn(0); 152db4653c2SDaniel Finn } 153db4653c2SDaniel Finn 154db4653c2SDaniel Finn static PetscErrorCode TSDiscGradUseGonzalez_DiscGrad(TS ts,PetscBool flg) 155db4653c2SDaniel Finn { 156db4653c2SDaniel Finn TS_DiscGrad *dg = (TS_DiscGrad*)ts->data; 157db4653c2SDaniel Finn 158db4653c2SDaniel Finn PetscFunctionBegin; 159db4653c2SDaniel Finn dg->gonzalez = flg; 160db4653c2SDaniel Finn PetscFunctionReturn(0); 161db4653c2SDaniel Finn } 162db4653c2SDaniel Finn 16340be0ff1SMatthew G. Knepley static PetscErrorCode TSReset_DiscGrad(TS ts) 16440be0ff1SMatthew G. Knepley { 16540be0ff1SMatthew G. Knepley TS_DiscGrad *dg = (TS_DiscGrad *) ts->data; 16640be0ff1SMatthew G. Knepley 16740be0ff1SMatthew G. Knepley PetscFunctionBegin; 1689566063dSJacob Faibussowitsch PetscCall(VecDestroy(&dg->X)); 1699566063dSJacob Faibussowitsch PetscCall(VecDestroy(&dg->X0)); 1709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&dg->Xdot)); 17140be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 17240be0ff1SMatthew G. Knepley } 17340be0ff1SMatthew G. Knepley 17440be0ff1SMatthew G. Knepley static PetscErrorCode TSDestroy_DiscGrad(TS ts) 17540be0ff1SMatthew G. Knepley { 17640be0ff1SMatthew G. Knepley DM dm; 17740be0ff1SMatthew G. Knepley 17840be0ff1SMatthew G. Knepley PetscFunctionBegin; 1799566063dSJacob Faibussowitsch PetscCall(TSReset_DiscGrad(ts)); 1809566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &dm)); 18140be0ff1SMatthew G. Knepley if (dm) { 1829566063dSJacob Faibussowitsch PetscCall(DMCoarsenHookRemove(dm, DMCoarsenHook_TSDiscGrad, DMRestrictHook_TSDiscGrad, ts)); 1839566063dSJacob Faibussowitsch PetscCall(DMSubDomainHookRemove(dm, DMSubDomainHook_TSDiscGrad, DMSubDomainRestrictHook_TSDiscGrad, ts)); 18440be0ff1SMatthew G. Knepley } 1859566063dSJacob Faibussowitsch PetscCall(PetscFree(ts->data)); 1869566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts,"TSDiscGradGetFormulation_C",NULL)); 1879566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts,"TSDiscGradSetFormulation_C",NULL)); 18840be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 18940be0ff1SMatthew G. Knepley } 19040be0ff1SMatthew G. Knepley 19140be0ff1SMatthew G. Knepley static PetscErrorCode TSInterpolate_DiscGrad(TS ts, PetscReal t, Vec X) 19240be0ff1SMatthew G. Knepley { 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)); 19940be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 20040be0ff1SMatthew G. Knepley } 20140be0ff1SMatthew G. Knepley 20240be0ff1SMatthew G. Knepley static PetscErrorCode TSDiscGrad_SNESSolve(TS ts, Vec b, Vec x) 20340be0ff1SMatthew G. Knepley { 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; 21440be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 21540be0ff1SMatthew G. Knepley } 21640be0ff1SMatthew G. Knepley 21740be0ff1SMatthew G. Knepley static PetscErrorCode TSStep_DiscGrad(TS ts) 21840be0ff1SMatthew G. Knepley { 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: 25740be0ff1SMatthew G. Knepley ts->reject++; accept = PETSC_FALSE; 25840be0ff1SMatthew G. Knepley if (!ts->reason && ts->max_reject >= 0 && ++rejections > ts->max_reject) { 25940be0ff1SMatthew G. Knepley ts->reason = TS_DIVERGED_STEP_REJECTED; 2609566063dSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%D, step rejections %D greater than current TS allowed, stopping solve\n", ts->steps, rejections)); 26140be0ff1SMatthew G. Knepley } 26240be0ff1SMatthew G. Knepley } 26340be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 26440be0ff1SMatthew G. Knepley } 26540be0ff1SMatthew G. Knepley 26640be0ff1SMatthew G. Knepley static PetscErrorCode TSGetStages_DiscGrad(TS ts, PetscInt *ns, Vec **Y) 26740be0ff1SMatthew G. Knepley { 26840be0ff1SMatthew G. Knepley TS_DiscGrad *dg = (TS_DiscGrad *) ts->data; 26940be0ff1SMatthew G. Knepley 27040be0ff1SMatthew G. Knepley PetscFunctionBegin; 27140be0ff1SMatthew G. Knepley if (ns) *ns = 1; 27240be0ff1SMatthew G. Knepley if (Y) *Y = &(dg->X); 27340be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 27440be0ff1SMatthew G. Knepley } 27540be0ff1SMatthew G. Knepley 27640be0ff1SMatthew G. Knepley /* 27740be0ff1SMatthew G. Knepley This defines the nonlinear equation that is to be solved with SNES 27840be0ff1SMatthew G. Knepley G(U) = F[t0 + 0.5*dt, U, (U-U0)/dt] = 0 27940be0ff1SMatthew G. Knepley */ 280db4653c2SDaniel Finn 281db4653c2SDaniel Finn /* x = (x+x')/2 */ 282db4653c2SDaniel Finn /* NEED TO CALCULATE x_{n+1} from x and x_{n}*/ 28340be0ff1SMatthew G. Knepley static PetscErrorCode SNESTSFormFunction_DiscGrad(SNES snes, Vec x, Vec y, TS ts) 28440be0ff1SMatthew G. Knepley { 285db4653c2SDaniel Finn 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 35440be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 35540be0ff1SMatthew G. Knepley } 35640be0ff1SMatthew G. Knepley 35740be0ff1SMatthew G. Knepley static PetscErrorCode SNESTSFormJacobian_DiscGrad(SNES snes, Vec x, Mat A, Mat B, TS ts) 35840be0ff1SMatthew G. Knepley { 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)); 37440be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 37540be0ff1SMatthew G. Knepley } 37640be0ff1SMatthew G. Knepley 377db4653c2SDaniel Finn 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) 37840be0ff1SMatthew G. Knepley { 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; 38540be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 38640be0ff1SMatthew G. Knepley } 38740be0ff1SMatthew G. Knepley 388db4653c2SDaniel Finn 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) 38940be0ff1SMatthew G. Knepley { 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; 39740be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 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 4032ceb51e8SPatrick Sanan Notes: 4042ceb51e8SPatrick Sanan This is the implicit midpoint rule, with an optional term that guarantees the discrete gradient property. This 40540be0ff1SMatthew G. Knepley timestepper applies to systems of the form 40640be0ff1SMatthew G. Knepley $ u_t = S(u) grad F(u) 40740be0ff1SMatthew G. Knepley where S(u) is a linear operator, and F is a functional of u. 40840be0ff1SMatthew G. Knepley 409f1a722f8SMatthew G. Knepley Level: intermediate 410f1a722f8SMatthew G. Knepley 411db4653c2SDaniel Finn .seealso: TSCreate(), TSSetType(), TS, TSDISCGRAD, TSDiscGradSetFormulation() 41240be0ff1SMatthew G. Knepley M*/ 41340be0ff1SMatthew G. Knepley PETSC_EXTERN PetscErrorCode TSCreate_DiscGrad(TS ts) 41440be0ff1SMatthew G. Knepley { 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 4339566063dSJacob Faibussowitsch PetscCall(PetscNewLog(ts,&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)); 44240be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 44340be0ff1SMatthew G. Knepley } 44440be0ff1SMatthew G. Knepley 44540be0ff1SMatthew G. Knepley /*@C 44640be0ff1SMatthew G. Knepley TSDiscGradGetFormulation - Get the construction method for S, F, and grad F from the formulation u_t = S grad F 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 45940be0ff1SMatthew G. Knepley Calling sequence of Sfunc: 46040be0ff1SMatthew G. Knepley $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Mat S, void *) 46140be0ff1SMatthew G. Knepley 46240be0ff1SMatthew G. Knepley Calling sequence of Ffunc: 46340be0ff1SMatthew G. Knepley $ PetscErrorCode func(TS ts, PetscReal time, Vec u, PetscScalar *F, void *) 46440be0ff1SMatthew G. Knepley 46540be0ff1SMatthew G. Knepley Calling sequence of Gfunc: 46640be0ff1SMatthew G. Knepley $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Vec G, void *) 46740be0ff1SMatthew G. Knepley 46840be0ff1SMatthew G. Knepley Level: intermediate 46940be0ff1SMatthew G. Knepley 47040be0ff1SMatthew G. Knepley .seealso: TSDiscGradSetFormulation() 47140be0ff1SMatthew G. Knepley @*/ 472db4653c2SDaniel Finn 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) 47340be0ff1SMatthew G. Knepley { 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); 479*cac4c232SBarry 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)); 48040be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 48140be0ff1SMatthew G. Knepley } 48240be0ff1SMatthew G. Knepley 48340be0ff1SMatthew G. Knepley /*@C 48440be0ff1SMatthew G. Knepley TSDiscGradSetFormulation - Set the construction method for S, F, and grad F from the formulation u_t = S(u) grad F(u) 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 Calling sequence of Sfunc: 49440be0ff1SMatthew G. Knepley $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Mat S, void *) 49540be0ff1SMatthew G. Knepley 49640be0ff1SMatthew G. Knepley Calling sequence of Ffunc: 49740be0ff1SMatthew G. Knepley $ PetscErrorCode func(TS ts, PetscReal time, Vec u, PetscScalar *F, void *) 49840be0ff1SMatthew G. Knepley 49940be0ff1SMatthew G. Knepley Calling sequence of Gfunc: 50040be0ff1SMatthew G. Knepley $ PetscErrorCode func(TS ts, PetscReal time, Vec u, Vec G, void *) 50140be0ff1SMatthew G. Knepley 50240be0ff1SMatthew G. Knepley Level: Intermediate 50340be0ff1SMatthew G. Knepley 50440be0ff1SMatthew G. Knepley .seealso: TSDiscGradGetFormulation() 50540be0ff1SMatthew G. Knepley @*/ 50640be0ff1SMatthew G. Knepley 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) 50740be0ff1SMatthew G. Knepley { 50840be0ff1SMatthew G. Knepley PetscFunctionBegin; 50940be0ff1SMatthew G. Knepley PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 51040be0ff1SMatthew G. Knepley PetscValidFunction(Sfunc, 2); 51140be0ff1SMatthew G. Knepley PetscValidFunction(Ffunc, 3); 51240be0ff1SMatthew G. Knepley PetscValidFunction(Gfunc, 4); 513*cac4c232SBarry 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)); 514db4653c2SDaniel Finn PetscFunctionReturn(0); 515db4653c2SDaniel Finn } 516db4653c2SDaniel Finn 517db4653c2SDaniel Finn /*@ 518db4653c2SDaniel Finn TSDiscGradIsGonzalez - Checks flag for whether to use additional conservative terms in discrete gradient formulation. 519db4653c2SDaniel Finn 520db4653c2SDaniel Finn Not Collective 521db4653c2SDaniel Finn 522db4653c2SDaniel Finn Input Parameter: 523db4653c2SDaniel Finn . ts - timestepping context 524db4653c2SDaniel Finn 525db4653c2SDaniel Finn Output Parameter: 526db4653c2SDaniel Finn . gonzalez - PETSC_TRUE when using the Gonzalez term 527db4653c2SDaniel Finn 528db4653c2SDaniel Finn Level: Advanced 529db4653c2SDaniel Finn 530db4653c2SDaniel Finn .seealso: TSDiscGradUseGonzalez(), TSDISCGRAD 531db4653c2SDaniel Finn @*/ 532db4653c2SDaniel Finn PetscErrorCode TSDiscGradIsGonzalez(TS ts,PetscBool *gonzalez) 533db4653c2SDaniel Finn { 534db4653c2SDaniel Finn PetscFunctionBegin; 535db4653c2SDaniel Finn PetscValidHeaderSpecific(ts,TS_CLASSID,1); 536dadcf809SJacob Faibussowitsch PetscValidBoolPointer(gonzalez,2); 537*cac4c232SBarry Smith PetscUseMethod(ts,"TSDiscGradIsGonzalez_C",(TS,PetscBool*),(ts,gonzalez)); 538db4653c2SDaniel Finn PetscFunctionReturn(0); 539db4653c2SDaniel Finn } 540db4653c2SDaniel Finn 541db4653c2SDaniel Finn /*@ 542db4653c2SDaniel Finn TSDiscGradUseGonzalez - Sets discrete gradient formulation with or without additional conservative terms. Without flag, the discrete gradients timestepper is just backwards euler 543db4653c2SDaniel Finn 544db4653c2SDaniel Finn Not Collective 545db4653c2SDaniel Finn 546f1a722f8SMatthew G. Knepley Input Parameters: 547db4653c2SDaniel Finn + ts - timestepping context 548db4653c2SDaniel Finn - flg - PETSC_TRUE to use the Gonzalez term 549db4653c2SDaniel Finn 550db4653c2SDaniel Finn Options Database: 55167b8a455SSatish Balay . -ts_discgrad_gonzalez <flg> - use the Gonzalez term for the discrete gradient formulation 552db4653c2SDaniel Finn 553db4653c2SDaniel Finn Level: Intermediate 554db4653c2SDaniel Finn 555db4653c2SDaniel Finn .seealso: TSDISCGRAD 556db4653c2SDaniel Finn @*/ 557db4653c2SDaniel Finn PetscErrorCode TSDiscGradUseGonzalez(TS ts,PetscBool flg) 558db4653c2SDaniel Finn { 559db4653c2SDaniel Finn PetscFunctionBegin; 560db4653c2SDaniel Finn PetscValidHeaderSpecific(ts,TS_CLASSID,1); 561*cac4c232SBarry Smith PetscTryMethod(ts,"TSDiscGradUseGonzalez_C",(TS,PetscBool),(ts,flg)); 56240be0ff1SMatthew G. Knepley PetscFunctionReturn(0); 56340be0ff1SMatthew G. Knepley } 564