xref: /petsc/src/ts/impls/implicit/theta/theta.c (revision 520136c7e8a9141a0ef59e65a90b8ca416b0ca5f)
1316643e7SJed Brown /*
2316643e7SJed Brown   Code for timestepping with implicit Theta method
3316643e7SJed Brown */
4af0996ceSBarry Smith #include <petsc/private/tsimpl.h> /*I   "petscts.h"   I*/
5a055c8caSBarry Smith #include <petscsnes.h>
61e25c274SJed Brown #include <petscdm.h>
73c54f92cSHong Zhang #include <petscmat.h>
8316643e7SJed Brown 
9316643e7SJed Brown typedef struct {
10715f1b00SHong Zhang   /* context for time stepping */
111566a47fSLisandro Dalcin   PetscReal    stage_time;
12cc4f23bcSHong Zhang   Vec          Stages[2];   /* Storage for stage solutions */
13cc4f23bcSHong Zhang   Vec          X0, X, Xdot; /* Storage for u^n, u^n + dt a_{11} k_1, and time derivative u^{n+1}_t */
141566a47fSLisandro Dalcin   Vec          affine;      /* Affine vector needed for residual at beginning of step in endpoint formulation */
151566a47fSLisandro Dalcin   PetscReal    Theta;
161a352fa8SHong Zhang   PetscReal    shift; /* Shift parameter for SNES Jacobian, used by forward, TLM and adjoint */
171566a47fSLisandro Dalcin   PetscInt     order;
181566a47fSLisandro Dalcin   PetscBool    endpoint;
191566a47fSLisandro Dalcin   PetscBool    extrapolate;
20715f1b00SHong Zhang   TSStepStatus status;
211a352fa8SHong Zhang   Vec          VecCostIntegral0; /* Backup for roll-backs due to events, used by cost integral */
221a352fa8SHong Zhang   PetscReal    ptime0;           /* Backup for ts->ptime, the start time of current time step, used by TLM and cost integral */
231a352fa8SHong Zhang   PetscReal    time_step0;       /* Backup for ts->timestep, the step size of current time step, used by TLM and cost integral*/
241566a47fSLisandro Dalcin 
25715f1b00SHong Zhang   /* context for sensitivity analysis */
26022c081aSHong Zhang   PetscInt num_tlm;               /* Total number of tangent linear equations */
27b5e0532dSHong Zhang   Vec     *VecsDeltaLam;          /* Increment of the adjoint sensitivity w.r.t IC at stage */
28b5e0532dSHong Zhang   Vec     *VecsDeltaMu;           /* Increment of the adjoint sensitivity w.r.t P at stage */
2913b1b0ffSHong Zhang   Vec     *VecsSensiTemp;         /* Vector to be multiplied with Jacobian transpose */
30cc4f23bcSHong Zhang   Mat      MatFwdStages[2];       /* TLM Stages */
3113b1b0ffSHong Zhang   Mat      MatDeltaFwdSensip;     /* Increment of the forward sensitivity at stage */
32b5b4017aSHong Zhang   Vec      VecDeltaFwdSensipCol;  /* Working vector for holding one column of the sensitivity matrix */
3313b1b0ffSHong Zhang   Mat      MatFwdSensip0;         /* backup for roll-backs due to events */
347207e0fdSHong Zhang   Mat      MatIntegralSensipTemp; /* Working vector for forward integral sensitivity */
357207e0fdSHong Zhang   Mat      MatIntegralSensip0;    /* backup for roll-backs due to events */
36b5b4017aSHong Zhang   Vec     *VecsDeltaLam2;         /* Increment of the 2nd-order adjoint sensitivity w.r.t IC at stage */
37b5b4017aSHong Zhang   Vec     *VecsDeltaMu2;          /* Increment of the 2nd-order adjoint sensitivity w.r.t P at stage */
38b5b4017aSHong Zhang   Vec     *VecsSensi2Temp;        /* Working vectors that holds the residual for the second-order adjoint */
39b5b4017aSHong Zhang   Vec     *VecsAffine;            /* Working vectors to store residuals */
40715f1b00SHong Zhang   /* context for error estimation */
411566a47fSLisandro Dalcin   Vec vec_sol_prev;
421566a47fSLisandro Dalcin   Vec vec_lte_work;
43316643e7SJed Brown } TS_Theta;
44316643e7SJed Brown 
45d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
46d71ae5a4SJacob Faibussowitsch {
477445fe48SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
487445fe48SJed Brown 
497445fe48SJed Brown   PetscFunctionBegin;
507445fe48SJed Brown   if (X0) {
517445fe48SJed Brown     if (dm && dm != ts->dm) {
529566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_X0", X0));
537445fe48SJed Brown     } else *X0 = ts->vec_sol;
547445fe48SJed Brown   }
557445fe48SJed Brown   if (Xdot) {
567445fe48SJed Brown     if (dm && dm != ts->dm) {
579566063dSJacob Faibussowitsch       PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_Xdot", Xdot));
587445fe48SJed Brown     } else *Xdot = th->Xdot;
597445fe48SJed Brown   }
603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
617445fe48SJed Brown }
627445fe48SJed Brown 
63d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
64d71ae5a4SJacob Faibussowitsch {
650d0b770aSPeter Brune   PetscFunctionBegin;
660d0b770aSPeter Brune   if (X0) {
6748a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_X0", X0));
680d0b770aSPeter Brune   }
690d0b770aSPeter Brune   if (Xdot) {
7048a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_Xdot", Xdot));
710d0b770aSPeter Brune   }
723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
730d0b770aSPeter Brune }
740d0b770aSPeter Brune 
75d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_TSTheta(DM fine, DM coarse, void *ctx)
76d71ae5a4SJacob Faibussowitsch {
777445fe48SJed Brown   PetscFunctionBegin;
783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
797445fe48SJed Brown }
807445fe48SJed Brown 
81d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_TSTheta(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
82d71ae5a4SJacob Faibussowitsch {
837445fe48SJed Brown   TS  ts = (TS)ctx;
847445fe48SJed Brown   Vec X0, Xdot, X0_c, Xdot_c;
857445fe48SJed Brown 
867445fe48SJed Brown   PetscFunctionBegin;
879566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, fine, &X0, &Xdot));
889566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
899566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, X0, X0_c));
909566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, Xdot, Xdot_c));
919566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(X0_c, rscale, X0_c));
929566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(Xdot_c, rscale, Xdot_c));
939566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, fine, &X0, &Xdot));
949566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
967445fe48SJed Brown }
977445fe48SJed Brown 
98d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_TSTheta(DM dm, DM subdm, void *ctx)
99d71ae5a4SJacob Faibussowitsch {
100258e1594SPeter Brune   PetscFunctionBegin;
1013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102258e1594SPeter Brune }
103258e1594SPeter Brune 
104d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
105d71ae5a4SJacob Faibussowitsch {
106258e1594SPeter Brune   TS  ts = (TS)ctx;
107258e1594SPeter Brune   Vec X0, Xdot, X0_sub, Xdot_sub;
108258e1594SPeter Brune 
109258e1594SPeter Brune   PetscFunctionBegin;
1109566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot));
1119566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
112258e1594SPeter Brune 
1139566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
1149566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
115258e1594SPeter Brune 
1169566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
1179566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
118258e1594SPeter Brune 
1199566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot));
1209566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
1213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122258e1594SPeter Brune }
123258e1594SPeter Brune 
124d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaEvaluateCostIntegral(TS ts)
125d71ae5a4SJacob Faibussowitsch {
126022c081aSHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
127cd4cee2dSHong Zhang   TS        quadts = ts->quadraturets;
128022c081aSHong Zhang 
129022c081aSHong Zhang   PetscFunctionBegin;
130022c081aSHong Zhang   if (th->endpoint) {
131022c081aSHong Zhang     /* Evolve ts->vec_costintegral to compute integrals */
132022c081aSHong Zhang     if (th->Theta != 1.0) {
1339566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSFunction(quadts, th->ptime0, th->X0, ts->vec_costintegrand));
1349566063dSJacob Faibussowitsch       PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * (1.0 - th->Theta), ts->vec_costintegrand));
135022c081aSHong Zhang     }
1369566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSFunction(quadts, ts->ptime, ts->vec_sol, ts->vec_costintegrand));
1379566063dSJacob Faibussowitsch     PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * th->Theta, ts->vec_costintegrand));
138022c081aSHong Zhang   } else {
1399566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSFunction(quadts, th->stage_time, th->X, ts->vec_costintegrand));
1409566063dSJacob Faibussowitsch     PetscCall(VecAXPY(quadts->vec_sol, th->time_step0, ts->vec_costintegrand));
141022c081aSHong Zhang   }
1423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
143022c081aSHong Zhang }
144022c081aSHong Zhang 
145d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardCostIntegral_Theta(TS ts)
146d71ae5a4SJacob Faibussowitsch {
147b1cb36f3SHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
148cd4cee2dSHong Zhang   TS        quadts = ts->quadraturets;
149b1cb36f3SHong Zhang 
150b1cb36f3SHong Zhang   PetscFunctionBegin;
151b1cb36f3SHong Zhang   /* backup cost integral */
1529566063dSJacob Faibussowitsch   PetscCall(VecCopy(quadts->vec_sol, th->VecCostIntegral0));
1539566063dSJacob Faibussowitsch   PetscCall(TSThetaEvaluateCostIntegral(ts));
1543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
155b1cb36f3SHong Zhang }
156b1cb36f3SHong Zhang 
157d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointCostIntegral_Theta(TS ts)
158d71ae5a4SJacob Faibussowitsch {
1591a352fa8SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
160b1cb36f3SHong Zhang 
161b1cb36f3SHong Zhang   PetscFunctionBegin;
1621a352fa8SHong Zhang   /* Like TSForwardCostIntegral(), the adjoint cost integral evaluation relies on ptime0 and time_step0. */
1631a352fa8SHong Zhang   th->ptime0     = ts->ptime + ts->time_step;
1641a352fa8SHong Zhang   th->time_step0 = -ts->time_step;
1659566063dSJacob Faibussowitsch   PetscCall(TSThetaEvaluateCostIntegral(ts));
1663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16724655328SShri }
16824655328SShri 
169d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSTheta_SNESSolve(TS ts, Vec b, Vec x)
170d71ae5a4SJacob Faibussowitsch {
1711566a47fSLisandro Dalcin   PetscInt nits, lits;
1721566a47fSLisandro Dalcin 
1731566a47fSLisandro Dalcin   PetscFunctionBegin;
1749566063dSJacob Faibussowitsch   PetscCall(SNESSolve(ts->snes, b, x));
1759566063dSJacob Faibussowitsch   PetscCall(SNESGetIterationNumber(ts->snes, &nits));
1769566063dSJacob Faibussowitsch   PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
1779371c9d4SSatish Balay   ts->snes_its += nits;
1789371c9d4SSatish Balay   ts->ksp_its += lits;
1793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1801566a47fSLisandro Dalcin }
1811566a47fSLisandro Dalcin 
18226b5f05dSStefano Zampini static PetscErrorCode TSResizeRegister_Theta(TS ts, PetscBool reg)
18326b5f05dSStefano Zampini {
18426b5f05dSStefano Zampini   TS_Theta *th = (TS_Theta *)ts->data;
18526b5f05dSStefano Zampini 
18626b5f05dSStefano Zampini   PetscFunctionBegin;
187ecc87898SStefano Zampini   if (reg) {
188ecc87898SStefano Zampini     PetscCall(TSResizeRegisterVec(ts, "ts:theta:sol_prev", th->vec_sol_prev));
189ecc87898SStefano Zampini     PetscCall(TSResizeRegisterVec(ts, "ts:theta:X0", th->X0));
190ecc87898SStefano Zampini   } else {
191ecc87898SStefano Zampini     PetscCall(TSResizeRetrieveVec(ts, "ts:theta:sol_prev", &th->vec_sol_prev));
192ecc87898SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)th->vec_sol_prev));
193ecc87898SStefano Zampini     PetscCall(TSResizeRetrieveVec(ts, "ts:theta:X0", &th->X0));
19426b5f05dSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)th->X0));
19526b5f05dSStefano Zampini   }
19626b5f05dSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
19726b5f05dSStefano Zampini }
19826b5f05dSStefano Zampini 
199d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_Theta(TS ts)
200d71ae5a4SJacob Faibussowitsch {
201316643e7SJed Brown   TS_Theta *th         = (TS_Theta *)ts->data;
2021566a47fSLisandro Dalcin   PetscInt  rejections = 0;
2034957b756SLisandro Dalcin   PetscBool stageok, accept = PETSC_TRUE;
2041566a47fSLisandro Dalcin   PetscReal next_time_step = ts->time_step;
205316643e7SJed Brown 
206316643e7SJed Brown   PetscFunctionBegin;
2071566a47fSLisandro Dalcin   if (!ts->steprollback) {
2089566063dSJacob Faibussowitsch     if (th->vec_sol_prev) PetscCall(VecCopy(th->X0, th->vec_sol_prev));
2099566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, th->X0));
2101566a47fSLisandro Dalcin   }
2111566a47fSLisandro Dalcin 
2121566a47fSLisandro Dalcin   th->status = TS_STEP_INCOMPLETE;
21399260352SHong Zhang   while (!ts->reason && th->status != TS_STEP_COMPLETE) {
2143e05ceb1SHong Zhang     th->shift      = 1 / (th->Theta * ts->time_step);
2151566a47fSLisandro Dalcin     th->stage_time = ts->ptime + (th->endpoint ? (PetscReal)1 : th->Theta) * ts->time_step;
2169566063dSJacob Faibussowitsch     PetscCall(VecCopy(th->X0, th->X));
21748a46eb9SPierre Jolivet     if (th->extrapolate && !ts->steprestart) PetscCall(VecAXPY(th->X, 1 / th->shift, th->Xdot));
218eb284becSJed Brown     if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */
2199566063dSJacob Faibussowitsch       if (!th->affine) PetscCall(VecDuplicate(ts->vec_sol, &th->affine));
2209566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(th->Xdot));
2219566063dSJacob Faibussowitsch       PetscCall(TSComputeIFunction(ts, ts->ptime, th->X0, th->Xdot, th->affine, PETSC_FALSE));
2229566063dSJacob Faibussowitsch       PetscCall(VecScale(th->affine, (th->Theta - 1) / th->Theta));
223eb284becSJed Brown     }
2249566063dSJacob Faibussowitsch     PetscCall(TSPreStage(ts, th->stage_time));
22582d7ce88SStefano Zampini     PetscCall(TSTheta_SNESSolve(ts, th->endpoint ? th->affine : NULL, th->X));
2269566063dSJacob Faibussowitsch     PetscCall(TSPostStage(ts, th->stage_time, 0, &th->X));
2279566063dSJacob Faibussowitsch     PetscCall(TSAdaptCheckStage(ts->adapt, ts, th->stage_time, th->X, &stageok));
228fecfb714SLisandro Dalcin     if (!stageok) goto reject_step;
229051f2191SLisandro Dalcin 
230051f2191SLisandro Dalcin     th->status = TS_STEP_PENDING;
2311566a47fSLisandro Dalcin     if (th->endpoint) {
2329566063dSJacob Faibussowitsch       PetscCall(VecCopy(th->X, ts->vec_sol));
2331566a47fSLisandro Dalcin     } else {
2349566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
2359566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ts->vec_sol, ts->time_step, th->Xdot));
2361566a47fSLisandro Dalcin     }
2379566063dSJacob Faibussowitsch     PetscCall(TSAdaptChoose(ts->adapt, ts, ts->time_step, NULL, &next_time_step, &accept));
2381566a47fSLisandro Dalcin     th->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
2391566a47fSLisandro Dalcin     if (!accept) {
2409566063dSJacob Faibussowitsch       PetscCall(VecCopy(th->X0, ts->vec_sol));
241be5899b3SLisandro Dalcin       ts->time_step = next_time_step;
242be5899b3SLisandro Dalcin       goto reject_step;
243051f2191SLisandro Dalcin     }
2443b1890cdSShri Abhyankar 
245715f1b00SHong Zhang     if (ts->forward_solve || ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */
2461a352fa8SHong Zhang       th->ptime0     = ts->ptime;
2471a352fa8SHong Zhang       th->time_step0 = ts->time_step;
24817145e75SHong Zhang     }
2492b5a38e1SLisandro Dalcin     ts->ptime += ts->time_step;
250cdbf8f93SLisandro Dalcin     ts->time_step = next_time_step;
251051f2191SLisandro Dalcin     break;
252051f2191SLisandro Dalcin 
253051f2191SLisandro Dalcin   reject_step:
2549371c9d4SSatish Balay     ts->reject++;
2559371c9d4SSatish Balay     accept = PETSC_FALSE;
2561566a47fSLisandro Dalcin     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
257051f2191SLisandro Dalcin       ts->reason = TS_DIVERGED_STEP_REJECTED;
25863a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections));
2593b1890cdSShri Abhyankar     }
2603b1890cdSShri Abhyankar   }
2613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
262316643e7SJed Brown }
263316643e7SJed Brown 
264d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointStepBEuler_Private(TS ts)
265d71ae5a4SJacob Faibussowitsch {
266c9681e5dSHong Zhang   TS_Theta      *th           = (TS_Theta *)ts->data;
267cd4cee2dSHong Zhang   TS             quadts       = ts->quadraturets;
268c9681e5dSHong Zhang   Vec           *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp;
269c9681e5dSHong Zhang   Vec           *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp;
270c9681e5dSHong Zhang   PetscInt       nadj;
2717207e0fdSHong Zhang   Mat            J, Jpre, quadJ = NULL, quadJp = NULL;
272c9681e5dSHong Zhang   KSP            ksp;
273c9681e5dSHong Zhang   PetscScalar   *xarr;
274077c4feaSHong Zhang   TSEquationType eqtype;
275077c4feaSHong Zhang   PetscBool      isexplicitode = PETSC_FALSE;
2761a352fa8SHong Zhang   PetscReal      adjoint_time_step;
277c9681e5dSHong Zhang 
278c9681e5dSHong Zhang   PetscFunctionBegin;
2799566063dSJacob Faibussowitsch   PetscCall(TSGetEquationType(ts, &eqtype));
280077c4feaSHong Zhang   if (eqtype == TS_EQ_ODE_EXPLICIT) {
281077c4feaSHong Zhang     isexplicitode = PETSC_TRUE;
282077c4feaSHong Zhang     VecsDeltaLam  = ts->vecs_sensi;
283077c4feaSHong Zhang     VecsDeltaLam2 = ts->vecs_sensi2;
284077c4feaSHong Zhang   }
285c9681e5dSHong Zhang   th->status = TS_STEP_INCOMPLETE;
2869566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(ts->snes, &ksp));
2879566063dSJacob Faibussowitsch   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
2887207e0fdSHong Zhang   if (quadts) {
2899566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
2909566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
2917207e0fdSHong Zhang   }
292c9681e5dSHong Zhang 
2931a352fa8SHong Zhang   th->stage_time    = ts->ptime;
2941a352fa8SHong Zhang   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
295c9681e5dSHong Zhang 
29633f72c5dSHong Zhang   /* Build RHS for first-order adjoint lambda_{n+1}/h + r_u^T(n+1) */
2971baa6e33SBarry Smith   if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
298cd4cee2dSHong Zhang 
299c9681e5dSHong Zhang   for (nadj = 0; nadj < ts->numcost; nadj++) {
3009566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj]));
3019566063dSJacob Faibussowitsch     PetscCall(VecScale(VecsSensiTemp[nadj], 1. / adjoint_time_step)); /* lambda_{n+1}/h */
302cd4cee2dSHong Zhang     if (quadJ) {
3039566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
3049566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
3059566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col));
3069566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_drdu_col));
3079566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
308c9681e5dSHong Zhang     }
309c9681e5dSHong Zhang   }
310c9681e5dSHong Zhang 
311c9681e5dSHong Zhang   /* Build LHS for first-order adjoint */
312c87ba875SIvan Yashchuk   th->shift = 1. / adjoint_time_step;
3139566063dSJacob Faibussowitsch   PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
3149566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(ksp, J, Jpre));
315c9681e5dSHong Zhang 
316c9681e5dSHong Zhang   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
317c9681e5dSHong Zhang   for (nadj = 0; nadj < ts->numcost; nadj++) {
318c9681e5dSHong Zhang     KSPConvergedReason kspreason;
3199566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj]));
3209566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
321c9681e5dSHong Zhang     if (kspreason < 0) {
322c9681e5dSHong Zhang       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
32363a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n", ts->steps, nadj));
324c9681e5dSHong Zhang     }
325c9681e5dSHong Zhang   }
326c9681e5dSHong Zhang 
327c9681e5dSHong Zhang   if (ts->vecs_sensi2) { /* U_{n+1} */
328c9681e5dSHong Zhang     /* Get w1 at t_{n+1} from TLM matrix */
3299566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
3309566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
331c9681e5dSHong Zhang     /* lambda_s^T F_UU w_1 */
3329566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
333c9681e5dSHong Zhang     /* lambda_s^T F_UP w_2 */
3349566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
335c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */
3369566063dSJacob Faibussowitsch       PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj]));
3379566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensi2Temp[nadj], 1. / adjoint_time_step));
3389566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj]));
33948a46eb9SPierre Jolivet       if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj]));
340c9681e5dSHong Zhang     }
341c9681e5dSHong Zhang     /* Solve stage equation LHS X = RHS for second-order adjoint */
342c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
34305c9950eSHong Zhang       KSPConvergedReason kspreason;
3449566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj]));
3459566063dSJacob Faibussowitsch       PetscCall(KSPGetConvergedReason(ksp, &kspreason));
34605c9950eSHong Zhang       if (kspreason < 0) {
34705c9950eSHong Zhang         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
34863a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n", ts->steps, nadj));
34905c9950eSHong Zhang       }
350c9681e5dSHong Zhang     }
351c9681e5dSHong Zhang   }
352c9681e5dSHong Zhang 
353c9681e5dSHong Zhang   /* Update sensitivities, and evaluate integrals if there is any */
354077c4feaSHong Zhang   if (!isexplicitode) {
3553e05ceb1SHong Zhang     th->shift = 0.0;
3569566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
3579566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, J, Jpre));
358c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
35933f72c5dSHong Zhang       /* Add f_U \lambda_s to the original RHS */
3609566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensiTemp[nadj], -1.));
3619566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj], VecsSensiTemp[nadj]));
3629566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensiTemp[nadj], -adjoint_time_step));
3639566063dSJacob Faibussowitsch       PetscCall(VecCopy(VecsSensiTemp[nadj], ts->vecs_sensi[nadj]));
364c9681e5dSHong Zhang       if (ts->vecs_sensi2) {
3659566063dSJacob Faibussowitsch         PetscCall(MatMultTransposeAdd(J, VecsDeltaLam2[nadj], VecsSensi2Temp[nadj], VecsSensi2Temp[nadj]));
3669566063dSJacob Faibussowitsch         PetscCall(VecScale(VecsSensi2Temp[nadj], -adjoint_time_step));
3679566063dSJacob Faibussowitsch         PetscCall(VecCopy(VecsSensi2Temp[nadj], ts->vecs_sensi2[nadj]));
368c9681e5dSHong Zhang       }
369c9681e5dSHong Zhang     }
370077c4feaSHong Zhang   }
371c9681e5dSHong Zhang   if (ts->vecs_sensip) {
3729566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(th->Xdot, -1. / adjoint_time_step, 1.0 / adjoint_time_step, 0, th->X0, ts->vec_sol));
3739566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, 1. / adjoint_time_step, ts->Jacp, PETSC_FALSE)); /* get -f_p */
3741baa6e33SBarry Smith     if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
375c9681e5dSHong Zhang     if (ts->vecs_sensi2p) {
376c9681e5dSHong Zhang       /* lambda_s^T F_PU w_1 */
3779566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
37833f72c5dSHong Zhang       /* lambda_s^T F_PP w_2 */
3799566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
380c9681e5dSHong Zhang     }
381cd4cee2dSHong Zhang 
382c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
3839566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
3849566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj]));
385cd4cee2dSHong Zhang       if (quadJp) {
3869566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
3879566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
3889566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col));
3899566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_drdp_col));
3909566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
39133f72c5dSHong Zhang       }
392c9681e5dSHong Zhang       if (ts->vecs_sensi2p) {
3939566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
3949566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, VecsDeltaMu2[nadj]));
39548a46eb9SPierre Jolivet         if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpu[nadj]));
39648a46eb9SPierre Jolivet         if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpp[nadj]));
397c9681e5dSHong Zhang       }
398c9681e5dSHong Zhang     }
399c9681e5dSHong Zhang   }
400c9681e5dSHong Zhang 
401c9681e5dSHong Zhang   if (ts->vecs_sensi2) {
4029566063dSJacob Faibussowitsch     PetscCall(VecResetArray(ts->vec_sensip_col));
4039566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
404c9681e5dSHong Zhang   }
405c9681e5dSHong Zhang   th->status = TS_STEP_COMPLETE;
4063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
407c9681e5dSHong Zhang }
408c9681e5dSHong Zhang 
409d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointStep_Theta(TS ts)
410d71ae5a4SJacob Faibussowitsch {
4112ca6e920SHong Zhang   TS_Theta    *th           = (TS_Theta *)ts->data;
412cd4cee2dSHong Zhang   TS           quadts       = ts->quadraturets;
413b5e0532dSHong Zhang   Vec         *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp;
414b5b4017aSHong Zhang   Vec         *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp;
4152ca6e920SHong Zhang   PetscInt     nadj;
4167207e0fdSHong Zhang   Mat          J, Jpre, quadJ = NULL, quadJp = NULL;
4172ca6e920SHong Zhang   KSP          ksp;
418b5b4017aSHong Zhang   PetscScalar *xarr;
4191a352fa8SHong Zhang   PetscReal    adjoint_time_step;
420da81f932SPierre Jolivet   PetscReal    adjoint_ptime; /* end time of the adjoint time step (ts->ptime is the start time, usually ts->ptime is larger than adjoint_ptime) */
4212ca6e920SHong Zhang 
4222ca6e920SHong Zhang   PetscFunctionBegin;
423c9681e5dSHong Zhang   if (th->Theta == 1.) {
4249566063dSJacob Faibussowitsch     PetscCall(TSAdjointStepBEuler_Private(ts));
4253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
426c9681e5dSHong Zhang   }
4272ca6e920SHong Zhang   th->status = TS_STEP_INCOMPLETE;
4289566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(ts->snes, &ksp));
4299566063dSJacob Faibussowitsch   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
4307207e0fdSHong Zhang   if (quadts) {
4319566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
4329566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
4337207e0fdSHong Zhang   }
434b5e0532dSHong Zhang   /* If endpoint=1, th->ptime and th->X0 will be used; if endpoint=0, th->stage_time and th->X will be used. */
4351a352fa8SHong Zhang   th->stage_time    = th->endpoint ? ts->ptime : (ts->ptime + (1. - th->Theta) * ts->time_step);
4361a352fa8SHong Zhang   adjoint_ptime     = ts->ptime + ts->time_step;
4371a352fa8SHong Zhang   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
4382ca6e920SHong Zhang 
43982ad9101SHong Zhang   if (!th->endpoint) {
4405072d23cSHong Zhang     /* recover th->X0 using vec_sol and the stage value th->X */
4419566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(th->X0, 1.0 / (1.0 - th->Theta), th->Theta / (th->Theta - 1.0), 0, th->X, ts->vec_sol));
44282ad9101SHong Zhang   }
44382ad9101SHong Zhang 
444b5b4017aSHong Zhang   /* Build RHS for first-order adjoint */
44533f72c5dSHong Zhang   /* Cost function has an integral term */
4467207e0fdSHong Zhang   if (quadts) {
44705755b9cSHong Zhang     if (th->endpoint) {
4489566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
44905755b9cSHong Zhang     } else {
4509566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
45105755b9cSHong Zhang     }
4527207e0fdSHong Zhang   }
45333f72c5dSHong Zhang 
454abc2977eSBarry Smith   for (nadj = 0; nadj < ts->numcost; nadj++) {
4559566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj]));
4569566063dSJacob Faibussowitsch     PetscCall(VecScale(VecsSensiTemp[nadj], 1. / (th->Theta * adjoint_time_step)));
457cd4cee2dSHong Zhang     if (quadJ) {
4589566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
4599566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
4609566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col));
4619566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_drdu_col));
4629566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
46336eaed60SHong Zhang     }
4642ca6e920SHong Zhang   }
4653c54f92cSHong Zhang 
466b5b4017aSHong Zhang   /* Build LHS for first-order adjoint */
4671a352fa8SHong Zhang   th->shift = 1. / (th->Theta * adjoint_time_step);
4683c54f92cSHong Zhang   if (th->endpoint) {
4699566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
4703c54f92cSHong Zhang   } else {
4719566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre));
4723c54f92cSHong Zhang   }
4739566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(ksp, J, Jpre));
4742ca6e920SHong Zhang 
475b5b4017aSHong Zhang   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
476abc2977eSBarry Smith   for (nadj = 0; nadj < ts->numcost; nadj++) {
4771d14d03bSHong Zhang     KSPConvergedReason kspreason;
4789566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj]));
4799566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
4801d14d03bSHong Zhang     if (kspreason < 0) {
4811d14d03bSHong Zhang       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
48263a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n", ts->steps, nadj));
4831d14d03bSHong Zhang     }
4842ca6e920SHong Zhang   }
4853c54f92cSHong Zhang 
4861d14d03bSHong Zhang   /* Second-order adjoint */
487b5b4017aSHong Zhang   if (ts->vecs_sensi2) { /* U_{n+1} */
4883c633725SBarry Smith     PetscCheck(th->endpoint, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Operation not implemented in TS_Theta");
489b5b4017aSHong Zhang     /* Get w1 at t_{n+1} from TLM matrix */
4909566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
4919566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
492b5b4017aSHong Zhang     /* lambda_s^T F_UU w_1 */
4939566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
4949566063dSJacob Faibussowitsch     PetscCall(VecResetArray(ts->vec_sensip_col));
4959566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
496b5b4017aSHong Zhang     /* lambda_s^T F_UP w_2 */
4979566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
498b5b4017aSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */
4999566063dSJacob Faibussowitsch       PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj]));
5009566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensi2Temp[nadj], th->shift));
5019566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj]));
50248a46eb9SPierre Jolivet       if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj]));
503b5b4017aSHong Zhang     }
504b5b4017aSHong Zhang     /* Solve stage equation LHS X = RHS for second-order adjoint */
505b5b4017aSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
5061d14d03bSHong Zhang       KSPConvergedReason kspreason;
5079566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj]));
5089566063dSJacob Faibussowitsch       PetscCall(KSPGetConvergedReason(ksp, &kspreason));
5091d14d03bSHong Zhang       if (kspreason < 0) {
5101d14d03bSHong Zhang         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
51163a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n", ts->steps, nadj));
5121d14d03bSHong Zhang       }
513b5b4017aSHong Zhang     }
514b5b4017aSHong Zhang   }
515b5b4017aSHong Zhang 
51636eaed60SHong Zhang   /* Update sensitivities, and evaluate integrals if there is any */
5171d14d03bSHong Zhang   if (th->endpoint) { /* two-stage Theta methods with th->Theta!=1, th->Theta==1 leads to BEuler */
5181a352fa8SHong Zhang     th->shift      = 1. / ((th->Theta - 1.) * adjoint_time_step);
5191a352fa8SHong Zhang     th->stage_time = adjoint_ptime;
5209566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, th->X0, J, Jpre));
5219566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, J, Jpre));
52233f72c5dSHong Zhang     /* R_U at t_n */
5231baa6e33SBarry Smith     if (quadts) PetscCall(TSComputeRHSJacobian(quadts, adjoint_ptime, th->X0, quadJ, NULL));
524abc2977eSBarry Smith     for (nadj = 0; nadj < ts->numcost; nadj++) {
5259566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], ts->vecs_sensi[nadj]));
526cd4cee2dSHong Zhang       if (quadJ) {
5279566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
5289566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
5299566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi[nadj], -1., ts->vec_drdu_col));
5309566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_drdu_col));
5319566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
532b5b4017aSHong Zhang       }
5339566063dSJacob Faibussowitsch       PetscCall(VecScale(ts->vecs_sensi[nadj], 1. / th->shift));
534b5b4017aSHong Zhang     }
5351d14d03bSHong Zhang 
5361d14d03bSHong Zhang     /* Second-order adjoint */
5371d14d03bSHong Zhang     if (ts->vecs_sensi2) { /* U_n */
538b5b4017aSHong Zhang       /* Get w1 at t_n from TLM matrix */
5399566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr));
5409566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
541b5b4017aSHong Zhang       /* lambda_s^T F_UU w_1 */
5429566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionUU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
5439566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_sensip_col));
5449566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr));
545b5b4017aSHong Zhang       /* lambda_s^T F_UU w_2 */
5469566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionUP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
547b5b4017aSHong Zhang       for (nadj = 0; nadj < ts->numcost; nadj++) {
54833f72c5dSHong Zhang         /* M^T Lambda_s + h(1-theta) F_U^T Lambda_s + h(1-theta) lambda_s^T F_UU w_1 + lambda_s^T F_UP w_2  */
5499566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(J, VecsDeltaLam2[nadj], ts->vecs_sensi2[nadj]));
5509566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fuu[nadj]));
55148a46eb9SPierre Jolivet         if (ts->vecs_fup) PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fup[nadj]));
5529566063dSJacob Faibussowitsch         PetscCall(VecScale(ts->vecs_sensi2[nadj], 1. / th->shift));
553b5b4017aSHong Zhang       }
554b5e0532dSHong Zhang     }
5553fd52205SHong Zhang 
556c586f2e8SHong Zhang     th->stage_time = ts->ptime; /* recover the old value */
557c586f2e8SHong Zhang 
5583fd52205SHong Zhang     if (ts->vecs_sensip) { /* sensitivities wrt parameters */
559b5b4017aSHong Zhang       /* U_{n+1} */
56082ad9101SHong Zhang       th->shift = 1.0 / (adjoint_time_step * th->Theta);
5619566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol));
5629566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, -1. / (th->Theta * adjoint_time_step), ts->Jacp, PETSC_FALSE));
5631baa6e33SBarry Smith       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
564abc2977eSBarry Smith       for (nadj = 0; nadj < ts->numcost; nadj++) {
5659566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
5669566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu[nadj]));
5673b711c3fSHong Zhang         if (quadJp) {
5689566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
5699566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
5709566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * th->Theta, ts->vec_drdp_col));
5719566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_drdp_col));
5729566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
5733b711c3fSHong Zhang         }
5743fd52205SHong Zhang       }
57533f72c5dSHong Zhang       if (ts->vecs_sensi2p) { /* second-order */
57633f72c5dSHong Zhang         /* Get w1 at t_{n+1} from TLM matrix */
5779566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
5789566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
579b5b4017aSHong Zhang         /* lambda_s^T F_PU w_1 */
5809566063dSJacob Faibussowitsch         PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
5819566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_sensip_col));
5829566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
58333f72c5dSHong Zhang 
584b5b4017aSHong Zhang         /* lambda_s^T F_PP w_2 */
5859566063dSJacob Faibussowitsch         PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
586b5b4017aSHong Zhang         for (nadj = 0; nadj < ts->numcost; nadj++) {
58733f72c5dSHong Zhang           /* Mu2 <- Mu2 + h theta F_P^T Lambda_s + h theta (lambda_s^T F_UU w_1 + lambda_s^T F_UP w_2)  */
5889566063dSJacob Faibussowitsch           PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
5899566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu2[nadj]));
59048a46eb9SPierre Jolivet           if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpu[nadj]));
59148a46eb9SPierre Jolivet           if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpp[nadj]));
592b5b4017aSHong Zhang         }
593b5b4017aSHong Zhang       }
594b5b4017aSHong Zhang 
595b5b4017aSHong Zhang       /* U_s */
5969566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(th->Xdot));
5979566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, adjoint_ptime, th->X0, th->Xdot, 1. / ((th->Theta - 1.0) * adjoint_time_step), ts->Jacp, PETSC_FALSE));
5981baa6e33SBarry Smith       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, adjoint_ptime, th->X0, quadJp));
599abc2977eSBarry Smith       for (nadj = 0; nadj < ts->numcost; nadj++) {
6009566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
6019566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu[nadj]));
6023b711c3fSHong Zhang         if (quadJp) {
6039566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
6049566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
6059566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * (1.0 - th->Theta), ts->vec_drdp_col));
6069566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_drdp_col));
6079566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
6083b711c3fSHong Zhang         }
60933f72c5dSHong Zhang         if (ts->vecs_sensi2p) { /* second-order */
61033f72c5dSHong Zhang           /* Get w1 at t_n from TLM matrix */
6119566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr));
6129566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
613b5b4017aSHong Zhang           /* lambda_s^T F_PU w_1 */
6149566063dSJacob Faibussowitsch           PetscCall(TSComputeIHessianProductFunctionPU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
6159566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_sensip_col));
6169566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr));
617b5b4017aSHong Zhang           /* lambda_s^T F_PP w_2 */
6189566063dSJacob Faibussowitsch           PetscCall(TSComputeIHessianProductFunctionPP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
619b5b4017aSHong Zhang           for (nadj = 0; nadj < ts->numcost; nadj++) {
62033f72c5dSHong Zhang             /* Mu2 <- Mu2 + h(1-theta) F_P^T Lambda_s + h(1-theta) (lambda_s^T F_UU w_1 + lambda_s^T F_UP w_2) */
6219566063dSJacob Faibussowitsch             PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
6229566063dSJacob Faibussowitsch             PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu2[nadj]));
62348a46eb9SPierre Jolivet             if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpu[nadj]));
62448a46eb9SPierre Jolivet             if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpp[nadj]));
62536eaed60SHong Zhang           }
62636eaed60SHong Zhang         }
6273fd52205SHong Zhang       }
628b5e0532dSHong Zhang     }
6293fd52205SHong Zhang   } else { /* one-stage case */
6303e05ceb1SHong Zhang     th->shift = 0.0;
6319566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre)); /* get -f_y */
6329566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, J, Jpre));
6331baa6e33SBarry Smith     if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
634abc2977eSBarry Smith     for (nadj = 0; nadj < ts->numcost; nadj++) {
6359566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj]));
6369566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ts->vecs_sensi[nadj], -adjoint_time_step, VecsSensiTemp[nadj]));
637cd4cee2dSHong Zhang       if (quadJ) {
6389566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
6399566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
6409566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi[nadj], adjoint_time_step, ts->vec_drdu_col));
6419566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_drdu_col));
6429566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
64336eaed60SHong Zhang       }
6442ca6e920SHong Zhang     }
6453fd52205SHong Zhang     if (ts->vecs_sensip) {
64682ad9101SHong Zhang       th->shift = 1.0 / (adjoint_time_step * th->Theta);
6479566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
6489566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
6491baa6e33SBarry Smith       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp));
650abc2977eSBarry Smith       for (nadj = 0; nadj < ts->numcost; nadj++) {
6519566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
6529566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj]));
653cd4cee2dSHong Zhang         if (quadJp) {
6549566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
6559566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
6569566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col));
6579566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_drdp_col));
6589566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
65936eaed60SHong Zhang         }
66036eaed60SHong Zhang       }
6613fd52205SHong Zhang     }
6622ca6e920SHong Zhang   }
6632ca6e920SHong Zhang 
6642ca6e920SHong Zhang   th->status = TS_STEP_COMPLETE;
6653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6662ca6e920SHong Zhang }
6672ca6e920SHong Zhang 
668d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_Theta(TS ts, PetscReal t, Vec X)
669d71ae5a4SJacob Faibussowitsch {
670cd652676SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
671be5899b3SLisandro Dalcin   PetscReal dt = t - ts->ptime;
672cd652676SJed Brown 
673cd652676SJed Brown   PetscFunctionBegin;
6749566063dSJacob Faibussowitsch   PetscCall(VecCopy(ts->vec_sol, th->X));
675be5899b3SLisandro Dalcin   if (th->endpoint) dt *= th->Theta;
6769566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(X, dt, th->Xdot, th->X));
6773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
678cd652676SJed Brown }
679cd652676SJed Brown 
680d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEvaluateWLTE_Theta(TS ts, NormType wnormtype, PetscInt *order, PetscReal *wlte)
681d71ae5a4SJacob Faibussowitsch {
6821566a47fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
6831566a47fSLisandro Dalcin   Vec       X  = ts->vec_sol;      /* X = solution */
6841566a47fSLisandro Dalcin   Vec       Y  = th->vec_lte_work; /* Y = X + LTE  */
6857453f775SEmil Constantinescu   PetscReal wltea, wlter;
6861566a47fSLisandro Dalcin 
6871566a47fSLisandro Dalcin   PetscFunctionBegin;
6889371c9d4SSatish Balay   if (!th->vec_sol_prev) {
6899371c9d4SSatish Balay     *wlte = -1;
6903ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6919371c9d4SSatish Balay   }
6921566a47fSLisandro Dalcin   /* Cannot compute LTE in first step or in restart after event */
6939371c9d4SSatish Balay   if (ts->steprestart) {
6949371c9d4SSatish Balay     *wlte = -1;
6953ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6969371c9d4SSatish Balay   }
6971566a47fSLisandro Dalcin   /* Compute LTE using backward differences with non-constant time step */
698fecfb714SLisandro Dalcin   {
699be5899b3SLisandro Dalcin     PetscReal   h = ts->time_step, h_prev = ts->ptime - ts->ptime_prev;
700be5899b3SLisandro Dalcin     PetscReal   a = 1 + h_prev / h;
7019371c9d4SSatish Balay     PetscScalar scal[3];
7029371c9d4SSatish Balay     Vec         vecs[3];
7039371c9d4SSatish Balay     scal[0] = +1 / a;
7049371c9d4SSatish Balay     scal[1] = -1 / (a - 1);
7059371c9d4SSatish Balay     scal[2] = +1 / (a * (a - 1));
7069371c9d4SSatish Balay     vecs[0] = X;
7079371c9d4SSatish Balay     vecs[1] = th->X0;
7089371c9d4SSatish Balay     vecs[2] = th->vec_sol_prev;
7099566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, Y));
7109566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(Y, 3, scal, vecs));
7119566063dSJacob Faibussowitsch     PetscCall(TSErrorWeightedNorm(ts, X, Y, wnormtype, wlte, &wltea, &wlter));
7121566a47fSLisandro Dalcin   }
7131566a47fSLisandro Dalcin   if (order) *order = 2;
7143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7151566a47fSLisandro Dalcin }
7161566a47fSLisandro Dalcin 
717d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSRollBack_Theta(TS ts)
718d71ae5a4SJacob Faibussowitsch {
7191566a47fSLisandro Dalcin   TS_Theta *th     = (TS_Theta *)ts->data;
7207207e0fdSHong Zhang   TS        quadts = ts->quadraturets;
7211566a47fSLisandro Dalcin 
7221566a47fSLisandro Dalcin   PetscFunctionBegin;
72348a46eb9SPierre Jolivet   if (quadts && ts->costintegralfwd) PetscCall(VecCopy(th->VecCostIntegral0, quadts->vec_sol));
724715f1b00SHong Zhang   th->status = TS_STEP_INCOMPLETE;
7251baa6e33SBarry Smith   if (ts->mat_sensip) PetscCall(MatCopy(th->MatFwdSensip0, ts->mat_sensip, SAME_NONZERO_PATTERN));
72648a46eb9SPierre Jolivet   if (quadts && quadts->mat_sensip) PetscCall(MatCopy(th->MatIntegralSensip0, quadts->mat_sensip, SAME_NONZERO_PATTERN));
7273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
728715f1b00SHong Zhang }
729715f1b00SHong Zhang 
730d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardStep_Theta(TS ts)
731d71ae5a4SJacob Faibussowitsch {
732715f1b00SHong Zhang   TS_Theta    *th                   = (TS_Theta *)ts->data;
733cd4cee2dSHong Zhang   TS           quadts               = ts->quadraturets;
73413b1b0ffSHong Zhang   Mat          MatDeltaFwdSensip    = th->MatDeltaFwdSensip;
735b5b4017aSHong Zhang   Vec          VecDeltaFwdSensipCol = th->VecDeltaFwdSensipCol;
7367207e0fdSHong Zhang   PetscInt     ntlm;
737715f1b00SHong Zhang   KSP          ksp;
7387207e0fdSHong Zhang   Mat          J, Jpre, quadJ = NULL, quadJp = NULL;
73913b1b0ffSHong Zhang   PetscScalar *barr, *xarr;
7401a352fa8SHong Zhang   PetscReal    previous_shift;
741715f1b00SHong Zhang 
742715f1b00SHong Zhang   PetscFunctionBegin;
7431a352fa8SHong Zhang   previous_shift = th->shift;
7449566063dSJacob Faibussowitsch   PetscCall(MatCopy(ts->mat_sensip, th->MatFwdSensip0, SAME_NONZERO_PATTERN));
74513b1b0ffSHong Zhang 
74648a46eb9SPierre Jolivet   if (quadts && quadts->mat_sensip) PetscCall(MatCopy(quadts->mat_sensip, th->MatIntegralSensip0, SAME_NONZERO_PATTERN));
7479566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(ts->snes, &ksp));
7489566063dSJacob Faibussowitsch   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
7497207e0fdSHong Zhang   if (quadts) {
7509566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
7519566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
7527207e0fdSHong Zhang   }
753715f1b00SHong Zhang 
754715f1b00SHong Zhang   /* Build RHS */
755715f1b00SHong Zhang   if (th->endpoint) { /* 2-stage method*/
7561a352fa8SHong Zhang     th->shift = 1. / ((th->Theta - 1.) * th->time_step0);
7579566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->ptime0, th->X0, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
7589566063dSJacob Faibussowitsch     PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DEFAULT, &MatDeltaFwdSensip));
7599566063dSJacob Faibussowitsch     PetscCall(MatScale(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta));
760715f1b00SHong Zhang 
761022c081aSHong Zhang     /* Add the f_p forcing terms */
7620e11c21fSHong Zhang     if (ts->Jacp) {
7639566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(th->Xdot));
7649566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->ptime0, th->X0, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
7659566063dSJacob Faibussowitsch       PetscCall(MatAXPY(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta, ts->Jacp, SUBSET_NONZERO_PATTERN));
76682ad9101SHong Zhang       th->shift = previous_shift;
7679566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol));
7689566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
7699566063dSJacob Faibussowitsch       PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN));
7700e11c21fSHong Zhang     }
771715f1b00SHong Zhang   } else { /* 1-stage method */
7723e05ceb1SHong Zhang     th->shift = 0.0;
7739566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
7749566063dSJacob Faibussowitsch     PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DEFAULT, &MatDeltaFwdSensip));
7759566063dSJacob Faibussowitsch     PetscCall(MatScale(MatDeltaFwdSensip, -1.));
77613b1b0ffSHong Zhang 
777022c081aSHong Zhang     /* Add the f_p forcing terms */
7780e11c21fSHong Zhang     if (ts->Jacp) {
77982ad9101SHong Zhang       th->shift = previous_shift;
7809566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
7819566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
7829566063dSJacob Faibussowitsch       PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN));
783715f1b00SHong Zhang     }
7840e11c21fSHong Zhang   }
785715f1b00SHong Zhang 
786715f1b00SHong Zhang   /* Build LHS */
7871a352fa8SHong Zhang   th->shift = previous_shift; /* recover the previous shift used in TSStep_Theta() */
788715f1b00SHong Zhang   if (th->endpoint) {
7899566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
790715f1b00SHong Zhang   } else {
7919566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
792715f1b00SHong Zhang   }
7939566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(ksp, J, Jpre));
794715f1b00SHong Zhang 
795715f1b00SHong Zhang   /*
796715f1b00SHong Zhang     Evaluate the first stage of integral gradients with the 2-stage method:
797c9ad9de0SHong Zhang     drdu|t_n*S(t_n) + drdp|t_n
798715f1b00SHong Zhang     This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1})
799715f1b00SHong Zhang   */
800715f1b00SHong Zhang   if (th->endpoint) { /* 2-stage method only */
8017207e0fdSHong Zhang     if (quadts && quadts->mat_sensip) {
8029566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->ptime0, th->X0, quadJ, NULL));
8039566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobianP(quadts, th->ptime0, th->X0, quadJp));
8049566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp));
8059566063dSJacob Faibussowitsch       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
8069566063dSJacob Faibussowitsch       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * (1. - th->Theta), th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
807715f1b00SHong Zhang     }
808715f1b00SHong Zhang   }
809715f1b00SHong Zhang 
810715f1b00SHong Zhang   /* Solve the tangent linear equation for forward sensitivities to parameters */
811022c081aSHong Zhang   for (ntlm = 0; ntlm < th->num_tlm; ntlm++) {
812b5b4017aSHong Zhang     KSPConvergedReason kspreason;
8139566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumn(MatDeltaFwdSensip, ntlm, &barr));
8149566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(VecDeltaFwdSensipCol, barr));
815715f1b00SHong Zhang     if (th->endpoint) {
8169566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(ts->mat_sensip, ntlm, &xarr));
8179566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
8189566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, ts->vec_sensip_col));
8199566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_sensip_col));
8209566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
821715f1b00SHong Zhang     } else {
8229566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, VecDeltaFwdSensipCol));
823715f1b00SHong Zhang     }
8249566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
825b5b4017aSHong Zhang     if (kspreason < 0) {
826b5b4017aSHong Zhang       ts->reason = TSFORWARD_DIVERGED_LINEAR_SOLVE;
82763a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th tangent linear solve, linear solve fails, stopping tangent linear solve\n", ts->steps, ntlm));
828b5b4017aSHong Zhang     }
8299566063dSJacob Faibussowitsch     PetscCall(VecResetArray(VecDeltaFwdSensipCol));
8309566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumn(MatDeltaFwdSensip, &barr));
831715f1b00SHong Zhang   }
832715f1b00SHong Zhang 
83313b1b0ffSHong Zhang   /*
83413b1b0ffSHong Zhang     Evaluate the second stage of integral gradients with the 2-stage method:
835c9ad9de0SHong Zhang     drdu|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1}
83613b1b0ffSHong Zhang   */
8377207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
83813b1b0ffSHong Zhang     if (!th->endpoint) {
8399566063dSJacob Faibussowitsch       PetscCall(MatAXPY(ts->mat_sensip, 1, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); /* stage sensitivity */
8409566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
8419566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp));
8429566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp));
8439566063dSJacob Faibussowitsch       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
8449566063dSJacob Faibussowitsch       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
8459566063dSJacob Faibussowitsch       PetscCall(MatAXPY(ts->mat_sensip, (1. - th->Theta) / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN));
84613b1b0ffSHong Zhang     } else {
8479566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
8489566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
8499566063dSJacob Faibussowitsch       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp));
8509566063dSJacob Faibussowitsch       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
8519566063dSJacob Faibussowitsch       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * th->Theta, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
85213b1b0ffSHong Zhang     }
85313b1b0ffSHong Zhang   } else {
85448a46eb9SPierre Jolivet     if (!th->endpoint) PetscCall(MatAXPY(ts->mat_sensip, 1. / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN));
855715f1b00SHong Zhang   }
8563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8571566a47fSLisandro Dalcin }
8581566a47fSLisandro Dalcin 
859d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardGetStages_Theta(TS ts, PetscInt *ns, Mat *stagesensip[])
860d71ae5a4SJacob Faibussowitsch {
8616affb6f8SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
8626affb6f8SHong Zhang 
8636affb6f8SHong Zhang   PetscFunctionBegin;
8647409eceaSHong Zhang   if (ns) {
8657409eceaSHong Zhang     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
8667409eceaSHong Zhang     else *ns = 2;                                   /* endpoint form */
8677409eceaSHong Zhang   }
8685072d23cSHong Zhang   if (stagesensip) {
869cc4f23bcSHong Zhang     if (!th->endpoint && th->Theta != 1.0) {
8707409eceaSHong Zhang       th->MatFwdStages[0] = th->MatDeltaFwdSensip;
871cc4f23bcSHong Zhang     } else {
872cc4f23bcSHong Zhang       th->MatFwdStages[0] = th->MatFwdSensip0;
873cc4f23bcSHong Zhang       th->MatFwdStages[1] = ts->mat_sensip; /* stiffly accurate */
874cc4f23bcSHong Zhang     }
875cc4f23bcSHong Zhang     *stagesensip = th->MatFwdStages;
8765072d23cSHong Zhang   }
8773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8786affb6f8SHong Zhang }
8796affb6f8SHong Zhang 
880316643e7SJed Brown /*------------------------------------------------------------*/
881d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_Theta(TS ts)
882d71ae5a4SJacob Faibussowitsch {
883316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
884316643e7SJed Brown 
885316643e7SJed Brown   PetscFunctionBegin;
8869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->X));
8879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->Xdot));
8889566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->X0));
8899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->affine));
8901566a47fSLisandro Dalcin 
8919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->vec_sol_prev));
8929566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->vec_lte_work));
8931566a47fSLisandro Dalcin 
8949566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->VecCostIntegral0));
8953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
896277b19d0SLisandro Dalcin }
897277b19d0SLisandro Dalcin 
898d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointReset_Theta(TS ts)
899d71ae5a4SJacob Faibussowitsch {
900ece46509SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
901ece46509SHong Zhang 
902ece46509SHong Zhang   PetscFunctionBegin;
9039566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam));
9049566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu));
9059566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam2));
9069566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu2));
9079566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensiTemp));
9089566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensi2Temp));
9093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
910ece46509SHong Zhang }
911ece46509SHong Zhang 
912d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_Theta(TS ts)
913d71ae5a4SJacob Faibussowitsch {
914277b19d0SLisandro Dalcin   PetscFunctionBegin;
9159566063dSJacob Faibussowitsch   PetscCall(TSReset_Theta(ts));
916b3a6b972SJed Brown   if (ts->dm) {
9179566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts));
9189566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts));
919b3a6b972SJed Brown   }
9209566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
9219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", NULL));
9229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", NULL));
9239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", NULL));
9249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", NULL));
9253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
926316643e7SJed Brown }
927316643e7SJed Brown 
928316643e7SJed Brown /*
929316643e7SJed Brown   This defines the nonlinear equation that is to be solved with SNES
9302b5a38e1SLisandro Dalcin   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
9310fd10508SMatthew Knepley 
9320fd10508SMatthew Knepley   Note that U here is the stage argument. This means that U = U_{n+1} only if endpoint = true,
9330fd10508SMatthew Knepley   otherwise U = theta U_{n+1} + (1 - theta) U0, which for the case of implicit midpoint is
9340fd10508SMatthew Knepley   U = (U_{n+1} + U0)/2
935316643e7SJed Brown */
936d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_Theta(SNES snes, Vec x, Vec y, TS ts)
937d71ae5a4SJacob Faibussowitsch {
938316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
9397445fe48SJed Brown   Vec       X0, Xdot;
9407445fe48SJed Brown   DM        dm, dmsave;
9413e05ceb1SHong Zhang   PetscReal shift = th->shift;
942316643e7SJed Brown 
943316643e7SJed Brown   PetscFunctionBegin;
9449566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
9455a3a76d0SJed Brown   /* When using the endpoint variant, this is actually 1/Theta * Xdot */
9469566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot));
947494ce9fcSHong Zhang   if (x != X0) {
9489566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x));
949494ce9fcSHong Zhang   } else {
9509566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(Xdot));
951494ce9fcSHong Zhang   }
9527445fe48SJed Brown   /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
9537445fe48SJed Brown   dmsave = ts->dm;
9547445fe48SJed Brown   ts->dm = dm;
9559566063dSJacob Faibussowitsch   PetscCall(TSComputeIFunction(ts, th->stage_time, x, Xdot, y, PETSC_FALSE));
9567445fe48SJed Brown   ts->dm = dmsave;
9579566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot));
9583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
959316643e7SJed Brown }
960316643e7SJed Brown 
961d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes, Vec x, Mat A, Mat B, TS ts)
962d71ae5a4SJacob Faibussowitsch {
963316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
9647445fe48SJed Brown   Vec       Xdot;
9657445fe48SJed Brown   DM        dm, dmsave;
9663e05ceb1SHong Zhang   PetscReal shift = th->shift;
967316643e7SJed Brown 
968316643e7SJed Brown   PetscFunctionBegin;
9699566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
970be5899b3SLisandro Dalcin   /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */
9719566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, dm, NULL, &Xdot));
9727445fe48SJed Brown 
9737445fe48SJed Brown   dmsave = ts->dm;
9747445fe48SJed Brown   ts->dm = dm;
9759566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, th->stage_time, x, Xdot, shift, A, B, PETSC_FALSE));
9767445fe48SJed Brown   ts->dm = dmsave;
9779566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, NULL, &Xdot));
9783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
979316643e7SJed Brown }
980316643e7SJed Brown 
981d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardSetUp_Theta(TS ts)
982d71ae5a4SJacob Faibussowitsch {
983715f1b00SHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
9847207e0fdSHong Zhang   TS        quadts = ts->quadraturets;
985715f1b00SHong Zhang 
986715f1b00SHong Zhang   PetscFunctionBegin;
987022c081aSHong Zhang   /* combine sensitivities to parameters and sensitivities to initial values into one array */
98813b1b0ffSHong Zhang   th->num_tlm = ts->num_parameters;
9899566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatDeltaFwdSensip));
9907207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
9919566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensipTemp));
9929566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensip0));
993715f1b00SHong Zhang   }
9946f92202bSHong Zhang   /* backup sensitivity results for roll-backs */
9959566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatFwdSensip0));
99613b1b0ffSHong Zhang 
9979566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &th->VecDeltaFwdSensipCol));
9983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
999715f1b00SHong Zhang }
1000715f1b00SHong Zhang 
1001d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardReset_Theta(TS ts)
1002d71ae5a4SJacob Faibussowitsch {
10037adebddeSHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
10047207e0fdSHong Zhang   TS        quadts = ts->quadraturets;
10057adebddeSHong Zhang 
10067adebddeSHong Zhang   PetscFunctionBegin;
10077207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
10089566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&th->MatIntegralSensipTemp));
10099566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&th->MatIntegralSensip0));
10107adebddeSHong Zhang   }
10119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->VecDeltaFwdSensipCol));
10129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&th->MatDeltaFwdSensip));
10139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&th->MatFwdSensip0));
10143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10157adebddeSHong Zhang }
10167adebddeSHong Zhang 
1017d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_Theta(TS ts)
1018d71ae5a4SJacob Faibussowitsch {
1019316643e7SJed Brown   TS_Theta *th     = (TS_Theta *)ts->data;
1020cd4cee2dSHong Zhang   TS        quadts = ts->quadraturets;
10212ffb9264SLisandro Dalcin   PetscBool match;
1022316643e7SJed Brown 
1023316643e7SJed Brown   PetscFunctionBegin;
1024cd4cee2dSHong Zhang   if (!th->VecCostIntegral0 && quadts && ts->costintegralfwd) { /* back up cost integral */
10259566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(quadts->vec_sol, &th->VecCostIntegral0));
1026b1cb36f3SHong Zhang   }
102748a46eb9SPierre Jolivet   if (!th->X) PetscCall(VecDuplicate(ts->vec_sol, &th->X));
102848a46eb9SPierre Jolivet   if (!th->Xdot) PetscCall(VecDuplicate(ts->vec_sol, &th->Xdot));
102948a46eb9SPierre Jolivet   if (!th->X0) PetscCall(VecDuplicate(ts->vec_sol, &th->X0));
103048a46eb9SPierre Jolivet   if (th->endpoint) PetscCall(VecDuplicate(ts->vec_sol, &th->affine));
10313b1890cdSShri Abhyankar 
10321566a47fSLisandro Dalcin   th->order = (th->Theta == 0.5) ? 2 : 1;
103320d49056SMatthew G. Knepley   th->shift = 1 / (th->Theta * ts->time_step);
10341566a47fSLisandro Dalcin 
10359566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &ts->dm));
10369566063dSJacob Faibussowitsch   PetscCall(DMCoarsenHookAdd(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts));
10379566063dSJacob Faibussowitsch   PetscCall(DMSubDomainHookAdd(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts));
10381566a47fSLisandro Dalcin 
10399566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts, &ts->adapt));
10409566063dSJacob Faibussowitsch   PetscCall(TSAdaptCandidatesClear(ts->adapt));
10419566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &match));
10422ffb9264SLisandro Dalcin   if (!match) {
1043ecc87898SStefano Zampini     if (!th->vec_sol_prev) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_sol_prev));
1044ecc87898SStefano Zampini     if (!th->vec_lte_work) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_lte_work));
10453b1890cdSShri Abhyankar   }
10469566063dSJacob Faibussowitsch   PetscCall(TSGetSNES(ts, &ts->snes));
1047cc4f23bcSHong Zhang 
1048cc4f23bcSHong Zhang   ts->stifflyaccurate = (!th->endpoint && th->Theta != 1.0) ? PETSC_FALSE : PETSC_TRUE;
10493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1050b4dd3bf9SBarry Smith }
10510c7376e5SHong Zhang 
1052b4dd3bf9SBarry Smith /*------------------------------------------------------------*/
1053b4dd3bf9SBarry Smith 
1054d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointSetUp_Theta(TS ts)
1055d71ae5a4SJacob Faibussowitsch {
1056b4dd3bf9SBarry Smith   TS_Theta *th = (TS_Theta *)ts->data;
1057b4dd3bf9SBarry Smith 
1058b4dd3bf9SBarry Smith   PetscFunctionBegin;
10599566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam));
10609566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsSensiTemp));
106148a46eb9SPierre Jolivet   if (ts->vecs_sensip) PetscCall(VecDuplicateVecs(ts->vecs_sensip[0], ts->numcost, &th->VecsDeltaMu));
1062b5b4017aSHong Zhang   if (ts->vecs_sensi2) {
10639566063dSJacob Faibussowitsch     PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam2));
10649566063dSJacob Faibussowitsch     PetscCall(VecDuplicateVecs(ts->vecs_sensi2[0], ts->numcost, &th->VecsSensi2Temp));
106567633408SHong Zhang     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
106667633408SHong Zhang     if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu;
106767633408SHong Zhang     if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup;
1068b5b4017aSHong Zhang   }
1069c9681e5dSHong Zhang   if (ts->vecs_sensi2p) {
10709566063dSJacob Faibussowitsch     PetscCall(VecDuplicateVecs(ts->vecs_sensi2p[0], ts->numcost, &th->VecsDeltaMu2));
107167633408SHong Zhang     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
107267633408SHong Zhang     if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu;
107367633408SHong Zhang     if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp;
1074b5b4017aSHong Zhang   }
10753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1076316643e7SJed Brown }
1077316643e7SJed Brown 
1078d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetFromOptions_Theta(TS ts, PetscOptionItems *PetscOptionsObject)
1079d71ae5a4SJacob Faibussowitsch {
1080316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
1081316643e7SJed Brown 
1082316643e7SJed Brown   PetscFunctionBegin;
1083d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Theta ODE solver options");
1084316643e7SJed Brown   {
10859566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_theta_theta", "Location of stage (0<Theta<=1)", "TSThetaSetTheta", th->Theta, &th->Theta, NULL));
10869566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_theta_endpoint", "Use the endpoint instead of midpoint form of the Theta method", "TSThetaSetEndpoint", th->endpoint, &th->endpoint, NULL));
10879566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_theta_initial_guess_extrapolate", "Extrapolate stage initial guess from previous solution (sometimes unstable)", "TSThetaSetExtrapolate", th->extrapolate, &th->extrapolate, NULL));
1088316643e7SJed Brown   }
1089d0609cedSBarry Smith   PetscOptionsHeadEnd();
10903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1091316643e7SJed Brown }
1092316643e7SJed Brown 
1093d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_Theta(TS ts, PetscViewer viewer)
1094d71ae5a4SJacob Faibussowitsch {
1095316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
1096ace3abfcSBarry Smith   PetscBool iascii;
1097316643e7SJed Brown 
1098316643e7SJed Brown   PetscFunctionBegin;
10999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1100316643e7SJed Brown   if (iascii) {
11019566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Theta=%g\n", (double)th->Theta));
11029566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation=%s\n", th->extrapolate ? "yes" : "no"));
1103316643e7SJed Brown   }
11043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1105316643e7SJed Brown }
1106316643e7SJed Brown 
1107d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetTheta_Theta(TS ts, PetscReal *theta)
1108d71ae5a4SJacob Faibussowitsch {
11090de4c49aSJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
11100de4c49aSJed Brown 
11110de4c49aSJed Brown   PetscFunctionBegin;
11120de4c49aSJed Brown   *theta = th->Theta;
11133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11140de4c49aSJed Brown }
11150de4c49aSJed Brown 
1116d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaSetTheta_Theta(TS ts, PetscReal theta)
1117d71ae5a4SJacob Faibussowitsch {
11180de4c49aSJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
11190de4c49aSJed Brown 
11200de4c49aSJed Brown   PetscFunctionBegin;
1121cad9d221SBarry Smith   PetscCheck(theta > 0 && theta <= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Theta %g not in range (0,1]", (double)theta);
11220de4c49aSJed Brown   th->Theta = theta;
11231566a47fSLisandro Dalcin   th->order = (th->Theta == 0.5) ? 2 : 1;
11243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11250de4c49aSJed Brown }
1126eb284becSJed Brown 
1127d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts, PetscBool *endpoint)
1128d71ae5a4SJacob Faibussowitsch {
112926f2ff8fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
113026f2ff8fSLisandro Dalcin 
113126f2ff8fSLisandro Dalcin   PetscFunctionBegin;
113226f2ff8fSLisandro Dalcin   *endpoint = th->endpoint;
11333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
113426f2ff8fSLisandro Dalcin }
113526f2ff8fSLisandro Dalcin 
1136d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts, PetscBool flg)
1137d71ae5a4SJacob Faibussowitsch {
1138eb284becSJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
1139eb284becSJed Brown 
1140eb284becSJed Brown   PetscFunctionBegin;
1141eb284becSJed Brown   th->endpoint = flg;
11423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1143eb284becSJed Brown }
11440de4c49aSJed Brown 
1145f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX)
1146d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSComputeLinearStability_Theta(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi)
1147d71ae5a4SJacob Faibussowitsch {
1148f9c1d6abSBarry Smith   PetscComplex z  = xr + xi * PETSC_i, f;
1149f9c1d6abSBarry Smith   TS_Theta    *th = (TS_Theta *)ts->data;
1150f9c1d6abSBarry Smith 
1151f9c1d6abSBarry Smith   PetscFunctionBegin;
1152*520136c7SJose E. Roman   f   = (1.0 + (1.0 - th->Theta) * z) / (1.0 - th->Theta * z);
1153f9c1d6abSBarry Smith   *yr = PetscRealPartComplex(f);
1154f9c1d6abSBarry Smith   *yi = PetscImaginaryPartComplex(f);
11553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1156f9c1d6abSBarry Smith }
1157f9c1d6abSBarry Smith #endif
1158f9c1d6abSBarry Smith 
1159d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGetStages_Theta(TS ts, PetscInt *ns, Vec *Y[])
1160d71ae5a4SJacob Faibussowitsch {
116142682096SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
116242682096SHong Zhang 
116342682096SHong Zhang   PetscFunctionBegin;
11647409eceaSHong Zhang   if (ns) {
11657409eceaSHong Zhang     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
11667409eceaSHong Zhang     else *ns = 2;                                   /* endpoint form */
11677409eceaSHong Zhang   }
11685072d23cSHong Zhang   if (Y) {
1169cc4f23bcSHong Zhang     if (!th->endpoint && th->Theta != 1.0) {
11707409eceaSHong Zhang       th->Stages[0] = th->X;
1171cc4f23bcSHong Zhang     } else {
1172cc4f23bcSHong Zhang       th->Stages[0] = th->X0;
1173cc4f23bcSHong Zhang       th->Stages[1] = ts->vec_sol; /* stiffly accurate */
1174cc4f23bcSHong Zhang     }
1175cc4f23bcSHong Zhang     *Y = th->Stages;
11765072d23cSHong Zhang   }
11773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
117842682096SHong Zhang }
1179f9c1d6abSBarry Smith 
1180316643e7SJed Brown /* ------------------------------------------------------------ */
1181316643e7SJed Brown /*MC
118296f5712cSJed Brown       TSTHETA - DAE solver using the implicit Theta method
1183316643e7SJed Brown 
1184316643e7SJed Brown    Level: beginner
1185316643e7SJed Brown 
1186bcf0153eSBarry Smith    Options Database Keys:
1187c82ed962SBarry Smith +  -ts_theta_theta <Theta> - Location of stage (0<Theta<=1)
1188c82ed962SBarry Smith .  -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method
118903842d09SLisandro Dalcin -  -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable)
11904eb428fdSBarry Smith 
1191eb284becSJed Brown    Notes:
119237fdd005SBarry Smith .vb
119337fdd005SBarry Smith   -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER)
119437fdd005SBarry Smith   -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule
119537fdd005SBarry Smith   -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN)
119637fdd005SBarry Smith .ve
11974eb428fdSBarry Smith 
11987409eceaSHong Zhang    The endpoint variant of the Theta method and backward Euler can be applied to DAE. The midpoint variant is not suitable for DAEs because it is not stiffly accurate.
1199eb284becSJed Brown 
12007409eceaSHong Zhang    The midpoint variant is cast as a 1-stage implicit Runge-Kutta method.
1201eb284becSJed Brown 
1202eb284becSJed Brown .vb
1203eb284becSJed Brown   Theta | Theta
1204eb284becSJed Brown   -------------
1205eb284becSJed Brown         |  1
1206eb284becSJed Brown .ve
1207eb284becSJed Brown 
1208eb284becSJed Brown    For the default Theta=0.5, this is also known as the implicit midpoint rule.
1209eb284becSJed Brown 
1210eb284becSJed Brown    When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit:
1211eb284becSJed Brown 
1212eb284becSJed Brown .vb
1213eb284becSJed Brown   0 | 0         0
1214eb284becSJed Brown   1 | 1-Theta   Theta
1215eb284becSJed Brown   -------------------
1216eb284becSJed Brown     | 1-Theta   Theta
1217eb284becSJed Brown .ve
1218eb284becSJed Brown 
1219eb284becSJed Brown    For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN).
1220eb284becSJed Brown 
1221eb284becSJed Brown    To apply a diagonally implicit RK method to DAE, the stage formula
1222eb284becSJed Brown 
1223eb284becSJed Brown $  Y_i = X + h sum_j a_ij Y'_j
1224eb284becSJed Brown 
12254eb428fdSBarry Smith    is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i)
1226eb284becSJed Brown 
12271cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSCN`, `TSBEULER`, `TSThetaSetTheta()`, `TSThetaSetEndpoint()`
1228316643e7SJed Brown M*/
1229d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts)
1230d71ae5a4SJacob Faibussowitsch {
1231316643e7SJed Brown   TS_Theta *th;
1232316643e7SJed Brown 
1233316643e7SJed Brown   PetscFunctionBegin;
1234277b19d0SLisandro Dalcin   ts->ops->reset          = TSReset_Theta;
1235ece46509SHong Zhang   ts->ops->adjointreset   = TSAdjointReset_Theta;
1236316643e7SJed Brown   ts->ops->destroy        = TSDestroy_Theta;
1237316643e7SJed Brown   ts->ops->view           = TSView_Theta;
1238316643e7SJed Brown   ts->ops->setup          = TSSetUp_Theta;
123942f2b339SBarry Smith   ts->ops->adjointsetup   = TSAdjointSetUp_Theta;
1240ece46509SHong Zhang   ts->ops->adjointreset   = TSAdjointReset_Theta;
1241316643e7SJed Brown   ts->ops->step           = TSStep_Theta;
1242cd652676SJed Brown   ts->ops->interpolate    = TSInterpolate_Theta;
12431566a47fSLisandro Dalcin   ts->ops->evaluatewlte   = TSEvaluateWLTE_Theta;
124424655328SShri   ts->ops->rollback       = TSRollBack_Theta;
124526b5f05dSStefano Zampini   ts->ops->resizeregister = TSResizeRegister_Theta;
1246316643e7SJed Brown   ts->ops->setfromoptions = TSSetFromOptions_Theta;
12470f5c6efeSJed Brown   ts->ops->snesfunction   = SNESTSFormFunction_Theta;
12480f5c6efeSJed Brown   ts->ops->snesjacobian   = SNESTSFormJacobian_Theta;
1249f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX)
1250f9c1d6abSBarry Smith   ts->ops->linearstability = TSComputeLinearStability_Theta;
1251f9c1d6abSBarry Smith #endif
125242682096SHong Zhang   ts->ops->getstages       = TSGetStages_Theta;
125342f2b339SBarry Smith   ts->ops->adjointstep     = TSAdjointStep_Theta;
1254b1cb36f3SHong Zhang   ts->ops->adjointintegral = TSAdjointCostIntegral_Theta;
1255b1cb36f3SHong Zhang   ts->ops->forwardintegral = TSForwardCostIntegral_Theta;
12562ffb9264SLisandro Dalcin   ts->default_adapt_type   = TSADAPTNONE;
12576affb6f8SHong Zhang 
1258715f1b00SHong Zhang   ts->ops->forwardsetup     = TSForwardSetUp_Theta;
12597adebddeSHong Zhang   ts->ops->forwardreset     = TSForwardReset_Theta;
1260715f1b00SHong Zhang   ts->ops->forwardstep      = TSForwardStep_Theta;
12616affb6f8SHong Zhang   ts->ops->forwardgetstages = TSForwardGetStages_Theta;
1262316643e7SJed Brown 
1263efd4aadfSBarry Smith   ts->usessnes = PETSC_TRUE;
1264efd4aadfSBarry Smith 
12654dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&th));
1266316643e7SJed Brown   ts->data = (void *)th;
1267316643e7SJed Brown 
1268715f1b00SHong Zhang   th->VecsDeltaLam   = NULL;
1269715f1b00SHong Zhang   th->VecsDeltaMu    = NULL;
1270715f1b00SHong Zhang   th->VecsSensiTemp  = NULL;
1271b5b4017aSHong Zhang   th->VecsSensi2Temp = NULL;
1272715f1b00SHong Zhang 
12736f700aefSJed Brown   th->extrapolate = PETSC_FALSE;
1274316643e7SJed Brown   th->Theta       = 0.5;
12751566a47fSLisandro Dalcin   th->order       = 2;
12769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", TSThetaGetTheta_Theta));
12779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", TSThetaSetTheta_Theta));
12789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", TSThetaGetEndpoint_Theta));
12799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", TSThetaSetEndpoint_Theta));
12803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1281316643e7SJed Brown }
12820de4c49aSJed Brown 
12830de4c49aSJed Brown /*@
1284bcf0153eSBarry Smith   TSThetaGetTheta - Get the abscissa of the stage in (0,1] for `TSTHETA`
12850de4c49aSJed Brown 
12860de4c49aSJed Brown   Not Collective
12870de4c49aSJed Brown 
12880de4c49aSJed Brown   Input Parameter:
12890de4c49aSJed Brown . ts - timestepping context
12900de4c49aSJed Brown 
12910de4c49aSJed Brown   Output Parameter:
12920de4c49aSJed Brown . theta - stage abscissa
12930de4c49aSJed Brown 
1294bcf0153eSBarry Smith   Level: advanced
1295bcf0153eSBarry Smith 
12960de4c49aSJed Brown   Note:
1297bcf0153eSBarry Smith   Use of this function is normally only required to hack `TSTHETA` to use a modified integration scheme.
12980de4c49aSJed Brown 
12991cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaSetTheta()`, `TSTHETA`
13000de4c49aSJed Brown @*/
1301d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaGetTheta(TS ts, PetscReal *theta)
1302d71ae5a4SJacob Faibussowitsch {
13030de4c49aSJed Brown   PetscFunctionBegin;
1304afb20b64SJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
13054f572ea9SToby Isaac   PetscAssertPointer(theta, 2);
1306cac4c232SBarry Smith   PetscUseMethod(ts, "TSThetaGetTheta_C", (TS, PetscReal *), (ts, theta));
13073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13080de4c49aSJed Brown }
13090de4c49aSJed Brown 
13100de4c49aSJed Brown /*@
1311bcf0153eSBarry Smith   TSThetaSetTheta - Set the abscissa of the stage in (0,1]  for `TSTHETA`
13120de4c49aSJed Brown 
13130de4c49aSJed Brown   Not Collective
13140de4c49aSJed Brown 
1315d8d19677SJose E. Roman   Input Parameters:
13160de4c49aSJed Brown + ts    - timestepping context
13170de4c49aSJed Brown - theta - stage abscissa
13180de4c49aSJed Brown 
1319bcf0153eSBarry Smith   Options Database Key:
132067b8a455SSatish Balay . -ts_theta_theta <theta> - set theta
13210de4c49aSJed Brown 
1322bcf0153eSBarry Smith   Level: intermediate
13230de4c49aSJed Brown 
13241cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaGetTheta()`, `TSTHETA`, `TSCN`
13250de4c49aSJed Brown @*/
1326d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaSetTheta(TS ts, PetscReal theta)
1327d71ae5a4SJacob Faibussowitsch {
13280de4c49aSJed Brown   PetscFunctionBegin;
1329afb20b64SJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1330cac4c232SBarry Smith   PetscTryMethod(ts, "TSThetaSetTheta_C", (TS, PetscReal), (ts, theta));
13313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13320de4c49aSJed Brown }
1333f33bbcb6SJed Brown 
133426f2ff8fSLisandro Dalcin /*@
1335bcf0153eSBarry Smith   TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA`
133626f2ff8fSLisandro Dalcin 
133726f2ff8fSLisandro Dalcin   Not Collective
133826f2ff8fSLisandro Dalcin 
133926f2ff8fSLisandro Dalcin   Input Parameter:
134026f2ff8fSLisandro Dalcin . ts - timestepping context
134126f2ff8fSLisandro Dalcin 
134226f2ff8fSLisandro Dalcin   Output Parameter:
1343bcf0153eSBarry Smith . endpoint - `PETSC_TRUE` when using the endpoint variant
134426f2ff8fSLisandro Dalcin 
1345bcf0153eSBarry Smith   Level: advanced
134626f2ff8fSLisandro Dalcin 
13471cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaSetEndpoint()`, `TSTHETA`, `TSCN`
134826f2ff8fSLisandro Dalcin @*/
1349d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaGetEndpoint(TS ts, PetscBool *endpoint)
1350d71ae5a4SJacob Faibussowitsch {
135126f2ff8fSLisandro Dalcin   PetscFunctionBegin;
135226f2ff8fSLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
13534f572ea9SToby Isaac   PetscAssertPointer(endpoint, 2);
1354cac4c232SBarry Smith   PetscUseMethod(ts, "TSThetaGetEndpoint_C", (TS, PetscBool *), (ts, endpoint));
13553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
135626f2ff8fSLisandro Dalcin }
135726f2ff8fSLisandro Dalcin 
1358eb284becSJed Brown /*@
1359bcf0153eSBarry Smith   TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA`
1360eb284becSJed Brown 
1361eb284becSJed Brown   Not Collective
1362eb284becSJed Brown 
1363d8d19677SJose E. Roman   Input Parameters:
1364eb284becSJed Brown + ts  - timestepping context
1365bcf0153eSBarry Smith - flg - `PETSC_TRUE` to use the endpoint variant
1366eb284becSJed Brown 
1367bcf0153eSBarry Smith   Options Database Key:
136867b8a455SSatish Balay . -ts_theta_endpoint <flg> - use the endpoint variant
1369eb284becSJed Brown 
1370bcf0153eSBarry Smith   Level: intermediate
1371eb284becSJed Brown 
13721cc06b55SBarry Smith .seealso: [](ch_ts), `TSTHETA`, `TSCN`
1373eb284becSJed Brown @*/
1374d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaSetEndpoint(TS ts, PetscBool flg)
1375d71ae5a4SJacob Faibussowitsch {
1376eb284becSJed Brown   PetscFunctionBegin;
1377eb284becSJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1378cac4c232SBarry Smith   PetscTryMethod(ts, "TSThetaSetEndpoint_C", (TS, PetscBool), (ts, flg));
13793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1380eb284becSJed Brown }
1381eb284becSJed Brown 
1382f33bbcb6SJed Brown /*
1383f33bbcb6SJed Brown  * TSBEULER and TSCN are straightforward specializations of TSTHETA.
1384f33bbcb6SJed Brown  * The creation functions for these specializations are below.
1385f33bbcb6SJed Brown  */
1386f33bbcb6SJed Brown 
1387d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_BEuler(TS ts)
1388d71ae5a4SJacob Faibussowitsch {
13891566a47fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
13901566a47fSLisandro Dalcin 
13911566a47fSLisandro Dalcin   PetscFunctionBegin;
139208401ef6SPierre Jolivet   PetscCheck(th->Theta == 1.0, PetscObjectComm((PetscObject)ts), PETSC_ERR_OPT_OVERWRITE, "Can not change the default value (1) of theta when using backward Euler");
139328b400f6SJacob Faibussowitsch   PetscCheck(!th->endpoint, PetscObjectComm((PetscObject)ts), PETSC_ERR_OPT_OVERWRITE, "Can not change to the endpoint form of the Theta methods when using backward Euler");
13949566063dSJacob Faibussowitsch   PetscCall(TSSetUp_Theta(ts));
13953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13961566a47fSLisandro Dalcin }
13971566a47fSLisandro Dalcin 
1398d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_BEuler(TS ts, PetscViewer viewer)
1399d71ae5a4SJacob Faibussowitsch {
1400f33bbcb6SJed Brown   PetscFunctionBegin;
14013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1402f33bbcb6SJed Brown }
1403f33bbcb6SJed Brown 
1404f33bbcb6SJed Brown /*MC
1405f33bbcb6SJed Brown       TSBEULER - ODE solver using the implicit backward Euler method
1406f33bbcb6SJed Brown 
1407f33bbcb6SJed Brown   Level: beginner
1408f33bbcb6SJed Brown 
1409bcf0153eSBarry Smith   Note:
141037fdd005SBarry Smith   `TSBEULER` is equivalent to `TSTHETA` with Theta=1.0 or `-ts_type theta -ts_theta_theta 1.0`
14114eb428fdSBarry Smith 
14121cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSEULER`, `TSCN`, `TSTHETA`
1413f33bbcb6SJed Brown M*/
1414d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts)
1415d71ae5a4SJacob Faibussowitsch {
1416f33bbcb6SJed Brown   PetscFunctionBegin;
14179566063dSJacob Faibussowitsch   PetscCall(TSCreate_Theta(ts));
14189566063dSJacob Faibussowitsch   PetscCall(TSThetaSetTheta(ts, 1.0));
14199566063dSJacob Faibussowitsch   PetscCall(TSThetaSetEndpoint(ts, PETSC_FALSE));
14200c7376e5SHong Zhang   ts->ops->setup = TSSetUp_BEuler;
1421f33bbcb6SJed Brown   ts->ops->view  = TSView_BEuler;
14223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1423f33bbcb6SJed Brown }
1424f33bbcb6SJed Brown 
1425d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_CN(TS ts)
1426d71ae5a4SJacob Faibussowitsch {
14271566a47fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
14281566a47fSLisandro Dalcin 
14291566a47fSLisandro Dalcin   PetscFunctionBegin;
143008401ef6SPierre Jolivet   PetscCheck(th->Theta == 0.5, PetscObjectComm((PetscObject)ts), PETSC_ERR_OPT_OVERWRITE, "Can not change the default value (0.5) of theta when using Crank-Nicolson");
14313c633725SBarry Smith   PetscCheck(th->endpoint, PetscObjectComm((PetscObject)ts), PETSC_ERR_OPT_OVERWRITE, "Can not change to the midpoint form of the Theta methods when using Crank-Nicolson");
14329566063dSJacob Faibussowitsch   PetscCall(TSSetUp_Theta(ts));
14333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14341566a47fSLisandro Dalcin }
14351566a47fSLisandro Dalcin 
1436d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_CN(TS ts, PetscViewer viewer)
1437d71ae5a4SJacob Faibussowitsch {
1438f33bbcb6SJed Brown   PetscFunctionBegin;
14393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1440f33bbcb6SJed Brown }
1441f33bbcb6SJed Brown 
1442f33bbcb6SJed Brown /*MC
1443f33bbcb6SJed Brown       TSCN - ODE solver using the implicit Crank-Nicolson method.
1444f33bbcb6SJed Brown 
1445f33bbcb6SJed Brown   Level: beginner
1446f33bbcb6SJed Brown 
1447f33bbcb6SJed Brown   Notes:
1448bcf0153eSBarry Smith   `TSCN` is equivalent to `TSTHETA` with Theta=0.5 and the "endpoint" option set. I.e.
1449bcf0153eSBarry Smith .vb
1450bcf0153eSBarry Smith   -ts_type theta
1451bcf0153eSBarry Smith   -ts_theta_theta 0.5
1452bcf0153eSBarry Smith   -ts_theta_endpoint
1453bcf0153eSBarry Smith .ve
14547cf5af47SJed Brown 
14551cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSBEULER`, `TSTHETA`, `TSType`,
1456f33bbcb6SJed Brown M*/
1457d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts)
1458d71ae5a4SJacob Faibussowitsch {
1459f33bbcb6SJed Brown   PetscFunctionBegin;
14609566063dSJacob Faibussowitsch   PetscCall(TSCreate_Theta(ts));
14619566063dSJacob Faibussowitsch   PetscCall(TSThetaSetTheta(ts, 0.5));
14629566063dSJacob Faibussowitsch   PetscCall(TSThetaSetEndpoint(ts, PETSC_TRUE));
14630c7376e5SHong Zhang   ts->ops->setup = TSSetUp_CN;
1464f33bbcb6SJed Brown   ts->ops->view  = TSView_CN;
14653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1466f33bbcb6SJed Brown }
1467