xref: /petsc/src/ts/impls/implicit/theta/theta.c (revision ac530a7e429a3ef5a9263376acf6071236a5db98)
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) {
51*ac530a7eSPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_X0", X0));
52*ac530a7eSPierre Jolivet     else *X0 = ts->vec_sol;
537445fe48SJed Brown   }
547445fe48SJed Brown   if (Xdot) {
55*ac530a7eSPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_Xdot", Xdot));
56*ac530a7eSPierre Jolivet     else *Xdot = th->Xdot;
577445fe48SJed Brown   }
583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
597445fe48SJed Brown }
607445fe48SJed Brown 
61d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
62d71ae5a4SJacob Faibussowitsch {
630d0b770aSPeter Brune   PetscFunctionBegin;
640d0b770aSPeter Brune   if (X0) {
6548a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_X0", X0));
660d0b770aSPeter Brune   }
670d0b770aSPeter Brune   if (Xdot) {
6848a46eb9SPierre Jolivet     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_Xdot", Xdot));
690d0b770aSPeter Brune   }
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
710d0b770aSPeter Brune }
720d0b770aSPeter Brune 
73d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_TSTheta(DM fine, DM coarse, void *ctx)
74d71ae5a4SJacob Faibussowitsch {
757445fe48SJed Brown   PetscFunctionBegin;
763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
777445fe48SJed Brown }
787445fe48SJed Brown 
79d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_TSTheta(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
80d71ae5a4SJacob Faibussowitsch {
817445fe48SJed Brown   TS  ts = (TS)ctx;
827445fe48SJed Brown   Vec X0, Xdot, X0_c, Xdot_c;
837445fe48SJed Brown 
847445fe48SJed Brown   PetscFunctionBegin;
859566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, fine, &X0, &Xdot));
869566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
879566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, X0, X0_c));
889566063dSJacob Faibussowitsch   PetscCall(MatRestrict(restrct, Xdot, Xdot_c));
899566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(X0_c, rscale, X0_c));
909566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(Xdot_c, rscale, Xdot_c));
919566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, fine, &X0, &Xdot));
929566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
947445fe48SJed Brown }
957445fe48SJed Brown 
96d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_TSTheta(DM dm, DM subdm, void *ctx)
97d71ae5a4SJacob Faibussowitsch {
98258e1594SPeter Brune   PetscFunctionBegin;
993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100258e1594SPeter Brune }
101258e1594SPeter Brune 
102d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
103d71ae5a4SJacob Faibussowitsch {
104258e1594SPeter Brune   TS  ts = (TS)ctx;
105258e1594SPeter Brune   Vec X0, Xdot, X0_sub, Xdot_sub;
106258e1594SPeter Brune 
107258e1594SPeter Brune   PetscFunctionBegin;
1089566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot));
1099566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
110258e1594SPeter Brune 
1119566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
1129566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
113258e1594SPeter Brune 
1149566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
1159566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
116258e1594SPeter Brune 
1179566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot));
1189566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
1193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
120258e1594SPeter Brune }
121258e1594SPeter Brune 
122d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaEvaluateCostIntegral(TS ts)
123d71ae5a4SJacob Faibussowitsch {
124022c081aSHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
125cd4cee2dSHong Zhang   TS        quadts = ts->quadraturets;
126022c081aSHong Zhang 
127022c081aSHong Zhang   PetscFunctionBegin;
128022c081aSHong Zhang   if (th->endpoint) {
129022c081aSHong Zhang     /* Evolve ts->vec_costintegral to compute integrals */
130022c081aSHong Zhang     if (th->Theta != 1.0) {
1319566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSFunction(quadts, th->ptime0, th->X0, ts->vec_costintegrand));
1329566063dSJacob Faibussowitsch       PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * (1.0 - th->Theta), ts->vec_costintegrand));
133022c081aSHong Zhang     }
1349566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSFunction(quadts, ts->ptime, ts->vec_sol, ts->vec_costintegrand));
1359566063dSJacob Faibussowitsch     PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * th->Theta, ts->vec_costintegrand));
136022c081aSHong Zhang   } else {
1379566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSFunction(quadts, th->stage_time, th->X, ts->vec_costintegrand));
1389566063dSJacob Faibussowitsch     PetscCall(VecAXPY(quadts->vec_sol, th->time_step0, ts->vec_costintegrand));
139022c081aSHong Zhang   }
1403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
141022c081aSHong Zhang }
142022c081aSHong Zhang 
143d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardCostIntegral_Theta(TS ts)
144d71ae5a4SJacob Faibussowitsch {
145b1cb36f3SHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
146cd4cee2dSHong Zhang   TS        quadts = ts->quadraturets;
147b1cb36f3SHong Zhang 
148b1cb36f3SHong Zhang   PetscFunctionBegin;
149b1cb36f3SHong Zhang   /* backup cost integral */
1509566063dSJacob Faibussowitsch   PetscCall(VecCopy(quadts->vec_sol, th->VecCostIntegral0));
1519566063dSJacob Faibussowitsch   PetscCall(TSThetaEvaluateCostIntegral(ts));
1523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153b1cb36f3SHong Zhang }
154b1cb36f3SHong Zhang 
155d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointCostIntegral_Theta(TS ts)
156d71ae5a4SJacob Faibussowitsch {
1571a352fa8SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
158b1cb36f3SHong Zhang 
159b1cb36f3SHong Zhang   PetscFunctionBegin;
1601a352fa8SHong Zhang   /* Like TSForwardCostIntegral(), the adjoint cost integral evaluation relies on ptime0 and time_step0. */
1611a352fa8SHong Zhang   th->ptime0     = ts->ptime + ts->time_step;
1621a352fa8SHong Zhang   th->time_step0 = -ts->time_step;
1639566063dSJacob Faibussowitsch   PetscCall(TSThetaEvaluateCostIntegral(ts));
1643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16524655328SShri }
16624655328SShri 
167d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSTheta_SNESSolve(TS ts, Vec b, Vec x)
168d71ae5a4SJacob Faibussowitsch {
1691566a47fSLisandro Dalcin   PetscInt nits, lits;
1701566a47fSLisandro Dalcin 
1711566a47fSLisandro Dalcin   PetscFunctionBegin;
1729566063dSJacob Faibussowitsch   PetscCall(SNESSolve(ts->snes, b, x));
1739566063dSJacob Faibussowitsch   PetscCall(SNESGetIterationNumber(ts->snes, &nits));
1749566063dSJacob Faibussowitsch   PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
1759371c9d4SSatish Balay   ts->snes_its += nits;
1769371c9d4SSatish Balay   ts->ksp_its += lits;
1773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1781566a47fSLisandro Dalcin }
1791566a47fSLisandro Dalcin 
18026b5f05dSStefano Zampini static PetscErrorCode TSResizeRegister_Theta(TS ts, PetscBool reg)
18126b5f05dSStefano Zampini {
18226b5f05dSStefano Zampini   TS_Theta *th = (TS_Theta *)ts->data;
18326b5f05dSStefano Zampini 
18426b5f05dSStefano Zampini   PetscFunctionBegin;
185ecc87898SStefano Zampini   if (reg) {
186ecc87898SStefano Zampini     PetscCall(TSResizeRegisterVec(ts, "ts:theta:sol_prev", th->vec_sol_prev));
187ecc87898SStefano Zampini     PetscCall(TSResizeRegisterVec(ts, "ts:theta:X0", th->X0));
188ecc87898SStefano Zampini   } else {
189ecc87898SStefano Zampini     PetscCall(TSResizeRetrieveVec(ts, "ts:theta:sol_prev", &th->vec_sol_prev));
190ecc87898SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)th->vec_sol_prev));
191ecc87898SStefano Zampini     PetscCall(TSResizeRetrieveVec(ts, "ts:theta:X0", &th->X0));
19226b5f05dSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)th->X0));
19326b5f05dSStefano Zampini   }
19426b5f05dSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
19526b5f05dSStefano Zampini }
19626b5f05dSStefano Zampini 
197d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_Theta(TS ts)
198d71ae5a4SJacob Faibussowitsch {
199316643e7SJed Brown   TS_Theta *th         = (TS_Theta *)ts->data;
2001566a47fSLisandro Dalcin   PetscInt  rejections = 0;
2014957b756SLisandro Dalcin   PetscBool stageok, accept = PETSC_TRUE;
2021566a47fSLisandro Dalcin   PetscReal next_time_step = ts->time_step;
203316643e7SJed Brown 
204316643e7SJed Brown   PetscFunctionBegin;
2051566a47fSLisandro Dalcin   if (!ts->steprollback) {
2069566063dSJacob Faibussowitsch     if (th->vec_sol_prev) PetscCall(VecCopy(th->X0, th->vec_sol_prev));
2079566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_sol, th->X0));
2081566a47fSLisandro Dalcin   }
2091566a47fSLisandro Dalcin 
2101566a47fSLisandro Dalcin   th->status = TS_STEP_INCOMPLETE;
21199260352SHong Zhang   while (!ts->reason && th->status != TS_STEP_COMPLETE) {
2123e05ceb1SHong Zhang     th->shift      = 1 / (th->Theta * ts->time_step);
2131566a47fSLisandro Dalcin     th->stage_time = ts->ptime + (th->endpoint ? (PetscReal)1 : th->Theta) * ts->time_step;
2149566063dSJacob Faibussowitsch     PetscCall(VecCopy(th->X0, th->X));
21548a46eb9SPierre Jolivet     if (th->extrapolate && !ts->steprestart) PetscCall(VecAXPY(th->X, 1 / th->shift, th->Xdot));
216eb284becSJed Brown     if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */
2179566063dSJacob Faibussowitsch       if (!th->affine) PetscCall(VecDuplicate(ts->vec_sol, &th->affine));
2189566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(th->Xdot));
2199566063dSJacob Faibussowitsch       PetscCall(TSComputeIFunction(ts, ts->ptime, th->X0, th->Xdot, th->affine, PETSC_FALSE));
2209566063dSJacob Faibussowitsch       PetscCall(VecScale(th->affine, (th->Theta - 1) / th->Theta));
221eb284becSJed Brown     }
2229566063dSJacob Faibussowitsch     PetscCall(TSPreStage(ts, th->stage_time));
22382d7ce88SStefano Zampini     PetscCall(TSTheta_SNESSolve(ts, th->endpoint ? th->affine : NULL, th->X));
2249566063dSJacob Faibussowitsch     PetscCall(TSPostStage(ts, th->stage_time, 0, &th->X));
2259566063dSJacob Faibussowitsch     PetscCall(TSAdaptCheckStage(ts->adapt, ts, th->stage_time, th->X, &stageok));
226fecfb714SLisandro Dalcin     if (!stageok) goto reject_step;
227051f2191SLisandro Dalcin 
228b7795fd7SStefano Zampini     if (th->endpoint) {
2299566063dSJacob Faibussowitsch       PetscCall(VecCopy(th->X, ts->vec_sol));
2301566a47fSLisandro Dalcin     } else {
231b7795fd7SStefano Zampini       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X)); /* th->Xdot is needed by TSInterpolate_Theta */
232b7795fd7SStefano Zampini       if (th->Theta == 1.0) PetscCall(VecCopy(th->X, ts->vec_sol));              /* BEULER, stage already checked */
233b7795fd7SStefano Zampini       else {
2349566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vec_sol, ts->time_step, th->Xdot));
235b7795fd7SStefano Zampini         PetscCall(TSAdaptCheckStage(ts->adapt, ts, ts->ptime + ts->time_step, ts->vec_sol, &stageok));
236b7795fd7SStefano Zampini         if (!stageok) {
237b7795fd7SStefano Zampini           PetscCall(VecCopy(th->X0, ts->vec_sol));
238b7795fd7SStefano Zampini           goto reject_step;
2391566a47fSLisandro Dalcin         }
240b7795fd7SStefano Zampini       }
241b7795fd7SStefano Zampini     }
242b7795fd7SStefano Zampini 
243b7795fd7SStefano Zampini     th->status = TS_STEP_PENDING;
2449566063dSJacob Faibussowitsch     PetscCall(TSAdaptChoose(ts->adapt, ts, ts->time_step, NULL, &next_time_step, &accept));
2451566a47fSLisandro Dalcin     th->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
2461566a47fSLisandro Dalcin     if (!accept) {
2479566063dSJacob Faibussowitsch       PetscCall(VecCopy(th->X0, ts->vec_sol));
248be5899b3SLisandro Dalcin       ts->time_step = next_time_step;
249be5899b3SLisandro Dalcin       goto reject_step;
250051f2191SLisandro Dalcin     }
2513b1890cdSShri Abhyankar 
252715f1b00SHong Zhang     if (ts->forward_solve || ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */
2531a352fa8SHong Zhang       th->ptime0     = ts->ptime;
2541a352fa8SHong Zhang       th->time_step0 = ts->time_step;
25517145e75SHong Zhang     }
2562b5a38e1SLisandro Dalcin     ts->ptime += ts->time_step;
257cdbf8f93SLisandro Dalcin     ts->time_step = next_time_step;
258051f2191SLisandro Dalcin     break;
259051f2191SLisandro Dalcin 
260051f2191SLisandro Dalcin   reject_step:
2619371c9d4SSatish Balay     ts->reject++;
2629371c9d4SSatish Balay     accept = PETSC_FALSE;
2631566a47fSLisandro Dalcin     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
264051f2191SLisandro Dalcin       ts->reason = TS_DIVERGED_STEP_REJECTED;
26563a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections));
2663b1890cdSShri Abhyankar     }
2673b1890cdSShri Abhyankar   }
2683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
269316643e7SJed Brown }
270316643e7SJed Brown 
271d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointStepBEuler_Private(TS ts)
272d71ae5a4SJacob Faibussowitsch {
273c9681e5dSHong Zhang   TS_Theta      *th           = (TS_Theta *)ts->data;
274cd4cee2dSHong Zhang   TS             quadts       = ts->quadraturets;
275c9681e5dSHong Zhang   Vec           *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp;
276c9681e5dSHong Zhang   Vec           *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp;
277c9681e5dSHong Zhang   PetscInt       nadj;
2787207e0fdSHong Zhang   Mat            J, Jpre, quadJ = NULL, quadJp = NULL;
279c9681e5dSHong Zhang   KSP            ksp;
280c9681e5dSHong Zhang   PetscScalar   *xarr;
281077c4feaSHong Zhang   TSEquationType eqtype;
282077c4feaSHong Zhang   PetscBool      isexplicitode = PETSC_FALSE;
2831a352fa8SHong Zhang   PetscReal      adjoint_time_step;
284c9681e5dSHong Zhang 
285c9681e5dSHong Zhang   PetscFunctionBegin;
2869566063dSJacob Faibussowitsch   PetscCall(TSGetEquationType(ts, &eqtype));
287077c4feaSHong Zhang   if (eqtype == TS_EQ_ODE_EXPLICIT) {
288077c4feaSHong Zhang     isexplicitode = PETSC_TRUE;
289077c4feaSHong Zhang     VecsDeltaLam  = ts->vecs_sensi;
290077c4feaSHong Zhang     VecsDeltaLam2 = ts->vecs_sensi2;
291077c4feaSHong Zhang   }
292c9681e5dSHong Zhang   th->status = TS_STEP_INCOMPLETE;
2939566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(ts->snes, &ksp));
2949566063dSJacob Faibussowitsch   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
2957207e0fdSHong Zhang   if (quadts) {
2969566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
2979566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
2987207e0fdSHong Zhang   }
299c9681e5dSHong Zhang 
3001a352fa8SHong Zhang   th->stage_time    = ts->ptime;
3011a352fa8SHong Zhang   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
302c9681e5dSHong Zhang 
30333f72c5dSHong Zhang   /* Build RHS for first-order adjoint lambda_{n+1}/h + r_u^T(n+1) */
3041baa6e33SBarry Smith   if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
305cd4cee2dSHong Zhang 
306c9681e5dSHong Zhang   for (nadj = 0; nadj < ts->numcost; nadj++) {
3079566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj]));
3089566063dSJacob Faibussowitsch     PetscCall(VecScale(VecsSensiTemp[nadj], 1. / adjoint_time_step)); /* lambda_{n+1}/h */
309cd4cee2dSHong Zhang     if (quadJ) {
3109566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
3119566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
3129566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col));
3139566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_drdu_col));
3149566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
315c9681e5dSHong Zhang     }
316c9681e5dSHong Zhang   }
317c9681e5dSHong Zhang 
318c9681e5dSHong Zhang   /* Build LHS for first-order adjoint */
319c87ba875SIvan Yashchuk   th->shift = 1. / adjoint_time_step;
3209566063dSJacob Faibussowitsch   PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
3219566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(ksp, J, Jpre));
322c9681e5dSHong Zhang 
323c9681e5dSHong Zhang   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
324c9681e5dSHong Zhang   for (nadj = 0; nadj < ts->numcost; nadj++) {
325c9681e5dSHong Zhang     KSPConvergedReason kspreason;
3269566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj]));
3279566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
328c9681e5dSHong Zhang     if (kspreason < 0) {
329c9681e5dSHong Zhang       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
33063a3b9bcSJacob 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));
331c9681e5dSHong Zhang     }
332c9681e5dSHong Zhang   }
333c9681e5dSHong Zhang 
334c9681e5dSHong Zhang   if (ts->vecs_sensi2) { /* U_{n+1} */
335c9681e5dSHong Zhang     /* Get w1 at t_{n+1} from TLM matrix */
3369566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
3379566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
338c9681e5dSHong Zhang     /* lambda_s^T F_UU w_1 */
3399566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
340c9681e5dSHong Zhang     /* lambda_s^T F_UP w_2 */
3419566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
342c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */
3439566063dSJacob Faibussowitsch       PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj]));
3449566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensi2Temp[nadj], 1. / adjoint_time_step));
3459566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj]));
34648a46eb9SPierre Jolivet       if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj]));
347c9681e5dSHong Zhang     }
348c9681e5dSHong Zhang     /* Solve stage equation LHS X = RHS for second-order adjoint */
349c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
35005c9950eSHong Zhang       KSPConvergedReason kspreason;
3519566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj]));
3529566063dSJacob Faibussowitsch       PetscCall(KSPGetConvergedReason(ksp, &kspreason));
35305c9950eSHong Zhang       if (kspreason < 0) {
35405c9950eSHong Zhang         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
35563a3b9bcSJacob 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));
35605c9950eSHong Zhang       }
357c9681e5dSHong Zhang     }
358c9681e5dSHong Zhang   }
359c9681e5dSHong Zhang 
360c9681e5dSHong Zhang   /* Update sensitivities, and evaluate integrals if there is any */
361077c4feaSHong Zhang   if (!isexplicitode) {
3623e05ceb1SHong Zhang     th->shift = 0.0;
3639566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
3649566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, J, Jpre));
365c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
36633f72c5dSHong Zhang       /* Add f_U \lambda_s to the original RHS */
3679566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensiTemp[nadj], -1.));
3689566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj], VecsSensiTemp[nadj]));
3699566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensiTemp[nadj], -adjoint_time_step));
3709566063dSJacob Faibussowitsch       PetscCall(VecCopy(VecsSensiTemp[nadj], ts->vecs_sensi[nadj]));
371c9681e5dSHong Zhang       if (ts->vecs_sensi2) {
3729566063dSJacob Faibussowitsch         PetscCall(MatMultTransposeAdd(J, VecsDeltaLam2[nadj], VecsSensi2Temp[nadj], VecsSensi2Temp[nadj]));
3739566063dSJacob Faibussowitsch         PetscCall(VecScale(VecsSensi2Temp[nadj], -adjoint_time_step));
3749566063dSJacob Faibussowitsch         PetscCall(VecCopy(VecsSensi2Temp[nadj], ts->vecs_sensi2[nadj]));
375c9681e5dSHong Zhang       }
376c9681e5dSHong Zhang     }
377077c4feaSHong Zhang   }
378c9681e5dSHong Zhang   if (ts->vecs_sensip) {
3799566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(th->Xdot, -1. / adjoint_time_step, 1.0 / adjoint_time_step, 0, th->X0, ts->vec_sol));
3809566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, 1. / adjoint_time_step, ts->Jacp, PETSC_FALSE)); /* get -f_p */
3811baa6e33SBarry Smith     if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
382c9681e5dSHong Zhang     if (ts->vecs_sensi2p) {
383c9681e5dSHong Zhang       /* lambda_s^T F_PU w_1 */
3849566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
38533f72c5dSHong Zhang       /* lambda_s^T F_PP w_2 */
3869566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
387c9681e5dSHong Zhang     }
388cd4cee2dSHong Zhang 
389c9681e5dSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
3909566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
3919566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj]));
392cd4cee2dSHong Zhang       if (quadJp) {
3939566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
3949566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
3959566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col));
3969566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_drdp_col));
3979566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
39833f72c5dSHong Zhang       }
399c9681e5dSHong Zhang       if (ts->vecs_sensi2p) {
4009566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
4019566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, VecsDeltaMu2[nadj]));
40248a46eb9SPierre Jolivet         if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpu[nadj]));
40348a46eb9SPierre Jolivet         if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpp[nadj]));
404c9681e5dSHong Zhang       }
405c9681e5dSHong Zhang     }
406c9681e5dSHong Zhang   }
407c9681e5dSHong Zhang 
408c9681e5dSHong Zhang   if (ts->vecs_sensi2) {
4099566063dSJacob Faibussowitsch     PetscCall(VecResetArray(ts->vec_sensip_col));
4109566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
411c9681e5dSHong Zhang   }
412c9681e5dSHong Zhang   th->status = TS_STEP_COMPLETE;
4133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
414c9681e5dSHong Zhang }
415c9681e5dSHong Zhang 
416d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointStep_Theta(TS ts)
417d71ae5a4SJacob Faibussowitsch {
4182ca6e920SHong Zhang   TS_Theta    *th           = (TS_Theta *)ts->data;
419cd4cee2dSHong Zhang   TS           quadts       = ts->quadraturets;
420b5e0532dSHong Zhang   Vec         *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp;
421b5b4017aSHong Zhang   Vec         *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp;
4222ca6e920SHong Zhang   PetscInt     nadj;
4237207e0fdSHong Zhang   Mat          J, Jpre, quadJ = NULL, quadJp = NULL;
4242ca6e920SHong Zhang   KSP          ksp;
425b5b4017aSHong Zhang   PetscScalar *xarr;
4261a352fa8SHong Zhang   PetscReal    adjoint_time_step;
427da81f932SPierre 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) */
4282ca6e920SHong Zhang 
4292ca6e920SHong Zhang   PetscFunctionBegin;
430c9681e5dSHong Zhang   if (th->Theta == 1.) {
4319566063dSJacob Faibussowitsch     PetscCall(TSAdjointStepBEuler_Private(ts));
4323ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
433c9681e5dSHong Zhang   }
4342ca6e920SHong Zhang   th->status = TS_STEP_INCOMPLETE;
4359566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(ts->snes, &ksp));
4369566063dSJacob Faibussowitsch   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
4377207e0fdSHong Zhang   if (quadts) {
4389566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
4399566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
4407207e0fdSHong Zhang   }
441b5e0532dSHong Zhang   /* If endpoint=1, th->ptime and th->X0 will be used; if endpoint=0, th->stage_time and th->X will be used. */
4421a352fa8SHong Zhang   th->stage_time    = th->endpoint ? ts->ptime : (ts->ptime + (1. - th->Theta) * ts->time_step);
4431a352fa8SHong Zhang   adjoint_ptime     = ts->ptime + ts->time_step;
4441a352fa8SHong Zhang   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
4452ca6e920SHong Zhang 
44682ad9101SHong Zhang   if (!th->endpoint) {
4475072d23cSHong Zhang     /* recover th->X0 using vec_sol and the stage value th->X */
4489566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(th->X0, 1.0 / (1.0 - th->Theta), th->Theta / (th->Theta - 1.0), 0, th->X, ts->vec_sol));
44982ad9101SHong Zhang   }
45082ad9101SHong Zhang 
451b5b4017aSHong Zhang   /* Build RHS for first-order adjoint */
45233f72c5dSHong Zhang   /* Cost function has an integral term */
4537207e0fdSHong Zhang   if (quadts) {
45405755b9cSHong Zhang     if (th->endpoint) {
4559566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
45605755b9cSHong Zhang     } else {
4579566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
45805755b9cSHong Zhang     }
4597207e0fdSHong Zhang   }
46033f72c5dSHong Zhang 
461abc2977eSBarry Smith   for (nadj = 0; nadj < ts->numcost; nadj++) {
4629566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj]));
4639566063dSJacob Faibussowitsch     PetscCall(VecScale(VecsSensiTemp[nadj], 1. / (th->Theta * adjoint_time_step)));
464cd4cee2dSHong Zhang     if (quadJ) {
4659566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
4669566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
4679566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col));
4689566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_drdu_col));
4699566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
47036eaed60SHong Zhang     }
4712ca6e920SHong Zhang   }
4723c54f92cSHong Zhang 
473b5b4017aSHong Zhang   /* Build LHS for first-order adjoint */
4741a352fa8SHong Zhang   th->shift = 1. / (th->Theta * adjoint_time_step);
4753c54f92cSHong Zhang   if (th->endpoint) {
4769566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
4773c54f92cSHong Zhang   } else {
4789566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre));
4793c54f92cSHong Zhang   }
4809566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(ksp, J, Jpre));
4812ca6e920SHong Zhang 
482b5b4017aSHong Zhang   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
483abc2977eSBarry Smith   for (nadj = 0; nadj < ts->numcost; nadj++) {
4841d14d03bSHong Zhang     KSPConvergedReason kspreason;
4859566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj]));
4869566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
4871d14d03bSHong Zhang     if (kspreason < 0) {
4881d14d03bSHong Zhang       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
48963a3b9bcSJacob 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));
4901d14d03bSHong Zhang     }
4912ca6e920SHong Zhang   }
4923c54f92cSHong Zhang 
4931d14d03bSHong Zhang   /* Second-order adjoint */
494b5b4017aSHong Zhang   if (ts->vecs_sensi2) { /* U_{n+1} */
4953c633725SBarry Smith     PetscCheck(th->endpoint, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Operation not implemented in TS_Theta");
496b5b4017aSHong Zhang     /* Get w1 at t_{n+1} from TLM matrix */
4979566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
4989566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
499b5b4017aSHong Zhang     /* lambda_s^T F_UU w_1 */
5009566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
5019566063dSJacob Faibussowitsch     PetscCall(VecResetArray(ts->vec_sensip_col));
5029566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
503b5b4017aSHong Zhang     /* lambda_s^T F_UP w_2 */
5049566063dSJacob Faibussowitsch     PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
505b5b4017aSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */
5069566063dSJacob Faibussowitsch       PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj]));
5079566063dSJacob Faibussowitsch       PetscCall(VecScale(VecsSensi2Temp[nadj], th->shift));
5089566063dSJacob Faibussowitsch       PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj]));
50948a46eb9SPierre Jolivet       if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj]));
510b5b4017aSHong Zhang     }
511b5b4017aSHong Zhang     /* Solve stage equation LHS X = RHS for second-order adjoint */
512b5b4017aSHong Zhang     for (nadj = 0; nadj < ts->numcost; nadj++) {
5131d14d03bSHong Zhang       KSPConvergedReason kspreason;
5149566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj]));
5159566063dSJacob Faibussowitsch       PetscCall(KSPGetConvergedReason(ksp, &kspreason));
5161d14d03bSHong Zhang       if (kspreason < 0) {
5171d14d03bSHong Zhang         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
51863a3b9bcSJacob 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));
5191d14d03bSHong Zhang       }
520b5b4017aSHong Zhang     }
521b5b4017aSHong Zhang   }
522b5b4017aSHong Zhang 
52336eaed60SHong Zhang   /* Update sensitivities, and evaluate integrals if there is any */
5241d14d03bSHong Zhang   if (th->endpoint) { /* two-stage Theta methods with th->Theta!=1, th->Theta==1 leads to BEuler */
5251a352fa8SHong Zhang     th->shift      = 1. / ((th->Theta - 1.) * adjoint_time_step);
5261a352fa8SHong Zhang     th->stage_time = adjoint_ptime;
5279566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, th->X0, J, Jpre));
5289566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, J, Jpre));
52933f72c5dSHong Zhang     /* R_U at t_n */
5301baa6e33SBarry Smith     if (quadts) PetscCall(TSComputeRHSJacobian(quadts, adjoint_ptime, th->X0, quadJ, NULL));
531abc2977eSBarry Smith     for (nadj = 0; nadj < ts->numcost; nadj++) {
5329566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], ts->vecs_sensi[nadj]));
533cd4cee2dSHong Zhang       if (quadJ) {
5349566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
5359566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
5369566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi[nadj], -1., ts->vec_drdu_col));
5379566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_drdu_col));
5389566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
539b5b4017aSHong Zhang       }
5409566063dSJacob Faibussowitsch       PetscCall(VecScale(ts->vecs_sensi[nadj], 1. / th->shift));
541b5b4017aSHong Zhang     }
5421d14d03bSHong Zhang 
5431d14d03bSHong Zhang     /* Second-order adjoint */
5441d14d03bSHong Zhang     if (ts->vecs_sensi2) { /* U_n */
545b5b4017aSHong Zhang       /* Get w1 at t_n from TLM matrix */
5469566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr));
5479566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
548b5b4017aSHong Zhang       /* lambda_s^T F_UU w_1 */
5499566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionUU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
5509566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_sensip_col));
5519566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr));
552b5b4017aSHong Zhang       /* lambda_s^T F_UU w_2 */
5539566063dSJacob Faibussowitsch       PetscCall(TSComputeIHessianProductFunctionUP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
554b5b4017aSHong Zhang       for (nadj = 0; nadj < ts->numcost; nadj++) {
55533f72c5dSHong 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  */
5569566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(J, VecsDeltaLam2[nadj], ts->vecs_sensi2[nadj]));
5579566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fuu[nadj]));
55848a46eb9SPierre Jolivet         if (ts->vecs_fup) PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fup[nadj]));
5599566063dSJacob Faibussowitsch         PetscCall(VecScale(ts->vecs_sensi2[nadj], 1. / th->shift));
560b5b4017aSHong Zhang       }
561b5e0532dSHong Zhang     }
5623fd52205SHong Zhang 
563c586f2e8SHong Zhang     th->stage_time = ts->ptime; /* recover the old value */
564c586f2e8SHong Zhang 
5653fd52205SHong Zhang     if (ts->vecs_sensip) { /* sensitivities wrt parameters */
566b5b4017aSHong Zhang       /* U_{n+1} */
56782ad9101SHong Zhang       th->shift = 1.0 / (adjoint_time_step * th->Theta);
5689566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol));
5699566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, -1. / (th->Theta * adjoint_time_step), ts->Jacp, PETSC_FALSE));
5701baa6e33SBarry Smith       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
571abc2977eSBarry Smith       for (nadj = 0; nadj < ts->numcost; nadj++) {
5729566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
5739566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu[nadj]));
5743b711c3fSHong Zhang         if (quadJp) {
5759566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
5769566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
5779566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * th->Theta, ts->vec_drdp_col));
5789566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_drdp_col));
5799566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
5803b711c3fSHong Zhang         }
5813fd52205SHong Zhang       }
58233f72c5dSHong Zhang       if (ts->vecs_sensi2p) { /* second-order */
58333f72c5dSHong Zhang         /* Get w1 at t_{n+1} from TLM matrix */
5849566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
5859566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
586b5b4017aSHong Zhang         /* lambda_s^T F_PU w_1 */
5879566063dSJacob Faibussowitsch         PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
5889566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_sensip_col));
5899566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
59033f72c5dSHong Zhang 
591b5b4017aSHong Zhang         /* lambda_s^T F_PP w_2 */
5929566063dSJacob Faibussowitsch         PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
593b5b4017aSHong Zhang         for (nadj = 0; nadj < ts->numcost; nadj++) {
59433f72c5dSHong 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)  */
5959566063dSJacob Faibussowitsch           PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
5969566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu2[nadj]));
59748a46eb9SPierre Jolivet           if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpu[nadj]));
59848a46eb9SPierre Jolivet           if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpp[nadj]));
599b5b4017aSHong Zhang         }
600b5b4017aSHong Zhang       }
601b5b4017aSHong Zhang 
602b5b4017aSHong Zhang       /* U_s */
6039566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(th->Xdot));
6049566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, adjoint_ptime, th->X0, th->Xdot, 1. / ((th->Theta - 1.0) * adjoint_time_step), ts->Jacp, PETSC_FALSE));
6051baa6e33SBarry Smith       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, adjoint_ptime, th->X0, quadJp));
606abc2977eSBarry Smith       for (nadj = 0; nadj < ts->numcost; nadj++) {
6079566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
6089566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu[nadj]));
6093b711c3fSHong Zhang         if (quadJp) {
6109566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
6119566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
6129566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * (1.0 - th->Theta), ts->vec_drdp_col));
6139566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_drdp_col));
6149566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
6153b711c3fSHong Zhang         }
61633f72c5dSHong Zhang         if (ts->vecs_sensi2p) { /* second-order */
61733f72c5dSHong Zhang           /* Get w1 at t_n from TLM matrix */
6189566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr));
6199566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
620b5b4017aSHong Zhang           /* lambda_s^T F_PU w_1 */
6219566063dSJacob Faibussowitsch           PetscCall(TSComputeIHessianProductFunctionPU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
6229566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_sensip_col));
6239566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr));
624b5b4017aSHong Zhang           /* lambda_s^T F_PP w_2 */
6259566063dSJacob Faibussowitsch           PetscCall(TSComputeIHessianProductFunctionPP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
626b5b4017aSHong Zhang           for (nadj = 0; nadj < ts->numcost; nadj++) {
62733f72c5dSHong 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) */
6289566063dSJacob Faibussowitsch             PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
6299566063dSJacob Faibussowitsch             PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu2[nadj]));
63048a46eb9SPierre Jolivet             if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpu[nadj]));
63148a46eb9SPierre Jolivet             if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpp[nadj]));
63236eaed60SHong Zhang           }
63336eaed60SHong Zhang         }
6343fd52205SHong Zhang       }
635b5e0532dSHong Zhang     }
6363fd52205SHong Zhang   } else { /* one-stage case */
6373e05ceb1SHong Zhang     th->shift = 0.0;
6389566063dSJacob Faibussowitsch     PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre)); /* get -f_y */
6399566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, J, Jpre));
6401baa6e33SBarry Smith     if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
641abc2977eSBarry Smith     for (nadj = 0; nadj < ts->numcost; nadj++) {
6429566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj]));
6439566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ts->vecs_sensi[nadj], -adjoint_time_step, VecsSensiTemp[nadj]));
644cd4cee2dSHong Zhang       if (quadJ) {
6459566063dSJacob Faibussowitsch         PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
6469566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
6479566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensi[nadj], adjoint_time_step, ts->vec_drdu_col));
6489566063dSJacob Faibussowitsch         PetscCall(VecResetArray(ts->vec_drdu_col));
6499566063dSJacob Faibussowitsch         PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
65036eaed60SHong Zhang       }
6512ca6e920SHong Zhang     }
6523fd52205SHong Zhang     if (ts->vecs_sensip) {
65382ad9101SHong Zhang       th->shift = 1.0 / (adjoint_time_step * th->Theta);
6549566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
6559566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
6561baa6e33SBarry Smith       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp));
657abc2977eSBarry Smith       for (nadj = 0; nadj < ts->numcost; nadj++) {
6589566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
6599566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj]));
660cd4cee2dSHong Zhang         if (quadJp) {
6619566063dSJacob Faibussowitsch           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
6629566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
6639566063dSJacob Faibussowitsch           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col));
6649566063dSJacob Faibussowitsch           PetscCall(VecResetArray(ts->vec_drdp_col));
6659566063dSJacob Faibussowitsch           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
66636eaed60SHong Zhang         }
66736eaed60SHong Zhang       }
6683fd52205SHong Zhang     }
6692ca6e920SHong Zhang   }
6702ca6e920SHong Zhang 
6712ca6e920SHong Zhang   th->status = TS_STEP_COMPLETE;
6723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6732ca6e920SHong Zhang }
6742ca6e920SHong Zhang 
675d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_Theta(TS ts, PetscReal t, Vec X)
676d71ae5a4SJacob Faibussowitsch {
677cd652676SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
678be5899b3SLisandro Dalcin   PetscReal dt = t - ts->ptime;
679cd652676SJed Brown 
680cd652676SJed Brown   PetscFunctionBegin;
6819566063dSJacob Faibussowitsch   PetscCall(VecCopy(ts->vec_sol, th->X));
682be5899b3SLisandro Dalcin   if (th->endpoint) dt *= th->Theta;
6839566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(X, dt, th->Xdot, th->X));
6843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
685cd652676SJed Brown }
686cd652676SJed Brown 
687d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEvaluateWLTE_Theta(TS ts, NormType wnormtype, PetscInt *order, PetscReal *wlte)
688d71ae5a4SJacob Faibussowitsch {
6891566a47fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
6901566a47fSLisandro Dalcin   Vec       X  = ts->vec_sol;      /* X = solution */
6911566a47fSLisandro Dalcin   Vec       Y  = th->vec_lte_work; /* Y = X + LTE  */
6927453f775SEmil Constantinescu   PetscReal wltea, wlter;
6931566a47fSLisandro Dalcin 
6941566a47fSLisandro Dalcin   PetscFunctionBegin;
6959371c9d4SSatish Balay   if (!th->vec_sol_prev) {
6969371c9d4SSatish Balay     *wlte = -1;
6973ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6989371c9d4SSatish Balay   }
6991566a47fSLisandro Dalcin   /* Cannot compute LTE in first step or in restart after event */
7009371c9d4SSatish Balay   if (ts->steprestart) {
7019371c9d4SSatish Balay     *wlte = -1;
7023ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7039371c9d4SSatish Balay   }
7041566a47fSLisandro Dalcin   /* Compute LTE using backward differences with non-constant time step */
705fecfb714SLisandro Dalcin   {
706be5899b3SLisandro Dalcin     PetscReal   h = ts->time_step, h_prev = ts->ptime - ts->ptime_prev;
707be5899b3SLisandro Dalcin     PetscReal   a = 1 + h_prev / h;
7089371c9d4SSatish Balay     PetscScalar scal[3];
7099371c9d4SSatish Balay     Vec         vecs[3];
710225f7d0bSStefano Zampini     scal[0] = -1 / a;
711225f7d0bSStefano Zampini     scal[1] = +1 / (a - 1);
712225f7d0bSStefano Zampini     scal[2] = -1 / (a * (a - 1));
7139371c9d4SSatish Balay     vecs[0] = X;
7149371c9d4SSatish Balay     vecs[1] = th->X0;
7159371c9d4SSatish Balay     vecs[2] = th->vec_sol_prev;
7169566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, Y));
7179566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(Y, 3, scal, vecs));
7189566063dSJacob Faibussowitsch     PetscCall(TSErrorWeightedNorm(ts, X, Y, wnormtype, wlte, &wltea, &wlter));
7191566a47fSLisandro Dalcin   }
7201566a47fSLisandro Dalcin   if (order) *order = 2;
7213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7221566a47fSLisandro Dalcin }
7231566a47fSLisandro Dalcin 
724d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSRollBack_Theta(TS ts)
725d71ae5a4SJacob Faibussowitsch {
7261566a47fSLisandro Dalcin   TS_Theta *th     = (TS_Theta *)ts->data;
7277207e0fdSHong Zhang   TS        quadts = ts->quadraturets;
7281566a47fSLisandro Dalcin 
7291566a47fSLisandro Dalcin   PetscFunctionBegin;
73048a46eb9SPierre Jolivet   if (quadts && ts->costintegralfwd) PetscCall(VecCopy(th->VecCostIntegral0, quadts->vec_sol));
731715f1b00SHong Zhang   th->status = TS_STEP_INCOMPLETE;
7321baa6e33SBarry Smith   if (ts->mat_sensip) PetscCall(MatCopy(th->MatFwdSensip0, ts->mat_sensip, SAME_NONZERO_PATTERN));
73348a46eb9SPierre Jolivet   if (quadts && quadts->mat_sensip) PetscCall(MatCopy(th->MatIntegralSensip0, quadts->mat_sensip, SAME_NONZERO_PATTERN));
7343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
735715f1b00SHong Zhang }
736715f1b00SHong Zhang 
737d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardStep_Theta(TS ts)
738d71ae5a4SJacob Faibussowitsch {
739715f1b00SHong Zhang   TS_Theta    *th                   = (TS_Theta *)ts->data;
740cd4cee2dSHong Zhang   TS           quadts               = ts->quadraturets;
74113b1b0ffSHong Zhang   Mat          MatDeltaFwdSensip    = th->MatDeltaFwdSensip;
742b5b4017aSHong Zhang   Vec          VecDeltaFwdSensipCol = th->VecDeltaFwdSensipCol;
7437207e0fdSHong Zhang   PetscInt     ntlm;
744715f1b00SHong Zhang   KSP          ksp;
7457207e0fdSHong Zhang   Mat          J, Jpre, quadJ = NULL, quadJp = NULL;
74613b1b0ffSHong Zhang   PetscScalar *barr, *xarr;
7471a352fa8SHong Zhang   PetscReal    previous_shift;
748715f1b00SHong Zhang 
749715f1b00SHong Zhang   PetscFunctionBegin;
7501a352fa8SHong Zhang   previous_shift = th->shift;
7519566063dSJacob Faibussowitsch   PetscCall(MatCopy(ts->mat_sensip, th->MatFwdSensip0, SAME_NONZERO_PATTERN));
75213b1b0ffSHong Zhang 
75348a46eb9SPierre Jolivet   if (quadts && quadts->mat_sensip) PetscCall(MatCopy(quadts->mat_sensip, th->MatIntegralSensip0, SAME_NONZERO_PATTERN));
7549566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(ts->snes, &ksp));
7559566063dSJacob Faibussowitsch   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
7567207e0fdSHong Zhang   if (quadts) {
7579566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
7589566063dSJacob Faibussowitsch     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
7597207e0fdSHong Zhang   }
760715f1b00SHong Zhang 
761715f1b00SHong Zhang   /* Build RHS */
762715f1b00SHong Zhang   if (th->endpoint) { /* 2-stage method*/
7631a352fa8SHong Zhang     th->shift = 1. / ((th->Theta - 1.) * th->time_step0);
7649566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->ptime0, th->X0, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
765fb842aefSJose E. Roman     PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DETERMINE, &MatDeltaFwdSensip));
7669566063dSJacob Faibussowitsch     PetscCall(MatScale(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta));
767715f1b00SHong Zhang 
768022c081aSHong Zhang     /* Add the f_p forcing terms */
7690e11c21fSHong Zhang     if (ts->Jacp) {
7709566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(th->Xdot));
7719566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->ptime0, th->X0, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
7729566063dSJacob Faibussowitsch       PetscCall(MatAXPY(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta, ts->Jacp, SUBSET_NONZERO_PATTERN));
77382ad9101SHong Zhang       th->shift = previous_shift;
7749566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol));
7759566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
7769566063dSJacob Faibussowitsch       PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN));
7770e11c21fSHong Zhang     }
778715f1b00SHong Zhang   } else { /* 1-stage method */
7793e05ceb1SHong Zhang     th->shift = 0.0;
7809566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
781fb842aefSJose E. Roman     PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DETERMINE, &MatDeltaFwdSensip));
7829566063dSJacob Faibussowitsch     PetscCall(MatScale(MatDeltaFwdSensip, -1.));
78313b1b0ffSHong Zhang 
784022c081aSHong Zhang     /* Add the f_p forcing terms */
7850e11c21fSHong Zhang     if (ts->Jacp) {
78682ad9101SHong Zhang       th->shift = previous_shift;
7879566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
7889566063dSJacob Faibussowitsch       PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
7899566063dSJacob Faibussowitsch       PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN));
790715f1b00SHong Zhang     }
7910e11c21fSHong Zhang   }
792715f1b00SHong Zhang 
793715f1b00SHong Zhang   /* Build LHS */
7941a352fa8SHong Zhang   th->shift = previous_shift; /* recover the previous shift used in TSStep_Theta() */
795715f1b00SHong Zhang   if (th->endpoint) {
7969566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
797715f1b00SHong Zhang   } else {
7989566063dSJacob Faibussowitsch     PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
799715f1b00SHong Zhang   }
8009566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(ksp, J, Jpre));
801715f1b00SHong Zhang 
802715f1b00SHong Zhang   /*
803715f1b00SHong Zhang     Evaluate the first stage of integral gradients with the 2-stage method:
804c9ad9de0SHong Zhang     drdu|t_n*S(t_n) + drdp|t_n
805715f1b00SHong Zhang     This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1})
806715f1b00SHong Zhang   */
807715f1b00SHong Zhang   if (th->endpoint) { /* 2-stage method only */
8087207e0fdSHong Zhang     if (quadts && quadts->mat_sensip) {
8099566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->ptime0, th->X0, quadJ, NULL));
8109566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobianP(quadts, th->ptime0, th->X0, quadJp));
811fb842aefSJose E. Roman       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DETERMINE, &th->MatIntegralSensipTemp));
8129566063dSJacob Faibussowitsch       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
8139566063dSJacob Faibussowitsch       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * (1. - th->Theta), th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
814715f1b00SHong Zhang     }
815715f1b00SHong Zhang   }
816715f1b00SHong Zhang 
817715f1b00SHong Zhang   /* Solve the tangent linear equation for forward sensitivities to parameters */
818022c081aSHong Zhang   for (ntlm = 0; ntlm < th->num_tlm; ntlm++) {
819b5b4017aSHong Zhang     KSPConvergedReason kspreason;
8209566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumn(MatDeltaFwdSensip, ntlm, &barr));
8219566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(VecDeltaFwdSensipCol, barr));
822715f1b00SHong Zhang     if (th->endpoint) {
8239566063dSJacob Faibussowitsch       PetscCall(MatDenseGetColumn(ts->mat_sensip, ntlm, &xarr));
8249566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
8259566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, ts->vec_sensip_col));
8269566063dSJacob Faibussowitsch       PetscCall(VecResetArray(ts->vec_sensip_col));
8279566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
828715f1b00SHong Zhang     } else {
8299566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, VecDeltaFwdSensipCol));
830715f1b00SHong Zhang     }
8319566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
832b5b4017aSHong Zhang     if (kspreason < 0) {
833b5b4017aSHong Zhang       ts->reason = TSFORWARD_DIVERGED_LINEAR_SOLVE;
83463a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th tangent linear solve, linear solve fails, stopping tangent linear solve\n", ts->steps, ntlm));
835b5b4017aSHong Zhang     }
8369566063dSJacob Faibussowitsch     PetscCall(VecResetArray(VecDeltaFwdSensipCol));
8379566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumn(MatDeltaFwdSensip, &barr));
838715f1b00SHong Zhang   }
839715f1b00SHong Zhang 
84013b1b0ffSHong Zhang   /*
84113b1b0ffSHong Zhang     Evaluate the second stage of integral gradients with the 2-stage method:
842c9ad9de0SHong Zhang     drdu|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1}
84313b1b0ffSHong Zhang   */
8447207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
84513b1b0ffSHong Zhang     if (!th->endpoint) {
8469566063dSJacob Faibussowitsch       PetscCall(MatAXPY(ts->mat_sensip, 1, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); /* stage sensitivity */
8479566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
8489566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp));
849fb842aefSJose E. Roman       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DETERMINE, &th->MatIntegralSensipTemp));
8509566063dSJacob Faibussowitsch       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
8519566063dSJacob Faibussowitsch       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
8529566063dSJacob Faibussowitsch       PetscCall(MatAXPY(ts->mat_sensip, (1. - th->Theta) / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN));
85313b1b0ffSHong Zhang     } else {
8549566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
8559566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
856fb842aefSJose E. Roman       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DETERMINE, &th->MatIntegralSensipTemp));
8579566063dSJacob Faibussowitsch       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
8589566063dSJacob Faibussowitsch       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * th->Theta, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
85913b1b0ffSHong Zhang     }
86013b1b0ffSHong Zhang   } else {
86148a46eb9SPierre Jolivet     if (!th->endpoint) PetscCall(MatAXPY(ts->mat_sensip, 1. / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN));
862715f1b00SHong Zhang   }
8633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8641566a47fSLisandro Dalcin }
8651566a47fSLisandro Dalcin 
866d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardGetStages_Theta(TS ts, PetscInt *ns, Mat *stagesensip[])
867d71ae5a4SJacob Faibussowitsch {
8686affb6f8SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
8696affb6f8SHong Zhang 
8706affb6f8SHong Zhang   PetscFunctionBegin;
8717409eceaSHong Zhang   if (ns) {
8727409eceaSHong Zhang     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
8737409eceaSHong Zhang     else *ns = 2;                                   /* endpoint form */
8747409eceaSHong Zhang   }
8755072d23cSHong Zhang   if (stagesensip) {
876cc4f23bcSHong Zhang     if (!th->endpoint && th->Theta != 1.0) {
8777409eceaSHong Zhang       th->MatFwdStages[0] = th->MatDeltaFwdSensip;
878cc4f23bcSHong Zhang     } else {
879cc4f23bcSHong Zhang       th->MatFwdStages[0] = th->MatFwdSensip0;
880cc4f23bcSHong Zhang       th->MatFwdStages[1] = ts->mat_sensip; /* stiffly accurate */
881cc4f23bcSHong Zhang     }
882cc4f23bcSHong Zhang     *stagesensip = th->MatFwdStages;
8835072d23cSHong Zhang   }
8843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8856affb6f8SHong Zhang }
8866affb6f8SHong Zhang 
887316643e7SJed Brown /*------------------------------------------------------------*/
888d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_Theta(TS ts)
889d71ae5a4SJacob Faibussowitsch {
890316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
891316643e7SJed Brown 
892316643e7SJed Brown   PetscFunctionBegin;
8939566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->X));
8949566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->Xdot));
8959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->X0));
8969566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->affine));
8971566a47fSLisandro Dalcin 
8989566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->vec_sol_prev));
8999566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->vec_lte_work));
9001566a47fSLisandro Dalcin 
9019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->VecCostIntegral0));
9023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
903277b19d0SLisandro Dalcin }
904277b19d0SLisandro Dalcin 
905d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointReset_Theta(TS ts)
906d71ae5a4SJacob Faibussowitsch {
907ece46509SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
908ece46509SHong Zhang 
909ece46509SHong Zhang   PetscFunctionBegin;
9109566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam));
9119566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu));
9129566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam2));
9139566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu2));
9149566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensiTemp));
9159566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensi2Temp));
9163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
917ece46509SHong Zhang }
918ece46509SHong Zhang 
919d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_Theta(TS ts)
920d71ae5a4SJacob Faibussowitsch {
921277b19d0SLisandro Dalcin   PetscFunctionBegin;
9229566063dSJacob Faibussowitsch   PetscCall(TSReset_Theta(ts));
923b3a6b972SJed Brown   if (ts->dm) {
9249566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts));
9259566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts));
926b3a6b972SJed Brown   }
9279566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
9289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", NULL));
9299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", NULL));
9309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", NULL));
9319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", NULL));
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933316643e7SJed Brown }
934316643e7SJed Brown 
935316643e7SJed Brown /*
936316643e7SJed Brown   This defines the nonlinear equation that is to be solved with SNES
9372b5a38e1SLisandro Dalcin   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
9380fd10508SMatthew Knepley 
9390fd10508SMatthew Knepley   Note that U here is the stage argument. This means that U = U_{n+1} only if endpoint = true,
9400fd10508SMatthew Knepley   otherwise U = theta U_{n+1} + (1 - theta) U0, which for the case of implicit midpoint is
9410fd10508SMatthew Knepley   U = (U_{n+1} + U0)/2
942316643e7SJed Brown */
943d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_Theta(SNES snes, Vec x, Vec y, TS ts)
944d71ae5a4SJacob Faibussowitsch {
945316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
9467445fe48SJed Brown   Vec       X0, Xdot;
9477445fe48SJed Brown   DM        dm, dmsave;
9483e05ceb1SHong Zhang   PetscReal shift = th->shift;
949316643e7SJed Brown 
950316643e7SJed Brown   PetscFunctionBegin;
9519566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
9525a3a76d0SJed Brown   /* When using the endpoint variant, this is actually 1/Theta * Xdot */
9539566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot));
954494ce9fcSHong Zhang   if (x != X0) {
9559566063dSJacob Faibussowitsch     PetscCall(VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x));
956494ce9fcSHong Zhang   } else {
9579566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(Xdot));
958494ce9fcSHong Zhang   }
9597445fe48SJed Brown   /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
9607445fe48SJed Brown   dmsave = ts->dm;
9617445fe48SJed Brown   ts->dm = dm;
9629566063dSJacob Faibussowitsch   PetscCall(TSComputeIFunction(ts, th->stage_time, x, Xdot, y, PETSC_FALSE));
9637445fe48SJed Brown   ts->dm = dmsave;
9649566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot));
9653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
966316643e7SJed Brown }
967316643e7SJed Brown 
968d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes, Vec x, Mat A, Mat B, TS ts)
969d71ae5a4SJacob Faibussowitsch {
970316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
9717445fe48SJed Brown   Vec       Xdot;
9727445fe48SJed Brown   DM        dm, dmsave;
9733e05ceb1SHong Zhang   PetscReal shift = th->shift;
974316643e7SJed Brown 
975316643e7SJed Brown   PetscFunctionBegin;
9769566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
977be5899b3SLisandro Dalcin   /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */
9789566063dSJacob Faibussowitsch   PetscCall(TSThetaGetX0AndXdot(ts, dm, NULL, &Xdot));
9797445fe48SJed Brown 
9807445fe48SJed Brown   dmsave = ts->dm;
9817445fe48SJed Brown   ts->dm = dm;
9829566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, th->stage_time, x, Xdot, shift, A, B, PETSC_FALSE));
9837445fe48SJed Brown   ts->dm = dmsave;
9849566063dSJacob Faibussowitsch   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, NULL, &Xdot));
9853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
986316643e7SJed Brown }
987316643e7SJed Brown 
988d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardSetUp_Theta(TS ts)
989d71ae5a4SJacob Faibussowitsch {
990715f1b00SHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
9917207e0fdSHong Zhang   TS        quadts = ts->quadraturets;
992715f1b00SHong Zhang 
993715f1b00SHong Zhang   PetscFunctionBegin;
994022c081aSHong Zhang   /* combine sensitivities to parameters and sensitivities to initial values into one array */
99513b1b0ffSHong Zhang   th->num_tlm = ts->num_parameters;
9969566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatDeltaFwdSensip));
9977207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
9989566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensipTemp));
9999566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensip0));
1000715f1b00SHong Zhang   }
10016f92202bSHong Zhang   /* backup sensitivity results for roll-backs */
10029566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatFwdSensip0));
100313b1b0ffSHong Zhang 
10049566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &th->VecDeltaFwdSensipCol));
10053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1006715f1b00SHong Zhang }
1007715f1b00SHong Zhang 
1008d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardReset_Theta(TS ts)
1009d71ae5a4SJacob Faibussowitsch {
10107adebddeSHong Zhang   TS_Theta *th     = (TS_Theta *)ts->data;
10117207e0fdSHong Zhang   TS        quadts = ts->quadraturets;
10127adebddeSHong Zhang 
10137adebddeSHong Zhang   PetscFunctionBegin;
10147207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
10159566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&th->MatIntegralSensipTemp));
10169566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&th->MatIntegralSensip0));
10177adebddeSHong Zhang   }
10189566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&th->VecDeltaFwdSensipCol));
10199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&th->MatDeltaFwdSensip));
10209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&th->MatFwdSensip0));
10213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10227adebddeSHong Zhang }
10237adebddeSHong Zhang 
1024d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_Theta(TS ts)
1025d71ae5a4SJacob Faibussowitsch {
1026316643e7SJed Brown   TS_Theta *th     = (TS_Theta *)ts->data;
1027cd4cee2dSHong Zhang   TS        quadts = ts->quadraturets;
10282ffb9264SLisandro Dalcin   PetscBool match;
1029316643e7SJed Brown 
1030316643e7SJed Brown   PetscFunctionBegin;
1031cd4cee2dSHong Zhang   if (!th->VecCostIntegral0 && quadts && ts->costintegralfwd) { /* back up cost integral */
10329566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(quadts->vec_sol, &th->VecCostIntegral0));
1033b1cb36f3SHong Zhang   }
103448a46eb9SPierre Jolivet   if (!th->X) PetscCall(VecDuplicate(ts->vec_sol, &th->X));
103548a46eb9SPierre Jolivet   if (!th->Xdot) PetscCall(VecDuplicate(ts->vec_sol, &th->Xdot));
103648a46eb9SPierre Jolivet   if (!th->X0) PetscCall(VecDuplicate(ts->vec_sol, &th->X0));
103748a46eb9SPierre Jolivet   if (th->endpoint) PetscCall(VecDuplicate(ts->vec_sol, &th->affine));
10383b1890cdSShri Abhyankar 
10391566a47fSLisandro Dalcin   th->order = (th->Theta == 0.5) ? 2 : 1;
104020d49056SMatthew G. Knepley   th->shift = 1 / (th->Theta * ts->time_step);
10411566a47fSLisandro Dalcin 
10429566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &ts->dm));
10439566063dSJacob Faibussowitsch   PetscCall(DMCoarsenHookAdd(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts));
10449566063dSJacob Faibussowitsch   PetscCall(DMSubDomainHookAdd(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts));
10451566a47fSLisandro Dalcin 
10469566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts, &ts->adapt));
10479566063dSJacob Faibussowitsch   PetscCall(TSAdaptCandidatesClear(ts->adapt));
10489566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &match));
10492ffb9264SLisandro Dalcin   if (!match) {
1050ecc87898SStefano Zampini     if (!th->vec_sol_prev) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_sol_prev));
1051ecc87898SStefano Zampini     if (!th->vec_lte_work) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_lte_work));
10523b1890cdSShri Abhyankar   }
10539566063dSJacob Faibussowitsch   PetscCall(TSGetSNES(ts, &ts->snes));
1054cc4f23bcSHong Zhang 
1055cc4f23bcSHong Zhang   ts->stifflyaccurate = (!th->endpoint && th->Theta != 1.0) ? PETSC_FALSE : PETSC_TRUE;
10563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1057b4dd3bf9SBarry Smith }
10580c7376e5SHong Zhang 
1059b4dd3bf9SBarry Smith /*------------------------------------------------------------*/
1060b4dd3bf9SBarry Smith 
1061d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointSetUp_Theta(TS ts)
1062d71ae5a4SJacob Faibussowitsch {
1063b4dd3bf9SBarry Smith   TS_Theta *th = (TS_Theta *)ts->data;
1064b4dd3bf9SBarry Smith 
1065b4dd3bf9SBarry Smith   PetscFunctionBegin;
10669566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam));
10679566063dSJacob Faibussowitsch   PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsSensiTemp));
106848a46eb9SPierre Jolivet   if (ts->vecs_sensip) PetscCall(VecDuplicateVecs(ts->vecs_sensip[0], ts->numcost, &th->VecsDeltaMu));
1069b5b4017aSHong Zhang   if (ts->vecs_sensi2) {
10709566063dSJacob Faibussowitsch     PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam2));
10719566063dSJacob Faibussowitsch     PetscCall(VecDuplicateVecs(ts->vecs_sensi2[0], ts->numcost, &th->VecsSensi2Temp));
107267633408SHong Zhang     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
107367633408SHong Zhang     if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu;
107467633408SHong Zhang     if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup;
1075b5b4017aSHong Zhang   }
1076c9681e5dSHong Zhang   if (ts->vecs_sensi2p) {
10779566063dSJacob Faibussowitsch     PetscCall(VecDuplicateVecs(ts->vecs_sensi2p[0], ts->numcost, &th->VecsDeltaMu2));
107867633408SHong Zhang     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
107967633408SHong Zhang     if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu;
108067633408SHong Zhang     if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp;
1081b5b4017aSHong Zhang   }
10823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1083316643e7SJed Brown }
1084316643e7SJed Brown 
1085ce78bad3SBarry Smith static PetscErrorCode TSSetFromOptions_Theta(TS ts, PetscOptionItems PetscOptionsObject)
1086d71ae5a4SJacob Faibussowitsch {
1087316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
1088316643e7SJed Brown 
1089316643e7SJed Brown   PetscFunctionBegin;
1090d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Theta ODE solver options");
1091316643e7SJed Brown   {
10929566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_theta_theta", "Location of stage (0<Theta<=1)", "TSThetaSetTheta", th->Theta, &th->Theta, NULL));
10939566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_theta_endpoint", "Use the endpoint instead of midpoint form of the Theta method", "TSThetaSetEndpoint", th->endpoint, &th->endpoint, NULL));
10949566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-ts_theta_initial_guess_extrapolate", "Extrapolate stage initial guess from previous solution (sometimes unstable)", "TSThetaSetExtrapolate", th->extrapolate, &th->extrapolate, NULL));
1095316643e7SJed Brown   }
1096d0609cedSBarry Smith   PetscOptionsHeadEnd();
10973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1098316643e7SJed Brown }
1099316643e7SJed Brown 
1100d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_Theta(TS ts, PetscViewer viewer)
1101d71ae5a4SJacob Faibussowitsch {
1102316643e7SJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
11039f196a02SMartin Diehl   PetscBool isascii;
1104316643e7SJed Brown 
1105316643e7SJed Brown   PetscFunctionBegin;
11069f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
11079f196a02SMartin Diehl   if (isascii) {
11089566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Theta=%g\n", (double)th->Theta));
11099566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation=%s\n", th->extrapolate ? "yes" : "no"));
1110316643e7SJed Brown   }
11113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1112316643e7SJed Brown }
1113316643e7SJed Brown 
1114d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetTheta_Theta(TS ts, PetscReal *theta)
1115d71ae5a4SJacob Faibussowitsch {
11160de4c49aSJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
11170de4c49aSJed Brown 
11180de4c49aSJed Brown   PetscFunctionBegin;
11190de4c49aSJed Brown   *theta = th->Theta;
11203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11210de4c49aSJed Brown }
11220de4c49aSJed Brown 
1123d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaSetTheta_Theta(TS ts, PetscReal theta)
1124d71ae5a4SJacob Faibussowitsch {
11250de4c49aSJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
11260de4c49aSJed Brown 
11270de4c49aSJed Brown   PetscFunctionBegin;
1128cad9d221SBarry Smith   PetscCheck(theta > 0 && theta <= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Theta %g not in range (0,1]", (double)theta);
11290de4c49aSJed Brown   th->Theta = theta;
11301566a47fSLisandro Dalcin   th->order = (th->Theta == 0.5) ? 2 : 1;
11313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11320de4c49aSJed Brown }
1133eb284becSJed Brown 
1134d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts, PetscBool *endpoint)
1135d71ae5a4SJacob Faibussowitsch {
113626f2ff8fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
113726f2ff8fSLisandro Dalcin 
113826f2ff8fSLisandro Dalcin   PetscFunctionBegin;
113926f2ff8fSLisandro Dalcin   *endpoint = th->endpoint;
11403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114126f2ff8fSLisandro Dalcin }
114226f2ff8fSLisandro Dalcin 
1143d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts, PetscBool flg)
1144d71ae5a4SJacob Faibussowitsch {
1145eb284becSJed Brown   TS_Theta *th = (TS_Theta *)ts->data;
1146eb284becSJed Brown 
1147eb284becSJed Brown   PetscFunctionBegin;
1148eb284becSJed Brown   th->endpoint = flg;
11493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1150eb284becSJed Brown }
11510de4c49aSJed Brown 
1152f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX)
1153d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSComputeLinearStability_Theta(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi)
1154d71ae5a4SJacob Faibussowitsch {
1155f9c1d6abSBarry Smith   PetscComplex z  = xr + xi * PETSC_i, f;
1156f9c1d6abSBarry Smith   TS_Theta    *th = (TS_Theta *)ts->data;
1157f9c1d6abSBarry Smith 
1158f9c1d6abSBarry Smith   PetscFunctionBegin;
1159520136c7SJose E. Roman   f   = (1.0 + (1.0 - th->Theta) * z) / (1.0 - th->Theta * z);
1160f9c1d6abSBarry Smith   *yr = PetscRealPartComplex(f);
1161f9c1d6abSBarry Smith   *yi = PetscImaginaryPartComplex(f);
11623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1163f9c1d6abSBarry Smith }
1164f9c1d6abSBarry Smith #endif
1165f9c1d6abSBarry Smith 
1166d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGetStages_Theta(TS ts, PetscInt *ns, Vec *Y[])
1167d71ae5a4SJacob Faibussowitsch {
116842682096SHong Zhang   TS_Theta *th = (TS_Theta *)ts->data;
116942682096SHong Zhang 
117042682096SHong Zhang   PetscFunctionBegin;
11717409eceaSHong Zhang   if (ns) {
11727409eceaSHong Zhang     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
11737409eceaSHong Zhang     else *ns = 2;                                   /* endpoint form */
11747409eceaSHong Zhang   }
11755072d23cSHong Zhang   if (Y) {
1176cc4f23bcSHong Zhang     if (!th->endpoint && th->Theta != 1.0) {
11777409eceaSHong Zhang       th->Stages[0] = th->X;
1178cc4f23bcSHong Zhang     } else {
1179cc4f23bcSHong Zhang       th->Stages[0] = th->X0;
1180cc4f23bcSHong Zhang       th->Stages[1] = ts->vec_sol; /* stiffly accurate */
1181cc4f23bcSHong Zhang     }
1182cc4f23bcSHong Zhang     *Y = th->Stages;
11835072d23cSHong Zhang   }
11843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
118542682096SHong Zhang }
1186f9c1d6abSBarry Smith 
1187316643e7SJed Brown /* ------------------------------------------------------------ */
1188316643e7SJed Brown /*MC
118996f5712cSJed Brown       TSTHETA - DAE solver using the implicit Theta method
1190316643e7SJed Brown 
1191316643e7SJed Brown    Level: beginner
1192316643e7SJed Brown 
1193bcf0153eSBarry Smith    Options Database Keys:
1194c82ed962SBarry Smith +  -ts_theta_theta <Theta> - Location of stage (0<Theta<=1)
1195c82ed962SBarry Smith .  -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method
119603842d09SLisandro Dalcin -  -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable)
11974eb428fdSBarry Smith 
1198eb284becSJed Brown    Notes:
119937fdd005SBarry Smith .vb
120037fdd005SBarry Smith   -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER)
120137fdd005SBarry Smith   -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule
120237fdd005SBarry Smith   -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN)
120337fdd005SBarry Smith .ve
12044eb428fdSBarry Smith 
12057409eceaSHong 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.
1206eb284becSJed Brown 
12077409eceaSHong Zhang    The midpoint variant is cast as a 1-stage implicit Runge-Kutta method.
1208eb284becSJed Brown 
1209eb284becSJed Brown .vb
1210eb284becSJed Brown   Theta | Theta
1211eb284becSJed Brown   -------------
1212eb284becSJed Brown         |  1
1213eb284becSJed Brown .ve
1214eb284becSJed Brown 
1215eb284becSJed Brown    For the default Theta=0.5, this is also known as the implicit midpoint rule.
1216eb284becSJed Brown 
1217eb284becSJed Brown    When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit:
1218eb284becSJed Brown 
1219eb284becSJed Brown .vb
1220eb284becSJed Brown   0 | 0         0
1221eb284becSJed Brown   1 | 1-Theta   Theta
1222eb284becSJed Brown   -------------------
1223eb284becSJed Brown     | 1-Theta   Theta
1224eb284becSJed Brown .ve
1225eb284becSJed Brown 
1226eb284becSJed Brown    For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN).
1227eb284becSJed Brown 
1228eb284becSJed Brown    To apply a diagonally implicit RK method to DAE, the stage formula
1229b44f4de4SBarry Smith .vb
1230b44f4de4SBarry Smith   Y_i = X + h sum_j a_ij Y'_j
1231b44f4de4SBarry Smith .ve
12324eb428fdSBarry Smith    is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i)
1233eb284becSJed Brown 
12341cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSCN`, `TSBEULER`, `TSThetaSetTheta()`, `TSThetaSetEndpoint()`
1235316643e7SJed Brown M*/
1236d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts)
1237d71ae5a4SJacob Faibussowitsch {
1238316643e7SJed Brown   TS_Theta *th;
1239316643e7SJed Brown 
1240316643e7SJed Brown   PetscFunctionBegin;
1241277b19d0SLisandro Dalcin   ts->ops->reset          = TSReset_Theta;
1242ece46509SHong Zhang   ts->ops->adjointreset   = TSAdjointReset_Theta;
1243316643e7SJed Brown   ts->ops->destroy        = TSDestroy_Theta;
1244316643e7SJed Brown   ts->ops->view           = TSView_Theta;
1245316643e7SJed Brown   ts->ops->setup          = TSSetUp_Theta;
124642f2b339SBarry Smith   ts->ops->adjointsetup   = TSAdjointSetUp_Theta;
1247ece46509SHong Zhang   ts->ops->adjointreset   = TSAdjointReset_Theta;
1248316643e7SJed Brown   ts->ops->step           = TSStep_Theta;
1249cd652676SJed Brown   ts->ops->interpolate    = TSInterpolate_Theta;
12501566a47fSLisandro Dalcin   ts->ops->evaluatewlte   = TSEvaluateWLTE_Theta;
125124655328SShri   ts->ops->rollback       = TSRollBack_Theta;
125226b5f05dSStefano Zampini   ts->ops->resizeregister = TSResizeRegister_Theta;
1253316643e7SJed Brown   ts->ops->setfromoptions = TSSetFromOptions_Theta;
12540f5c6efeSJed Brown   ts->ops->snesfunction   = SNESTSFormFunction_Theta;
12550f5c6efeSJed Brown   ts->ops->snesjacobian   = SNESTSFormJacobian_Theta;
1256f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX)
1257f9c1d6abSBarry Smith   ts->ops->linearstability = TSComputeLinearStability_Theta;
1258f9c1d6abSBarry Smith #endif
125942682096SHong Zhang   ts->ops->getstages       = TSGetStages_Theta;
126042f2b339SBarry Smith   ts->ops->adjointstep     = TSAdjointStep_Theta;
1261b1cb36f3SHong Zhang   ts->ops->adjointintegral = TSAdjointCostIntegral_Theta;
1262b1cb36f3SHong Zhang   ts->ops->forwardintegral = TSForwardCostIntegral_Theta;
12632ffb9264SLisandro Dalcin   ts->default_adapt_type   = TSADAPTNONE;
12646affb6f8SHong Zhang 
1265715f1b00SHong Zhang   ts->ops->forwardsetup     = TSForwardSetUp_Theta;
12667adebddeSHong Zhang   ts->ops->forwardreset     = TSForwardReset_Theta;
1267715f1b00SHong Zhang   ts->ops->forwardstep      = TSForwardStep_Theta;
12686affb6f8SHong Zhang   ts->ops->forwardgetstages = TSForwardGetStages_Theta;
1269316643e7SJed Brown 
1270efd4aadfSBarry Smith   ts->usessnes = PETSC_TRUE;
1271efd4aadfSBarry Smith 
12724dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&th));
1273316643e7SJed Brown   ts->data = (void *)th;
1274316643e7SJed Brown 
1275715f1b00SHong Zhang   th->VecsDeltaLam   = NULL;
1276715f1b00SHong Zhang   th->VecsDeltaMu    = NULL;
1277715f1b00SHong Zhang   th->VecsSensiTemp  = NULL;
1278b5b4017aSHong Zhang   th->VecsSensi2Temp = NULL;
1279715f1b00SHong Zhang 
12806f700aefSJed Brown   th->extrapolate = PETSC_FALSE;
1281316643e7SJed Brown   th->Theta       = 0.5;
12821566a47fSLisandro Dalcin   th->order       = 2;
12839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", TSThetaGetTheta_Theta));
12849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", TSThetaSetTheta_Theta));
12859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", TSThetaGetEndpoint_Theta));
12869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", TSThetaSetEndpoint_Theta));
12873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1288316643e7SJed Brown }
12890de4c49aSJed Brown 
12900de4c49aSJed Brown /*@
1291bcf0153eSBarry Smith   TSThetaGetTheta - Get the abscissa of the stage in (0,1] for `TSTHETA`
12920de4c49aSJed Brown 
12930de4c49aSJed Brown   Not Collective
12940de4c49aSJed Brown 
12950de4c49aSJed Brown   Input Parameter:
12960de4c49aSJed Brown . ts - timestepping context
12970de4c49aSJed Brown 
12980de4c49aSJed Brown   Output Parameter:
12990de4c49aSJed Brown . theta - stage abscissa
13000de4c49aSJed Brown 
1301bcf0153eSBarry Smith   Level: advanced
1302bcf0153eSBarry Smith 
13030de4c49aSJed Brown   Note:
1304bcf0153eSBarry Smith   Use of this function is normally only required to hack `TSTHETA` to use a modified integration scheme.
13050de4c49aSJed Brown 
13061cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaSetTheta()`, `TSTHETA`
13070de4c49aSJed Brown @*/
1308d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaGetTheta(TS ts, PetscReal *theta)
1309d71ae5a4SJacob Faibussowitsch {
13100de4c49aSJed Brown   PetscFunctionBegin;
1311afb20b64SJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
13124f572ea9SToby Isaac   PetscAssertPointer(theta, 2);
1313cac4c232SBarry Smith   PetscUseMethod(ts, "TSThetaGetTheta_C", (TS, PetscReal *), (ts, theta));
13143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13150de4c49aSJed Brown }
13160de4c49aSJed Brown 
13170de4c49aSJed Brown /*@
1318bcf0153eSBarry Smith   TSThetaSetTheta - Set the abscissa of the stage in (0,1]  for `TSTHETA`
13190de4c49aSJed Brown 
13200de4c49aSJed Brown   Not Collective
13210de4c49aSJed Brown 
1322d8d19677SJose E. Roman   Input Parameters:
13230de4c49aSJed Brown + ts    - timestepping context
13240de4c49aSJed Brown - theta - stage abscissa
13250de4c49aSJed Brown 
1326bcf0153eSBarry Smith   Options Database Key:
132767b8a455SSatish Balay . -ts_theta_theta <theta> - set theta
13280de4c49aSJed Brown 
1329bcf0153eSBarry Smith   Level: intermediate
13300de4c49aSJed Brown 
13311cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaGetTheta()`, `TSTHETA`, `TSCN`
13320de4c49aSJed Brown @*/
1333d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaSetTheta(TS ts, PetscReal theta)
1334d71ae5a4SJacob Faibussowitsch {
13350de4c49aSJed Brown   PetscFunctionBegin;
1336afb20b64SJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1337cac4c232SBarry Smith   PetscTryMethod(ts, "TSThetaSetTheta_C", (TS, PetscReal), (ts, theta));
13383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13390de4c49aSJed Brown }
1340f33bbcb6SJed Brown 
134126f2ff8fSLisandro Dalcin /*@
1342bcf0153eSBarry Smith   TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA`
134326f2ff8fSLisandro Dalcin 
134426f2ff8fSLisandro Dalcin   Not Collective
134526f2ff8fSLisandro Dalcin 
134626f2ff8fSLisandro Dalcin   Input Parameter:
134726f2ff8fSLisandro Dalcin . ts - timestepping context
134826f2ff8fSLisandro Dalcin 
134926f2ff8fSLisandro Dalcin   Output Parameter:
1350bcf0153eSBarry Smith . endpoint - `PETSC_TRUE` when using the endpoint variant
135126f2ff8fSLisandro Dalcin 
1352bcf0153eSBarry Smith   Level: advanced
135326f2ff8fSLisandro Dalcin 
13541cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaSetEndpoint()`, `TSTHETA`, `TSCN`
135526f2ff8fSLisandro Dalcin @*/
1356d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaGetEndpoint(TS ts, PetscBool *endpoint)
1357d71ae5a4SJacob Faibussowitsch {
135826f2ff8fSLisandro Dalcin   PetscFunctionBegin;
135926f2ff8fSLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
13604f572ea9SToby Isaac   PetscAssertPointer(endpoint, 2);
1361cac4c232SBarry Smith   PetscUseMethod(ts, "TSThetaGetEndpoint_C", (TS, PetscBool *), (ts, endpoint));
13623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
136326f2ff8fSLisandro Dalcin }
136426f2ff8fSLisandro Dalcin 
1365eb284becSJed Brown /*@
1366bcf0153eSBarry Smith   TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA`
1367eb284becSJed Brown 
1368eb284becSJed Brown   Not Collective
1369eb284becSJed Brown 
1370d8d19677SJose E. Roman   Input Parameters:
1371eb284becSJed Brown + ts  - timestepping context
1372bcf0153eSBarry Smith - flg - `PETSC_TRUE` to use the endpoint variant
1373eb284becSJed Brown 
1374bcf0153eSBarry Smith   Options Database Key:
137567b8a455SSatish Balay . -ts_theta_endpoint <flg> - use the endpoint variant
1376eb284becSJed Brown 
1377bcf0153eSBarry Smith   Level: intermediate
1378eb284becSJed Brown 
13791cc06b55SBarry Smith .seealso: [](ch_ts), `TSTHETA`, `TSCN`
1380eb284becSJed Brown @*/
1381d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaSetEndpoint(TS ts, PetscBool flg)
1382d71ae5a4SJacob Faibussowitsch {
1383eb284becSJed Brown   PetscFunctionBegin;
1384eb284becSJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1385cac4c232SBarry Smith   PetscTryMethod(ts, "TSThetaSetEndpoint_C", (TS, PetscBool), (ts, flg));
13863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1387eb284becSJed Brown }
1388eb284becSJed Brown 
1389f33bbcb6SJed Brown /*
1390f33bbcb6SJed Brown  * TSBEULER and TSCN are straightforward specializations of TSTHETA.
1391f33bbcb6SJed Brown  * The creation functions for these specializations are below.
1392f33bbcb6SJed Brown  */
1393f33bbcb6SJed Brown 
1394d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_BEuler(TS ts)
1395d71ae5a4SJacob Faibussowitsch {
13961566a47fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
13971566a47fSLisandro Dalcin 
13981566a47fSLisandro Dalcin   PetscFunctionBegin;
139908401ef6SPierre 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");
140028b400f6SJacob 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");
14019566063dSJacob Faibussowitsch   PetscCall(TSSetUp_Theta(ts));
14023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14031566a47fSLisandro Dalcin }
14041566a47fSLisandro Dalcin 
1405d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_BEuler(TS ts, PetscViewer viewer)
1406d71ae5a4SJacob Faibussowitsch {
1407f33bbcb6SJed Brown   PetscFunctionBegin;
14083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1409f33bbcb6SJed Brown }
1410f33bbcb6SJed Brown 
1411f33bbcb6SJed Brown /*MC
1412f33bbcb6SJed Brown       TSBEULER - ODE solver using the implicit backward Euler method
1413f33bbcb6SJed Brown 
1414f33bbcb6SJed Brown   Level: beginner
1415f33bbcb6SJed Brown 
1416bcf0153eSBarry Smith   Note:
141737fdd005SBarry Smith   `TSBEULER` is equivalent to `TSTHETA` with Theta=1.0 or `-ts_type theta -ts_theta_theta 1.0`
14184eb428fdSBarry Smith 
14191cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSEULER`, `TSCN`, `TSTHETA`
1420f33bbcb6SJed Brown M*/
1421d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts)
1422d71ae5a4SJacob Faibussowitsch {
1423f33bbcb6SJed Brown   PetscFunctionBegin;
14249566063dSJacob Faibussowitsch   PetscCall(TSCreate_Theta(ts));
14259566063dSJacob Faibussowitsch   PetscCall(TSThetaSetTheta(ts, 1.0));
14269566063dSJacob Faibussowitsch   PetscCall(TSThetaSetEndpoint(ts, PETSC_FALSE));
14270c7376e5SHong Zhang   ts->ops->setup = TSSetUp_BEuler;
1428f33bbcb6SJed Brown   ts->ops->view  = TSView_BEuler;
14293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1430f33bbcb6SJed Brown }
1431f33bbcb6SJed Brown 
1432d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_CN(TS ts)
1433d71ae5a4SJacob Faibussowitsch {
14341566a47fSLisandro Dalcin   TS_Theta *th = (TS_Theta *)ts->data;
14351566a47fSLisandro Dalcin 
14361566a47fSLisandro Dalcin   PetscFunctionBegin;
143708401ef6SPierre 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");
14383c633725SBarry 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");
14399566063dSJacob Faibussowitsch   PetscCall(TSSetUp_Theta(ts));
14403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14411566a47fSLisandro Dalcin }
14421566a47fSLisandro Dalcin 
1443d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_CN(TS ts, PetscViewer viewer)
1444d71ae5a4SJacob Faibussowitsch {
1445f33bbcb6SJed Brown   PetscFunctionBegin;
14463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1447f33bbcb6SJed Brown }
1448f33bbcb6SJed Brown 
1449f33bbcb6SJed Brown /*MC
1450f33bbcb6SJed Brown       TSCN - ODE solver using the implicit Crank-Nicolson method.
1451f33bbcb6SJed Brown 
1452f33bbcb6SJed Brown   Level: beginner
1453f33bbcb6SJed Brown 
1454f33bbcb6SJed Brown   Notes:
1455bcf0153eSBarry Smith   `TSCN` is equivalent to `TSTHETA` with Theta=0.5 and the "endpoint" option set. I.e.
1456bcf0153eSBarry Smith .vb
1457bcf0153eSBarry Smith   -ts_type theta
1458bcf0153eSBarry Smith   -ts_theta_theta 0.5
1459bcf0153eSBarry Smith   -ts_theta_endpoint
1460bcf0153eSBarry Smith .ve
14617cf5af47SJed Brown 
14621cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSBEULER`, `TSTHETA`, `TSType`,
1463f33bbcb6SJed Brown M*/
1464d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts)
1465d71ae5a4SJacob Faibussowitsch {
1466f33bbcb6SJed Brown   PetscFunctionBegin;
14679566063dSJacob Faibussowitsch   PetscCall(TSCreate_Theta(ts));
14689566063dSJacob Faibussowitsch   PetscCall(TSThetaSetTheta(ts, 0.5));
14699566063dSJacob Faibussowitsch   PetscCall(TSThetaSetEndpoint(ts, PETSC_TRUE));
14700c7376e5SHong Zhang   ts->ops->setup = TSSetUp_CN;
1471f33bbcb6SJed Brown   ts->ops->view  = TSView_CN;
14723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1473f33bbcb6SJed Brown }
1474