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