xref: /petsc/src/ts/impls/implicit/theta/theta.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1 /*
2   Code for timestepping with implicit Theta method
3 */
4 #include <petsc/private/tsimpl.h> /*I   "petscts.h"   I*/
5 #include <petscsnes.h>
6 #include <petscdm.h>
7 #include <petscmat.h>
8 
9 typedef struct {
10   /* context for time stepping */
11   PetscReal    stage_time;
12   Vec          Stages[2];   /* Storage for stage solutions */
13   Vec          X0, X, Xdot; /* Storage for u^n, u^n + dt a_{11} k_1, and time derivative u^{n+1}_t */
14   Vec          affine;      /* Affine vector needed for residual at beginning of step in endpoint formulation */
15   PetscReal    Theta;
16   PetscReal    shift; /* Shift parameter for SNES Jacobian, used by forward, TLM and adjoint */
17   PetscInt     order;
18   PetscBool    endpoint;
19   PetscBool    extrapolate;
20   TSStepStatus status;
21   Vec          VecCostIntegral0; /* Backup for roll-backs due to events, used by cost integral */
22   PetscReal    ptime0;           /* Backup for ts->ptime, the start time of current time step, used by TLM and cost integral */
23   PetscReal    time_step0;       /* Backup for ts->timestep, the step size of current time step, used by TLM and cost integral*/
24 
25   /* context for sensitivity analysis */
26   PetscInt num_tlm;               /* Total number of tangent linear equations */
27   Vec     *VecsDeltaLam;          /* Increment of the adjoint sensitivity w.r.t IC at stage */
28   Vec     *VecsDeltaMu;           /* Increment of the adjoint sensitivity w.r.t P at stage */
29   Vec     *VecsSensiTemp;         /* Vector to be multiplied with Jacobian transpose */
30   Mat      MatFwdStages[2];       /* TLM Stages */
31   Mat      MatDeltaFwdSensip;     /* Increment of the forward sensitivity at stage */
32   Vec      VecDeltaFwdSensipCol;  /* Working vector for holding one column of the sensitivity matrix */
33   Mat      MatFwdSensip0;         /* backup for roll-backs due to events */
34   Mat      MatIntegralSensipTemp; /* Working vector for forward integral sensitivity */
35   Mat      MatIntegralSensip0;    /* backup for roll-backs due to events */
36   Vec     *VecsDeltaLam2;         /* Increment of the 2nd-order adjoint sensitivity w.r.t IC at stage */
37   Vec     *VecsDeltaMu2;          /* Increment of the 2nd-order adjoint sensitivity w.r.t P at stage */
38   Vec     *VecsSensi2Temp;        /* Working vectors that holds the residual for the second-order adjoint */
39   Vec     *VecsAffine;            /* Working vectors to store residuals */
40   /* context for error estimation */
41   Vec vec_sol_prev;
42   Vec vec_lte_work;
43 } TS_Theta;
44 
45 static PetscErrorCode TSThetaGetX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
46 {
47   TS_Theta *th = (TS_Theta *)ts->data;
48 
49   PetscFunctionBegin;
50   if (X0) {
51     if (dm && dm != ts->dm) {
52       PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_X0", X0));
53     } else *X0 = ts->vec_sol;
54   }
55   if (Xdot) {
56     if (dm && dm != ts->dm) {
57       PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_Xdot", Xdot));
58     } else *Xdot = th->Xdot;
59   }
60   PetscFunctionReturn(PETSC_SUCCESS);
61 }
62 
63 static PetscErrorCode TSThetaRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot)
64 {
65   PetscFunctionBegin;
66   if (X0) {
67     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_X0", X0));
68   }
69   if (Xdot) {
70     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_Xdot", Xdot));
71   }
72   PetscFunctionReturn(PETSC_SUCCESS);
73 }
74 
75 static PetscErrorCode DMCoarsenHook_TSTheta(DM fine, DM coarse, void *ctx)
76 {
77   PetscFunctionBegin;
78   PetscFunctionReturn(PETSC_SUCCESS);
79 }
80 
81 static PetscErrorCode DMRestrictHook_TSTheta(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
82 {
83   TS  ts = (TS)ctx;
84   Vec X0, Xdot, X0_c, Xdot_c;
85 
86   PetscFunctionBegin;
87   PetscCall(TSThetaGetX0AndXdot(ts, fine, &X0, &Xdot));
88   PetscCall(TSThetaGetX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
89   PetscCall(MatRestrict(restrct, X0, X0_c));
90   PetscCall(MatRestrict(restrct, Xdot, Xdot_c));
91   PetscCall(VecPointwiseMult(X0_c, rscale, X0_c));
92   PetscCall(VecPointwiseMult(Xdot_c, rscale, Xdot_c));
93   PetscCall(TSThetaRestoreX0AndXdot(ts, fine, &X0, &Xdot));
94   PetscCall(TSThetaRestoreX0AndXdot(ts, coarse, &X0_c, &Xdot_c));
95   PetscFunctionReturn(PETSC_SUCCESS);
96 }
97 
98 static PetscErrorCode DMSubDomainHook_TSTheta(DM dm, DM subdm, void *ctx)
99 {
100   PetscFunctionBegin;
101   PetscFunctionReturn(PETSC_SUCCESS);
102 }
103 
104 static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
105 {
106   TS  ts = (TS)ctx;
107   Vec X0, Xdot, X0_sub, Xdot_sub;
108 
109   PetscFunctionBegin;
110   PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot));
111   PetscCall(TSThetaGetX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
112 
113   PetscCall(VecScatterBegin(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
114   PetscCall(VecScatterEnd(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD));
115 
116   PetscCall(VecScatterBegin(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
117   PetscCall(VecScatterEnd(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD));
118 
119   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot));
120   PetscCall(TSThetaRestoreX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub));
121   PetscFunctionReturn(PETSC_SUCCESS);
122 }
123 
124 static PetscErrorCode TSThetaEvaluateCostIntegral(TS ts)
125 {
126   TS_Theta *th     = (TS_Theta *)ts->data;
127   TS        quadts = ts->quadraturets;
128 
129   PetscFunctionBegin;
130   if (th->endpoint) {
131     /* Evolve ts->vec_costintegral to compute integrals */
132     if (th->Theta != 1.0) {
133       PetscCall(TSComputeRHSFunction(quadts, th->ptime0, th->X0, ts->vec_costintegrand));
134       PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * (1.0 - th->Theta), ts->vec_costintegrand));
135     }
136     PetscCall(TSComputeRHSFunction(quadts, ts->ptime, ts->vec_sol, ts->vec_costintegrand));
137     PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * th->Theta, ts->vec_costintegrand));
138   } else {
139     PetscCall(TSComputeRHSFunction(quadts, th->stage_time, th->X, ts->vec_costintegrand));
140     PetscCall(VecAXPY(quadts->vec_sol, th->time_step0, ts->vec_costintegrand));
141   }
142   PetscFunctionReturn(PETSC_SUCCESS);
143 }
144 
145 static PetscErrorCode TSForwardCostIntegral_Theta(TS ts)
146 {
147   TS_Theta *th     = (TS_Theta *)ts->data;
148   TS        quadts = ts->quadraturets;
149 
150   PetscFunctionBegin;
151   /* backup cost integral */
152   PetscCall(VecCopy(quadts->vec_sol, th->VecCostIntegral0));
153   PetscCall(TSThetaEvaluateCostIntegral(ts));
154   PetscFunctionReturn(PETSC_SUCCESS);
155 }
156 
157 static PetscErrorCode TSAdjointCostIntegral_Theta(TS ts)
158 {
159   TS_Theta *th = (TS_Theta *)ts->data;
160 
161   PetscFunctionBegin;
162   /* Like TSForwardCostIntegral(), the adjoint cost integral evaluation relies on ptime0 and time_step0. */
163   th->ptime0     = ts->ptime + ts->time_step;
164   th->time_step0 = -ts->time_step;
165   PetscCall(TSThetaEvaluateCostIntegral(ts));
166   PetscFunctionReturn(PETSC_SUCCESS);
167 }
168 
169 static PetscErrorCode TSTheta_SNESSolve(TS ts, Vec b, Vec x)
170 {
171   PetscInt nits, lits;
172 
173   PetscFunctionBegin;
174   PetscCall(SNESSolve(ts->snes, b, x));
175   PetscCall(SNESGetIterationNumber(ts->snes, &nits));
176   PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
177   ts->snes_its += nits;
178   ts->ksp_its += lits;
179   PetscFunctionReturn(PETSC_SUCCESS);
180 }
181 
182 static PetscErrorCode TSResizeRegister_Theta(TS ts, PetscBool reg)
183 {
184   TS_Theta *th = (TS_Theta *)ts->data;
185 
186   PetscFunctionBegin;
187   if (reg) {
188     PetscCall(TSResizeRegisterVec(ts, "ts:theta:sol_prev", th->vec_sol_prev));
189     PetscCall(TSResizeRegisterVec(ts, "ts:theta:X0", th->X0));
190   } else {
191     PetscCall(TSResizeRetrieveVec(ts, "ts:theta:sol_prev", &th->vec_sol_prev));
192     PetscCall(PetscObjectReference((PetscObject)th->vec_sol_prev));
193     PetscCall(TSResizeRetrieveVec(ts, "ts:theta:X0", &th->X0));
194     PetscCall(PetscObjectReference((PetscObject)th->X0));
195   }
196   PetscFunctionReturn(PETSC_SUCCESS);
197 }
198 
199 static PetscErrorCode TSStep_Theta(TS ts)
200 {
201   TS_Theta *th         = (TS_Theta *)ts->data;
202   PetscInt  rejections = 0;
203   PetscBool stageok, accept = PETSC_TRUE;
204   PetscReal next_time_step = ts->time_step;
205 
206   PetscFunctionBegin;
207   if (!ts->steprollback) {
208     if (th->vec_sol_prev) PetscCall(VecCopy(th->X0, th->vec_sol_prev));
209     PetscCall(VecCopy(ts->vec_sol, th->X0));
210   }
211 
212   th->status = TS_STEP_INCOMPLETE;
213   while (!ts->reason && th->status != TS_STEP_COMPLETE) {
214     th->shift      = 1 / (th->Theta * ts->time_step);
215     th->stage_time = ts->ptime + (th->endpoint ? (PetscReal)1 : th->Theta) * ts->time_step;
216     PetscCall(VecCopy(th->X0, th->X));
217     if (th->extrapolate && !ts->steprestart) PetscCall(VecAXPY(th->X, 1 / th->shift, th->Xdot));
218     if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */
219       if (!th->affine) PetscCall(VecDuplicate(ts->vec_sol, &th->affine));
220       PetscCall(VecZeroEntries(th->Xdot));
221       PetscCall(TSComputeIFunction(ts, ts->ptime, th->X0, th->Xdot, th->affine, PETSC_FALSE));
222       PetscCall(VecScale(th->affine, (th->Theta - 1) / th->Theta));
223     }
224     PetscCall(TSPreStage(ts, th->stage_time));
225     PetscCall(TSTheta_SNESSolve(ts, th->endpoint ? th->affine : NULL, th->X));
226     PetscCall(TSPostStage(ts, th->stage_time, 0, &th->X));
227     PetscCall(TSAdaptCheckStage(ts->adapt, ts, th->stage_time, th->X, &stageok));
228     if (!stageok) goto reject_step;
229 
230     th->status = TS_STEP_PENDING;
231     if (th->endpoint) {
232       PetscCall(VecCopy(th->X, ts->vec_sol));
233     } else {
234       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
235       PetscCall(VecAXPY(ts->vec_sol, ts->time_step, th->Xdot));
236     }
237     PetscCall(TSAdaptChoose(ts->adapt, ts, ts->time_step, NULL, &next_time_step, &accept));
238     th->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
239     if (!accept) {
240       PetscCall(VecCopy(th->X0, ts->vec_sol));
241       ts->time_step = next_time_step;
242       goto reject_step;
243     }
244 
245     if (ts->forward_solve || ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */
246       th->ptime0     = ts->ptime;
247       th->time_step0 = ts->time_step;
248     }
249     ts->ptime += ts->time_step;
250     ts->time_step = next_time_step;
251     break;
252 
253   reject_step:
254     ts->reject++;
255     accept = PETSC_FALSE;
256     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
257       ts->reason = TS_DIVERGED_STEP_REJECTED;
258       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections));
259     }
260   }
261   PetscFunctionReturn(PETSC_SUCCESS);
262 }
263 
264 static PetscErrorCode TSAdjointStepBEuler_Private(TS ts)
265 {
266   TS_Theta      *th           = (TS_Theta *)ts->data;
267   TS             quadts       = ts->quadraturets;
268   Vec           *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp;
269   Vec           *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp;
270   PetscInt       nadj;
271   Mat            J, Jpre, quadJ = NULL, quadJp = NULL;
272   KSP            ksp;
273   PetscScalar   *xarr;
274   TSEquationType eqtype;
275   PetscBool      isexplicitode = PETSC_FALSE;
276   PetscReal      adjoint_time_step;
277 
278   PetscFunctionBegin;
279   PetscCall(TSGetEquationType(ts, &eqtype));
280   if (eqtype == TS_EQ_ODE_EXPLICIT) {
281     isexplicitode = PETSC_TRUE;
282     VecsDeltaLam  = ts->vecs_sensi;
283     VecsDeltaLam2 = ts->vecs_sensi2;
284   }
285   th->status = TS_STEP_INCOMPLETE;
286   PetscCall(SNESGetKSP(ts->snes, &ksp));
287   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
288   if (quadts) {
289     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
290     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
291   }
292 
293   th->stage_time    = ts->ptime;
294   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
295 
296   /* Build RHS for first-order adjoint lambda_{n+1}/h + r_u^T(n+1) */
297   if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
298 
299   for (nadj = 0; nadj < ts->numcost; nadj++) {
300     PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj]));
301     PetscCall(VecScale(VecsSensiTemp[nadj], 1. / adjoint_time_step)); /* lambda_{n+1}/h */
302     if (quadJ) {
303       PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
304       PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
305       PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col));
306       PetscCall(VecResetArray(ts->vec_drdu_col));
307       PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
308     }
309   }
310 
311   /* Build LHS for first-order adjoint */
312   th->shift = 1. / adjoint_time_step;
313   PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
314   PetscCall(KSPSetOperators(ksp, J, Jpre));
315 
316   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
317   for (nadj = 0; nadj < ts->numcost; nadj++) {
318     KSPConvergedReason kspreason;
319     PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj]));
320     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
321     if (kspreason < 0) {
322       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
323       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n", ts->steps, nadj));
324     }
325   }
326 
327   if (ts->vecs_sensi2) { /* U_{n+1} */
328     /* Get w1 at t_{n+1} from TLM matrix */
329     PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
330     PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
331     /* lambda_s^T F_UU w_1 */
332     PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
333     /* lambda_s^T F_UP w_2 */
334     PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
335     for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */
336       PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj]));
337       PetscCall(VecScale(VecsSensi2Temp[nadj], 1. / adjoint_time_step));
338       PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj]));
339       if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj]));
340     }
341     /* Solve stage equation LHS X = RHS for second-order adjoint */
342     for (nadj = 0; nadj < ts->numcost; nadj++) {
343       KSPConvergedReason kspreason;
344       PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj]));
345       PetscCall(KSPGetConvergedReason(ksp, &kspreason));
346       if (kspreason < 0) {
347         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
348         PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n", ts->steps, nadj));
349       }
350     }
351   }
352 
353   /* Update sensitivities, and evaluate integrals if there is any */
354   if (!isexplicitode) {
355     th->shift = 0.0;
356     PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
357     PetscCall(KSPSetOperators(ksp, J, Jpre));
358     for (nadj = 0; nadj < ts->numcost; nadj++) {
359       /* Add f_U \lambda_s to the original RHS */
360       PetscCall(VecScale(VecsSensiTemp[nadj], -1.));
361       PetscCall(MatMultTransposeAdd(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj], VecsSensiTemp[nadj]));
362       PetscCall(VecScale(VecsSensiTemp[nadj], -adjoint_time_step));
363       PetscCall(VecCopy(VecsSensiTemp[nadj], ts->vecs_sensi[nadj]));
364       if (ts->vecs_sensi2) {
365         PetscCall(MatMultTransposeAdd(J, VecsDeltaLam2[nadj], VecsSensi2Temp[nadj], VecsSensi2Temp[nadj]));
366         PetscCall(VecScale(VecsSensi2Temp[nadj], -adjoint_time_step));
367         PetscCall(VecCopy(VecsSensi2Temp[nadj], ts->vecs_sensi2[nadj]));
368       }
369     }
370   }
371   if (ts->vecs_sensip) {
372     PetscCall(VecAXPBYPCZ(th->Xdot, -1. / adjoint_time_step, 1.0 / adjoint_time_step, 0, th->X0, ts->vec_sol));
373     PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, 1. / adjoint_time_step, ts->Jacp, PETSC_FALSE)); /* get -f_p */
374     if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
375     if (ts->vecs_sensi2p) {
376       /* lambda_s^T F_PU w_1 */
377       PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
378       /* lambda_s^T F_PP w_2 */
379       PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
380     }
381 
382     for (nadj = 0; nadj < ts->numcost; nadj++) {
383       PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
384       PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj]));
385       if (quadJp) {
386         PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
387         PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
388         PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col));
389         PetscCall(VecResetArray(ts->vec_drdp_col));
390         PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
391       }
392       if (ts->vecs_sensi2p) {
393         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
394         PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, VecsDeltaMu2[nadj]));
395         if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpu[nadj]));
396         if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpp[nadj]));
397       }
398     }
399   }
400 
401   if (ts->vecs_sensi2) {
402     PetscCall(VecResetArray(ts->vec_sensip_col));
403     PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
404   }
405   th->status = TS_STEP_COMPLETE;
406   PetscFunctionReturn(PETSC_SUCCESS);
407 }
408 
409 static PetscErrorCode TSAdjointStep_Theta(TS ts)
410 {
411   TS_Theta    *th           = (TS_Theta *)ts->data;
412   TS           quadts       = ts->quadraturets;
413   Vec         *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp;
414   Vec         *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp;
415   PetscInt     nadj;
416   Mat          J, Jpre, quadJ = NULL, quadJp = NULL;
417   KSP          ksp;
418   PetscScalar *xarr;
419   PetscReal    adjoint_time_step;
420   PetscReal    adjoint_ptime; /* end time of the adjoint time step (ts->ptime is the start time, usually ts->ptime is larger than adjoint_ptime) */
421 
422   PetscFunctionBegin;
423   if (th->Theta == 1.) {
424     PetscCall(TSAdjointStepBEuler_Private(ts));
425     PetscFunctionReturn(PETSC_SUCCESS);
426   }
427   th->status = TS_STEP_INCOMPLETE;
428   PetscCall(SNESGetKSP(ts->snes, &ksp));
429   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
430   if (quadts) {
431     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
432     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
433   }
434   /* If endpoint=1, th->ptime and th->X0 will be used; if endpoint=0, th->stage_time and th->X will be used. */
435   th->stage_time    = th->endpoint ? ts->ptime : (ts->ptime + (1. - th->Theta) * ts->time_step);
436   adjoint_ptime     = ts->ptime + ts->time_step;
437   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
438 
439   if (!th->endpoint) {
440     /* recover th->X0 using vec_sol and the stage value th->X */
441     PetscCall(VecAXPBYPCZ(th->X0, 1.0 / (1.0 - th->Theta), th->Theta / (th->Theta - 1.0), 0, th->X, ts->vec_sol));
442   }
443 
444   /* Build RHS for first-order adjoint */
445   /* Cost function has an integral term */
446   if (quadts) {
447     if (th->endpoint) {
448       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
449     } else {
450       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
451     }
452   }
453 
454   for (nadj = 0; nadj < ts->numcost; nadj++) {
455     PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj]));
456     PetscCall(VecScale(VecsSensiTemp[nadj], 1. / (th->Theta * adjoint_time_step)));
457     if (quadJ) {
458       PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
459       PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
460       PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col));
461       PetscCall(VecResetArray(ts->vec_drdu_col));
462       PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
463     }
464   }
465 
466   /* Build LHS for first-order adjoint */
467   th->shift = 1. / (th->Theta * adjoint_time_step);
468   if (th->endpoint) {
469     PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre));
470   } else {
471     PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre));
472   }
473   PetscCall(KSPSetOperators(ksp, J, Jpre));
474 
475   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
476   for (nadj = 0; nadj < ts->numcost; nadj++) {
477     KSPConvergedReason kspreason;
478     PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj]));
479     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
480     if (kspreason < 0) {
481       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
482       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n", ts->steps, nadj));
483     }
484   }
485 
486   /* Second-order adjoint */
487   if (ts->vecs_sensi2) { /* U_{n+1} */
488     PetscCheck(th->endpoint, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Operation not implemented in TS_Theta");
489     /* Get w1 at t_{n+1} from TLM matrix */
490     PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
491     PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
492     /* lambda_s^T F_UU w_1 */
493     PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
494     PetscCall(VecResetArray(ts->vec_sensip_col));
495     PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
496     /* lambda_s^T F_UP w_2 */
497     PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
498     for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */
499       PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj]));
500       PetscCall(VecScale(VecsSensi2Temp[nadj], th->shift));
501       PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj]));
502       if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj]));
503     }
504     /* Solve stage equation LHS X = RHS for second-order adjoint */
505     for (nadj = 0; nadj < ts->numcost; nadj++) {
506       KSPConvergedReason kspreason;
507       PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj]));
508       PetscCall(KSPGetConvergedReason(ksp, &kspreason));
509       if (kspreason < 0) {
510         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
511         PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n", ts->steps, nadj));
512       }
513     }
514   }
515 
516   /* Update sensitivities, and evaluate integrals if there is any */
517   if (th->endpoint) { /* two-stage Theta methods with th->Theta!=1, th->Theta==1 leads to BEuler */
518     th->shift      = 1. / ((th->Theta - 1.) * adjoint_time_step);
519     th->stage_time = adjoint_ptime;
520     PetscCall(TSComputeSNESJacobian(ts, th->X0, J, Jpre));
521     PetscCall(KSPSetOperators(ksp, J, Jpre));
522     /* R_U at t_n */
523     if (quadts) PetscCall(TSComputeRHSJacobian(quadts, adjoint_ptime, th->X0, quadJ, NULL));
524     for (nadj = 0; nadj < ts->numcost; nadj++) {
525       PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], ts->vecs_sensi[nadj]));
526       if (quadJ) {
527         PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
528         PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
529         PetscCall(VecAXPY(ts->vecs_sensi[nadj], -1., ts->vec_drdu_col));
530         PetscCall(VecResetArray(ts->vec_drdu_col));
531         PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
532       }
533       PetscCall(VecScale(ts->vecs_sensi[nadj], 1. / th->shift));
534     }
535 
536     /* Second-order adjoint */
537     if (ts->vecs_sensi2) { /* U_n */
538       /* Get w1 at t_n from TLM matrix */
539       PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr));
540       PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
541       /* lambda_s^T F_UU w_1 */
542       PetscCall(TSComputeIHessianProductFunctionUU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu));
543       PetscCall(VecResetArray(ts->vec_sensip_col));
544       PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr));
545       /* lambda_s^T F_UU w_2 */
546       PetscCall(TSComputeIHessianProductFunctionUP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fup));
547       for (nadj = 0; nadj < ts->numcost; nadj++) {
548         /* 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  */
549         PetscCall(MatMultTranspose(J, VecsDeltaLam2[nadj], ts->vecs_sensi2[nadj]));
550         PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fuu[nadj]));
551         if (ts->vecs_fup) PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fup[nadj]));
552         PetscCall(VecScale(ts->vecs_sensi2[nadj], 1. / th->shift));
553       }
554     }
555 
556     th->stage_time = ts->ptime; /* recover the old value */
557 
558     if (ts->vecs_sensip) { /* sensitivities wrt parameters */
559       /* U_{n+1} */
560       th->shift = 1.0 / (adjoint_time_step * th->Theta);
561       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol));
562       PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, -1. / (th->Theta * adjoint_time_step), ts->Jacp, PETSC_FALSE));
563       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
564       for (nadj = 0; nadj < ts->numcost; nadj++) {
565         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
566         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu[nadj]));
567         if (quadJp) {
568           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
569           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
570           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * th->Theta, ts->vec_drdp_col));
571           PetscCall(VecResetArray(ts->vec_drdp_col));
572           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
573         }
574       }
575       if (ts->vecs_sensi2p) { /* second-order */
576         /* Get w1 at t_{n+1} from TLM matrix */
577         PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr));
578         PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
579         /* lambda_s^T F_PU w_1 */
580         PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
581         PetscCall(VecResetArray(ts->vec_sensip_col));
582         PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
583 
584         /* lambda_s^T F_PP w_2 */
585         PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
586         for (nadj = 0; nadj < ts->numcost; nadj++) {
587           /* 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)  */
588           PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
589           PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu2[nadj]));
590           if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpu[nadj]));
591           if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpp[nadj]));
592         }
593       }
594 
595       /* U_s */
596       PetscCall(VecZeroEntries(th->Xdot));
597       PetscCall(TSComputeIJacobianP(ts, adjoint_ptime, th->X0, th->Xdot, 1. / ((th->Theta - 1.0) * adjoint_time_step), ts->Jacp, PETSC_FALSE));
598       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, adjoint_ptime, th->X0, quadJp));
599       for (nadj = 0; nadj < ts->numcost; nadj++) {
600         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
601         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu[nadj]));
602         if (quadJp) {
603           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
604           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
605           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * (1.0 - th->Theta), ts->vec_drdp_col));
606           PetscCall(VecResetArray(ts->vec_drdp_col));
607           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
608         }
609         if (ts->vecs_sensi2p) { /* second-order */
610           /* Get w1 at t_n from TLM matrix */
611           PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr));
612           PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
613           /* lambda_s^T F_PU w_1 */
614           PetscCall(TSComputeIHessianProductFunctionPU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu));
615           PetscCall(VecResetArray(ts->vec_sensip_col));
616           PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr));
617           /* lambda_s^T F_PP w_2 */
618           PetscCall(TSComputeIHessianProductFunctionPP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp));
619           for (nadj = 0; nadj < ts->numcost; nadj++) {
620             /* 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) */
621             PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj]));
622             PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu2[nadj]));
623             if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpu[nadj]));
624             if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpp[nadj]));
625           }
626         }
627       }
628     }
629   } else { /* one-stage case */
630     th->shift = 0.0;
631     PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre)); /* get -f_y */
632     PetscCall(KSPSetOperators(ksp, J, Jpre));
633     if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
634     for (nadj = 0; nadj < ts->numcost; nadj++) {
635       PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj]));
636       PetscCall(VecAXPY(ts->vecs_sensi[nadj], -adjoint_time_step, VecsSensiTemp[nadj]));
637       if (quadJ) {
638         PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr));
639         PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr));
640         PetscCall(VecAXPY(ts->vecs_sensi[nadj], adjoint_time_step, ts->vec_drdu_col));
641         PetscCall(VecResetArray(ts->vec_drdu_col));
642         PetscCall(MatDenseRestoreColumn(quadJ, &xarr));
643       }
644     }
645     if (ts->vecs_sensip) {
646       th->shift = 1.0 / (adjoint_time_step * th->Theta);
647       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
648       PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
649       if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp));
650       for (nadj = 0; nadj < ts->numcost; nadj++) {
651         PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj]));
652         PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj]));
653         if (quadJp) {
654           PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr));
655           PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr));
656           PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col));
657           PetscCall(VecResetArray(ts->vec_drdp_col));
658           PetscCall(MatDenseRestoreColumn(quadJp, &xarr));
659         }
660       }
661     }
662   }
663 
664   th->status = TS_STEP_COMPLETE;
665   PetscFunctionReturn(PETSC_SUCCESS);
666 }
667 
668 static PetscErrorCode TSInterpolate_Theta(TS ts, PetscReal t, Vec X)
669 {
670   TS_Theta *th = (TS_Theta *)ts->data;
671   PetscReal dt = t - ts->ptime;
672 
673   PetscFunctionBegin;
674   PetscCall(VecCopy(ts->vec_sol, th->X));
675   if (th->endpoint) dt *= th->Theta;
676   PetscCall(VecWAXPY(X, dt, th->Xdot, th->X));
677   PetscFunctionReturn(PETSC_SUCCESS);
678 }
679 
680 static PetscErrorCode TSEvaluateWLTE_Theta(TS ts, NormType wnormtype, PetscInt *order, PetscReal *wlte)
681 {
682   TS_Theta *th = (TS_Theta *)ts->data;
683   Vec       X  = ts->vec_sol;      /* X = solution */
684   Vec       Y  = th->vec_lte_work; /* Y = X + LTE  */
685   PetscReal wltea, wlter;
686 
687   PetscFunctionBegin;
688   if (!th->vec_sol_prev) {
689     *wlte = -1;
690     PetscFunctionReturn(PETSC_SUCCESS);
691   }
692   /* Cannot compute LTE in first step or in restart after event */
693   if (ts->steprestart) {
694     *wlte = -1;
695     PetscFunctionReturn(PETSC_SUCCESS);
696   }
697   /* Compute LTE using backward differences with non-constant time step */
698   {
699     PetscReal   h = ts->time_step, h_prev = ts->ptime - ts->ptime_prev;
700     PetscReal   a = 1 + h_prev / h;
701     PetscScalar scal[3];
702     Vec         vecs[3];
703     scal[0] = +1 / a;
704     scal[1] = -1 / (a - 1);
705     scal[2] = +1 / (a * (a - 1));
706     vecs[0] = X;
707     vecs[1] = th->X0;
708     vecs[2] = th->vec_sol_prev;
709     PetscCall(VecCopy(X, Y));
710     PetscCall(VecMAXPY(Y, 3, scal, vecs));
711     PetscCall(TSErrorWeightedNorm(ts, X, Y, wnormtype, wlte, &wltea, &wlter));
712   }
713   if (order) *order = 2;
714   PetscFunctionReturn(PETSC_SUCCESS);
715 }
716 
717 static PetscErrorCode TSRollBack_Theta(TS ts)
718 {
719   TS_Theta *th     = (TS_Theta *)ts->data;
720   TS        quadts = ts->quadraturets;
721 
722   PetscFunctionBegin;
723   if (quadts && ts->costintegralfwd) PetscCall(VecCopy(th->VecCostIntegral0, quadts->vec_sol));
724   th->status = TS_STEP_INCOMPLETE;
725   if (ts->mat_sensip) PetscCall(MatCopy(th->MatFwdSensip0, ts->mat_sensip, SAME_NONZERO_PATTERN));
726   if (quadts && quadts->mat_sensip) PetscCall(MatCopy(th->MatIntegralSensip0, quadts->mat_sensip, SAME_NONZERO_PATTERN));
727   PetscFunctionReturn(PETSC_SUCCESS);
728 }
729 
730 static PetscErrorCode TSForwardStep_Theta(TS ts)
731 {
732   TS_Theta    *th                   = (TS_Theta *)ts->data;
733   TS           quadts               = ts->quadraturets;
734   Mat          MatDeltaFwdSensip    = th->MatDeltaFwdSensip;
735   Vec          VecDeltaFwdSensipCol = th->VecDeltaFwdSensipCol;
736   PetscInt     ntlm;
737   KSP          ksp;
738   Mat          J, Jpre, quadJ = NULL, quadJp = NULL;
739   PetscScalar *barr, *xarr;
740   PetscReal    previous_shift;
741 
742   PetscFunctionBegin;
743   previous_shift = th->shift;
744   PetscCall(MatCopy(ts->mat_sensip, th->MatFwdSensip0, SAME_NONZERO_PATTERN));
745 
746   if (quadts && quadts->mat_sensip) PetscCall(MatCopy(quadts->mat_sensip, th->MatIntegralSensip0, SAME_NONZERO_PATTERN));
747   PetscCall(SNESGetKSP(ts->snes, &ksp));
748   PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL));
749   if (quadts) {
750     PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL));
751     PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL));
752   }
753 
754   /* Build RHS */
755   if (th->endpoint) { /* 2-stage method*/
756     th->shift = 1. / ((th->Theta - 1.) * th->time_step0);
757     PetscCall(TSComputeIJacobian(ts, th->ptime0, th->X0, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
758     PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DEFAULT, &MatDeltaFwdSensip));
759     PetscCall(MatScale(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta));
760 
761     /* Add the f_p forcing terms */
762     if (ts->Jacp) {
763       PetscCall(VecZeroEntries(th->Xdot));
764       PetscCall(TSComputeIJacobianP(ts, th->ptime0, th->X0, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
765       PetscCall(MatAXPY(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta, ts->Jacp, SUBSET_NONZERO_PATTERN));
766       th->shift = previous_shift;
767       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol));
768       PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
769       PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN));
770     }
771   } else { /* 1-stage method */
772     th->shift = 0.0;
773     PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
774     PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DEFAULT, &MatDeltaFwdSensip));
775     PetscCall(MatScale(MatDeltaFwdSensip, -1.));
776 
777     /* Add the f_p forcing terms */
778     if (ts->Jacp) {
779       th->shift = previous_shift;
780       PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X));
781       PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE));
782       PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN));
783     }
784   }
785 
786   /* Build LHS */
787   th->shift = previous_shift; /* recover the previous shift used in TSStep_Theta() */
788   if (th->endpoint) {
789     PetscCall(TSComputeIJacobian(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
790   } else {
791     PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE));
792   }
793   PetscCall(KSPSetOperators(ksp, J, Jpre));
794 
795   /*
796     Evaluate the first stage of integral gradients with the 2-stage method:
797     drdu|t_n*S(t_n) + drdp|t_n
798     This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1})
799   */
800   if (th->endpoint) { /* 2-stage method only */
801     if (quadts && quadts->mat_sensip) {
802       PetscCall(TSComputeRHSJacobian(quadts, th->ptime0, th->X0, quadJ, NULL));
803       PetscCall(TSComputeRHSJacobianP(quadts, th->ptime0, th->X0, quadJp));
804       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp));
805       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
806       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * (1. - th->Theta), th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
807     }
808   }
809 
810   /* Solve the tangent linear equation for forward sensitivities to parameters */
811   for (ntlm = 0; ntlm < th->num_tlm; ntlm++) {
812     KSPConvergedReason kspreason;
813     PetscCall(MatDenseGetColumn(MatDeltaFwdSensip, ntlm, &barr));
814     PetscCall(VecPlaceArray(VecDeltaFwdSensipCol, barr));
815     if (th->endpoint) {
816       PetscCall(MatDenseGetColumn(ts->mat_sensip, ntlm, &xarr));
817       PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr));
818       PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, ts->vec_sensip_col));
819       PetscCall(VecResetArray(ts->vec_sensip_col));
820       PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr));
821     } else {
822       PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, VecDeltaFwdSensipCol));
823     }
824     PetscCall(KSPGetConvergedReason(ksp, &kspreason));
825     if (kspreason < 0) {
826       ts->reason = TSFORWARD_DIVERGED_LINEAR_SOLVE;
827       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th tangent linear solve, linear solve fails, stopping tangent linear solve\n", ts->steps, ntlm));
828     }
829     PetscCall(VecResetArray(VecDeltaFwdSensipCol));
830     PetscCall(MatDenseRestoreColumn(MatDeltaFwdSensip, &barr));
831   }
832 
833   /*
834     Evaluate the second stage of integral gradients with the 2-stage method:
835     drdu|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1}
836   */
837   if (quadts && quadts->mat_sensip) {
838     if (!th->endpoint) {
839       PetscCall(MatAXPY(ts->mat_sensip, 1, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); /* stage sensitivity */
840       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL));
841       PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp));
842       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp));
843       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
844       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
845       PetscCall(MatAXPY(ts->mat_sensip, (1. - th->Theta) / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN));
846     } else {
847       PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL));
848       PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp));
849       PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp));
850       PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN));
851       PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * th->Theta, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN));
852     }
853   } else {
854     if (!th->endpoint) PetscCall(MatAXPY(ts->mat_sensip, 1. / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN));
855   }
856   PetscFunctionReturn(PETSC_SUCCESS);
857 }
858 
859 static PetscErrorCode TSForwardGetStages_Theta(TS ts, PetscInt *ns, Mat *stagesensip[])
860 {
861   TS_Theta *th = (TS_Theta *)ts->data;
862 
863   PetscFunctionBegin;
864   if (ns) {
865     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
866     else *ns = 2;                                   /* endpoint form */
867   }
868   if (stagesensip) {
869     if (!th->endpoint && th->Theta != 1.0) {
870       th->MatFwdStages[0] = th->MatDeltaFwdSensip;
871     } else {
872       th->MatFwdStages[0] = th->MatFwdSensip0;
873       th->MatFwdStages[1] = ts->mat_sensip; /* stiffly accurate */
874     }
875     *stagesensip = th->MatFwdStages;
876   }
877   PetscFunctionReturn(PETSC_SUCCESS);
878 }
879 
880 /*------------------------------------------------------------*/
881 static PetscErrorCode TSReset_Theta(TS ts)
882 {
883   TS_Theta *th = (TS_Theta *)ts->data;
884 
885   PetscFunctionBegin;
886   PetscCall(VecDestroy(&th->X));
887   PetscCall(VecDestroy(&th->Xdot));
888   PetscCall(VecDestroy(&th->X0));
889   PetscCall(VecDestroy(&th->affine));
890 
891   PetscCall(VecDestroy(&th->vec_sol_prev));
892   PetscCall(VecDestroy(&th->vec_lte_work));
893 
894   PetscCall(VecDestroy(&th->VecCostIntegral0));
895   PetscFunctionReturn(PETSC_SUCCESS);
896 }
897 
898 static PetscErrorCode TSAdjointReset_Theta(TS ts)
899 {
900   TS_Theta *th = (TS_Theta *)ts->data;
901 
902   PetscFunctionBegin;
903   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam));
904   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu));
905   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam2));
906   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu2));
907   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensiTemp));
908   PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensi2Temp));
909   PetscFunctionReturn(PETSC_SUCCESS);
910 }
911 
912 static PetscErrorCode TSDestroy_Theta(TS ts)
913 {
914   PetscFunctionBegin;
915   PetscCall(TSReset_Theta(ts));
916   if (ts->dm) {
917     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts));
918     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts));
919   }
920   PetscCall(PetscFree(ts->data));
921   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", NULL));
922   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", NULL));
923   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", NULL));
924   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", NULL));
925   PetscFunctionReturn(PETSC_SUCCESS);
926 }
927 
928 /*
929   This defines the nonlinear equation that is to be solved with SNES
930   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
931 
932   Note that U here is the stage argument. This means that U = U_{n+1} only if endpoint = true,
933   otherwise U = theta U_{n+1} + (1 - theta) U0, which for the case of implicit midpoint is
934   U = (U_{n+1} + U0)/2
935 */
936 static PetscErrorCode SNESTSFormFunction_Theta(SNES snes, Vec x, Vec y, TS ts)
937 {
938   TS_Theta *th = (TS_Theta *)ts->data;
939   Vec       X0, Xdot;
940   DM        dm, dmsave;
941   PetscReal shift = th->shift;
942 
943   PetscFunctionBegin;
944   PetscCall(SNESGetDM(snes, &dm));
945   /* When using the endpoint variant, this is actually 1/Theta * Xdot */
946   PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot));
947   if (x != X0) {
948     PetscCall(VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x));
949   } else {
950     PetscCall(VecZeroEntries(Xdot));
951   }
952   /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
953   dmsave = ts->dm;
954   ts->dm = dm;
955   PetscCall(TSComputeIFunction(ts, th->stage_time, x, Xdot, y, PETSC_FALSE));
956   ts->dm = dmsave;
957   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot));
958   PetscFunctionReturn(PETSC_SUCCESS);
959 }
960 
961 static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes, Vec x, Mat A, Mat B, TS ts)
962 {
963   TS_Theta *th = (TS_Theta *)ts->data;
964   Vec       Xdot;
965   DM        dm, dmsave;
966   PetscReal shift = th->shift;
967 
968   PetscFunctionBegin;
969   PetscCall(SNESGetDM(snes, &dm));
970   /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */
971   PetscCall(TSThetaGetX0AndXdot(ts, dm, NULL, &Xdot));
972 
973   dmsave = ts->dm;
974   ts->dm = dm;
975   PetscCall(TSComputeIJacobian(ts, th->stage_time, x, Xdot, shift, A, B, PETSC_FALSE));
976   ts->dm = dmsave;
977   PetscCall(TSThetaRestoreX0AndXdot(ts, dm, NULL, &Xdot));
978   PetscFunctionReturn(PETSC_SUCCESS);
979 }
980 
981 static PetscErrorCode TSForwardSetUp_Theta(TS ts)
982 {
983   TS_Theta *th     = (TS_Theta *)ts->data;
984   TS        quadts = ts->quadraturets;
985 
986   PetscFunctionBegin;
987   /* combine sensitivities to parameters and sensitivities to initial values into one array */
988   th->num_tlm = ts->num_parameters;
989   PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatDeltaFwdSensip));
990   if (quadts && quadts->mat_sensip) {
991     PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensipTemp));
992     PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensip0));
993   }
994   /* backup sensitivity results for roll-backs */
995   PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatFwdSensip0));
996 
997   PetscCall(VecDuplicate(ts->vec_sol, &th->VecDeltaFwdSensipCol));
998   PetscFunctionReturn(PETSC_SUCCESS);
999 }
1000 
1001 static PetscErrorCode TSForwardReset_Theta(TS ts)
1002 {
1003   TS_Theta *th     = (TS_Theta *)ts->data;
1004   TS        quadts = ts->quadraturets;
1005 
1006   PetscFunctionBegin;
1007   if (quadts && quadts->mat_sensip) {
1008     PetscCall(MatDestroy(&th->MatIntegralSensipTemp));
1009     PetscCall(MatDestroy(&th->MatIntegralSensip0));
1010   }
1011   PetscCall(VecDestroy(&th->VecDeltaFwdSensipCol));
1012   PetscCall(MatDestroy(&th->MatDeltaFwdSensip));
1013   PetscCall(MatDestroy(&th->MatFwdSensip0));
1014   PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016 
1017 static PetscErrorCode TSSetUp_Theta(TS ts)
1018 {
1019   TS_Theta *th     = (TS_Theta *)ts->data;
1020   TS        quadts = ts->quadraturets;
1021   PetscBool match;
1022 
1023   PetscFunctionBegin;
1024   if (!th->VecCostIntegral0 && quadts && ts->costintegralfwd) { /* back up cost integral */
1025     PetscCall(VecDuplicate(quadts->vec_sol, &th->VecCostIntegral0));
1026   }
1027   if (!th->X) PetscCall(VecDuplicate(ts->vec_sol, &th->X));
1028   if (!th->Xdot) PetscCall(VecDuplicate(ts->vec_sol, &th->Xdot));
1029   if (!th->X0) PetscCall(VecDuplicate(ts->vec_sol, &th->X0));
1030   if (th->endpoint) PetscCall(VecDuplicate(ts->vec_sol, &th->affine));
1031 
1032   th->order = (th->Theta == 0.5) ? 2 : 1;
1033   th->shift = 1 / (th->Theta * ts->time_step);
1034 
1035   PetscCall(TSGetDM(ts, &ts->dm));
1036   PetscCall(DMCoarsenHookAdd(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts));
1037   PetscCall(DMSubDomainHookAdd(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts));
1038 
1039   PetscCall(TSGetAdapt(ts, &ts->adapt));
1040   PetscCall(TSAdaptCandidatesClear(ts->adapt));
1041   PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &match));
1042   if (!match) {
1043     if (!th->vec_sol_prev) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_sol_prev));
1044     if (!th->vec_lte_work) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_lte_work));
1045   }
1046   PetscCall(TSGetSNES(ts, &ts->snes));
1047 
1048   ts->stifflyaccurate = (!th->endpoint && th->Theta != 1.0) ? PETSC_FALSE : PETSC_TRUE;
1049   PetscFunctionReturn(PETSC_SUCCESS);
1050 }
1051 
1052 /*------------------------------------------------------------*/
1053 
1054 static PetscErrorCode TSAdjointSetUp_Theta(TS ts)
1055 {
1056   TS_Theta *th = (TS_Theta *)ts->data;
1057 
1058   PetscFunctionBegin;
1059   PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam));
1060   PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsSensiTemp));
1061   if (ts->vecs_sensip) PetscCall(VecDuplicateVecs(ts->vecs_sensip[0], ts->numcost, &th->VecsDeltaMu));
1062   if (ts->vecs_sensi2) {
1063     PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam2));
1064     PetscCall(VecDuplicateVecs(ts->vecs_sensi2[0], ts->numcost, &th->VecsSensi2Temp));
1065     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
1066     if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu;
1067     if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup;
1068   }
1069   if (ts->vecs_sensi2p) {
1070     PetscCall(VecDuplicateVecs(ts->vecs_sensi2p[0], ts->numcost, &th->VecsDeltaMu2));
1071     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
1072     if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu;
1073     if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp;
1074   }
1075   PetscFunctionReturn(PETSC_SUCCESS);
1076 }
1077 
1078 static PetscErrorCode TSSetFromOptions_Theta(TS ts, PetscOptionItems *PetscOptionsObject)
1079 {
1080   TS_Theta *th = (TS_Theta *)ts->data;
1081 
1082   PetscFunctionBegin;
1083   PetscOptionsHeadBegin(PetscOptionsObject, "Theta ODE solver options");
1084   {
1085     PetscCall(PetscOptionsReal("-ts_theta_theta", "Location of stage (0<Theta<=1)", "TSThetaSetTheta", th->Theta, &th->Theta, NULL));
1086     PetscCall(PetscOptionsBool("-ts_theta_endpoint", "Use the endpoint instead of midpoint form of the Theta method", "TSThetaSetEndpoint", th->endpoint, &th->endpoint, NULL));
1087     PetscCall(PetscOptionsBool("-ts_theta_initial_guess_extrapolate", "Extrapolate stage initial guess from previous solution (sometimes unstable)", "TSThetaSetExtrapolate", th->extrapolate, &th->extrapolate, NULL));
1088   }
1089   PetscOptionsHeadEnd();
1090   PetscFunctionReturn(PETSC_SUCCESS);
1091 }
1092 
1093 static PetscErrorCode TSView_Theta(TS ts, PetscViewer viewer)
1094 {
1095   TS_Theta *th = (TS_Theta *)ts->data;
1096   PetscBool iascii;
1097 
1098   PetscFunctionBegin;
1099   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1100   if (iascii) {
1101     PetscCall(PetscViewerASCIIPrintf(viewer, "  Theta=%g\n", (double)th->Theta));
1102     PetscCall(PetscViewerASCIIPrintf(viewer, "  Extrapolation=%s\n", th->extrapolate ? "yes" : "no"));
1103   }
1104   PetscFunctionReturn(PETSC_SUCCESS);
1105 }
1106 
1107 static PetscErrorCode TSThetaGetTheta_Theta(TS ts, PetscReal *theta)
1108 {
1109   TS_Theta *th = (TS_Theta *)ts->data;
1110 
1111   PetscFunctionBegin;
1112   *theta = th->Theta;
1113   PetscFunctionReturn(PETSC_SUCCESS);
1114 }
1115 
1116 static PetscErrorCode TSThetaSetTheta_Theta(TS ts, PetscReal theta)
1117 {
1118   TS_Theta *th = (TS_Theta *)ts->data;
1119 
1120   PetscFunctionBegin;
1121   PetscCheck(theta > 0 && theta <= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Theta %g not in range (0,1]", (double)theta);
1122   th->Theta = theta;
1123   th->order = (th->Theta == 0.5) ? 2 : 1;
1124   PetscFunctionReturn(PETSC_SUCCESS);
1125 }
1126 
1127 static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts, PetscBool *endpoint)
1128 {
1129   TS_Theta *th = (TS_Theta *)ts->data;
1130 
1131   PetscFunctionBegin;
1132   *endpoint = th->endpoint;
1133   PetscFunctionReturn(PETSC_SUCCESS);
1134 }
1135 
1136 static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts, PetscBool flg)
1137 {
1138   TS_Theta *th = (TS_Theta *)ts->data;
1139 
1140   PetscFunctionBegin;
1141   th->endpoint = flg;
1142   PetscFunctionReturn(PETSC_SUCCESS);
1143 }
1144 
1145 #if defined(PETSC_HAVE_COMPLEX)
1146 static PetscErrorCode TSComputeLinearStability_Theta(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi)
1147 {
1148   PetscComplex    z   = xr + xi * PETSC_i, f;
1149   TS_Theta       *th  = (TS_Theta *)ts->data;
1150   const PetscReal one = 1.0;
1151 
1152   PetscFunctionBegin;
1153   f   = (one + (one - th->Theta) * z) / (one - th->Theta * z);
1154   *yr = PetscRealPartComplex(f);
1155   *yi = PetscImaginaryPartComplex(f);
1156   PetscFunctionReturn(PETSC_SUCCESS);
1157 }
1158 #endif
1159 
1160 static PetscErrorCode TSGetStages_Theta(TS ts, PetscInt *ns, Vec *Y[])
1161 {
1162   TS_Theta *th = (TS_Theta *)ts->data;
1163 
1164   PetscFunctionBegin;
1165   if (ns) {
1166     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
1167     else *ns = 2;                                   /* endpoint form */
1168   }
1169   if (Y) {
1170     if (!th->endpoint && th->Theta != 1.0) {
1171       th->Stages[0] = th->X;
1172     } else {
1173       th->Stages[0] = th->X0;
1174       th->Stages[1] = ts->vec_sol; /* stiffly accurate */
1175     }
1176     *Y = th->Stages;
1177   }
1178   PetscFunctionReturn(PETSC_SUCCESS);
1179 }
1180 
1181 /* ------------------------------------------------------------ */
1182 /*MC
1183       TSTHETA - DAE solver using the implicit Theta method
1184 
1185    Level: beginner
1186 
1187    Options Database Keys:
1188 +  -ts_theta_theta <Theta> - Location of stage (0<Theta<=1)
1189 .  -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method
1190 -  -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable)
1191 
1192    Notes:
1193 .vb
1194   -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER)
1195   -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule
1196   -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN)
1197 .ve
1198 
1199    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.
1200 
1201    The midpoint variant is cast as a 1-stage implicit Runge-Kutta method.
1202 
1203 .vb
1204   Theta | Theta
1205   -------------
1206         |  1
1207 .ve
1208 
1209    For the default Theta=0.5, this is also known as the implicit midpoint rule.
1210 
1211    When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit:
1212 
1213 .vb
1214   0 | 0         0
1215   1 | 1-Theta   Theta
1216   -------------------
1217     | 1-Theta   Theta
1218 .ve
1219 
1220    For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN).
1221 
1222    To apply a diagonally implicit RK method to DAE, the stage formula
1223 
1224 $  Y_i = X + h sum_j a_ij Y'_j
1225 
1226    is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i)
1227 
1228 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSCN`, `TSBEULER`, `TSThetaSetTheta()`, `TSThetaSetEndpoint()`
1229 M*/
1230 PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts)
1231 {
1232   TS_Theta *th;
1233 
1234   PetscFunctionBegin;
1235   ts->ops->reset          = TSReset_Theta;
1236   ts->ops->adjointreset   = TSAdjointReset_Theta;
1237   ts->ops->destroy        = TSDestroy_Theta;
1238   ts->ops->view           = TSView_Theta;
1239   ts->ops->setup          = TSSetUp_Theta;
1240   ts->ops->adjointsetup   = TSAdjointSetUp_Theta;
1241   ts->ops->adjointreset   = TSAdjointReset_Theta;
1242   ts->ops->step           = TSStep_Theta;
1243   ts->ops->interpolate    = TSInterpolate_Theta;
1244   ts->ops->evaluatewlte   = TSEvaluateWLTE_Theta;
1245   ts->ops->rollback       = TSRollBack_Theta;
1246   ts->ops->resizeregister = TSResizeRegister_Theta;
1247   ts->ops->setfromoptions = TSSetFromOptions_Theta;
1248   ts->ops->snesfunction   = SNESTSFormFunction_Theta;
1249   ts->ops->snesjacobian   = SNESTSFormJacobian_Theta;
1250 #if defined(PETSC_HAVE_COMPLEX)
1251   ts->ops->linearstability = TSComputeLinearStability_Theta;
1252 #endif
1253   ts->ops->getstages       = TSGetStages_Theta;
1254   ts->ops->adjointstep     = TSAdjointStep_Theta;
1255   ts->ops->adjointintegral = TSAdjointCostIntegral_Theta;
1256   ts->ops->forwardintegral = TSForwardCostIntegral_Theta;
1257   ts->default_adapt_type   = TSADAPTNONE;
1258 
1259   ts->ops->forwardsetup     = TSForwardSetUp_Theta;
1260   ts->ops->forwardreset     = TSForwardReset_Theta;
1261   ts->ops->forwardstep      = TSForwardStep_Theta;
1262   ts->ops->forwardgetstages = TSForwardGetStages_Theta;
1263 
1264   ts->usessnes = PETSC_TRUE;
1265 
1266   PetscCall(PetscNew(&th));
1267   ts->data = (void *)th;
1268 
1269   th->VecsDeltaLam   = NULL;
1270   th->VecsDeltaMu    = NULL;
1271   th->VecsSensiTemp  = NULL;
1272   th->VecsSensi2Temp = NULL;
1273 
1274   th->extrapolate = PETSC_FALSE;
1275   th->Theta       = 0.5;
1276   th->order       = 2;
1277   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", TSThetaGetTheta_Theta));
1278   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", TSThetaSetTheta_Theta));
1279   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", TSThetaGetEndpoint_Theta));
1280   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", TSThetaSetEndpoint_Theta));
1281   PetscFunctionReturn(PETSC_SUCCESS);
1282 }
1283 
1284 /*@
1285   TSThetaGetTheta - Get the abscissa of the stage in (0,1] for `TSTHETA`
1286 
1287   Not Collective
1288 
1289   Input Parameter:
1290 . ts - timestepping context
1291 
1292   Output Parameter:
1293 . theta - stage abscissa
1294 
1295   Level: advanced
1296 
1297   Note:
1298   Use of this function is normally only required to hack `TSTHETA` to use a modified integration scheme.
1299 
1300 .seealso: [](ch_ts), `TSThetaSetTheta()`, `TSTHETA`
1301 @*/
1302 PetscErrorCode TSThetaGetTheta(TS ts, PetscReal *theta)
1303 {
1304   PetscFunctionBegin;
1305   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1306   PetscAssertPointer(theta, 2);
1307   PetscUseMethod(ts, "TSThetaGetTheta_C", (TS, PetscReal *), (ts, theta));
1308   PetscFunctionReturn(PETSC_SUCCESS);
1309 }
1310 
1311 /*@
1312   TSThetaSetTheta - Set the abscissa of the stage in (0,1]  for `TSTHETA`
1313 
1314   Not Collective
1315 
1316   Input Parameters:
1317 + ts    - timestepping context
1318 - theta - stage abscissa
1319 
1320   Options Database Key:
1321 . -ts_theta_theta <theta> - set theta
1322 
1323   Level: intermediate
1324 
1325 .seealso: [](ch_ts), `TSThetaGetTheta()`, `TSTHETA`, `TSCN`
1326 @*/
1327 PetscErrorCode TSThetaSetTheta(TS ts, PetscReal theta)
1328 {
1329   PetscFunctionBegin;
1330   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1331   PetscTryMethod(ts, "TSThetaSetTheta_C", (TS, PetscReal), (ts, theta));
1332   PetscFunctionReturn(PETSC_SUCCESS);
1333 }
1334 
1335 /*@
1336   TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA`
1337 
1338   Not Collective
1339 
1340   Input Parameter:
1341 . ts - timestepping context
1342 
1343   Output Parameter:
1344 . endpoint - `PETSC_TRUE` when using the endpoint variant
1345 
1346   Level: advanced
1347 
1348 .seealso: [](ch_ts), `TSThetaSetEndpoint()`, `TSTHETA`, `TSCN`
1349 @*/
1350 PetscErrorCode TSThetaGetEndpoint(TS ts, PetscBool *endpoint)
1351 {
1352   PetscFunctionBegin;
1353   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1354   PetscAssertPointer(endpoint, 2);
1355   PetscUseMethod(ts, "TSThetaGetEndpoint_C", (TS, PetscBool *), (ts, endpoint));
1356   PetscFunctionReturn(PETSC_SUCCESS);
1357 }
1358 
1359 /*@
1360   TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA`
1361 
1362   Not Collective
1363 
1364   Input Parameters:
1365 + ts  - timestepping context
1366 - flg - `PETSC_TRUE` to use the endpoint variant
1367 
1368   Options Database Key:
1369 . -ts_theta_endpoint <flg> - use the endpoint variant
1370 
1371   Level: intermediate
1372 
1373 .seealso: [](ch_ts), `TSTHETA`, `TSCN`
1374 @*/
1375 PetscErrorCode TSThetaSetEndpoint(TS ts, PetscBool flg)
1376 {
1377   PetscFunctionBegin;
1378   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1379   PetscTryMethod(ts, "TSThetaSetEndpoint_C", (TS, PetscBool), (ts, flg));
1380   PetscFunctionReturn(PETSC_SUCCESS);
1381 }
1382 
1383 /*
1384  * TSBEULER and TSCN are straightforward specializations of TSTHETA.
1385  * The creation functions for these specializations are below.
1386  */
1387 
1388 static PetscErrorCode TSSetUp_BEuler(TS ts)
1389 {
1390   TS_Theta *th = (TS_Theta *)ts->data;
1391 
1392   PetscFunctionBegin;
1393   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");
1394   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");
1395   PetscCall(TSSetUp_Theta(ts));
1396   PetscFunctionReturn(PETSC_SUCCESS);
1397 }
1398 
1399 static PetscErrorCode TSView_BEuler(TS ts, PetscViewer viewer)
1400 {
1401   PetscFunctionBegin;
1402   PetscFunctionReturn(PETSC_SUCCESS);
1403 }
1404 
1405 /*MC
1406       TSBEULER - ODE solver using the implicit backward Euler method
1407 
1408   Level: beginner
1409 
1410   Note:
1411   `TSBEULER` is equivalent to `TSTHETA` with Theta=1.0 or `-ts_type theta -ts_theta_theta 1.0`
1412 
1413 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSEULER`, `TSCN`, `TSTHETA`
1414 M*/
1415 PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts)
1416 {
1417   PetscFunctionBegin;
1418   PetscCall(TSCreate_Theta(ts));
1419   PetscCall(TSThetaSetTheta(ts, 1.0));
1420   PetscCall(TSThetaSetEndpoint(ts, PETSC_FALSE));
1421   ts->ops->setup = TSSetUp_BEuler;
1422   ts->ops->view  = TSView_BEuler;
1423   PetscFunctionReturn(PETSC_SUCCESS);
1424 }
1425 
1426 static PetscErrorCode TSSetUp_CN(TS ts)
1427 {
1428   TS_Theta *th = (TS_Theta *)ts->data;
1429 
1430   PetscFunctionBegin;
1431   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");
1432   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");
1433   PetscCall(TSSetUp_Theta(ts));
1434   PetscFunctionReturn(PETSC_SUCCESS);
1435 }
1436 
1437 static PetscErrorCode TSView_CN(TS ts, PetscViewer viewer)
1438 {
1439   PetscFunctionBegin;
1440   PetscFunctionReturn(PETSC_SUCCESS);
1441 }
1442 
1443 /*MC
1444       TSCN - ODE solver using the implicit Crank-Nicolson method.
1445 
1446   Level: beginner
1447 
1448   Notes:
1449   `TSCN` is equivalent to `TSTHETA` with Theta=0.5 and the "endpoint" option set. I.e.
1450 .vb
1451   -ts_type theta
1452   -ts_theta_theta 0.5
1453   -ts_theta_endpoint
1454 .ve
1455 
1456 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSBEULER`, `TSTHETA`, `TSType`,
1457 M*/
1458 PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts)
1459 {
1460   PetscFunctionBegin;
1461   PetscCall(TSCreate_Theta(ts));
1462   PetscCall(TSThetaSetTheta(ts, 0.5));
1463   PetscCall(TSThetaSetEndpoint(ts, PETSC_TRUE));
1464   ts->ops->setup = TSSetUp_CN;
1465   ts->ops->view  = TSView_CN;
1466   PetscFunctionReturn(PETSC_SUCCESS);
1467 }
1468