xref: /petsc/src/ts/impls/implicit/theta/theta.c (revision b41ce5d507ea9a58bfa83cf403107a702e77a67d)
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          X0,X,Xdot;                /* Storage for stages and time derivative */
13   Vec          affine;                   /* Affine vector needed for residual at beginning of step in endpoint formulation */
14   PetscReal    Theta;
15   PetscReal    ptime;
16   PetscReal    time_step;
17   PetscInt     order;
18   PetscBool    endpoint;
19   PetscBool    extrapolate;
20   TSStepStatus status;
21   Vec          VecCostIntegral0;         /* Backup for roll-backs due to events */
22 
23   /* context for sensitivity analysis */
24   PetscInt     num_tlm;                  /* Total number of tangent linear equations */
25   Vec          *VecsDeltaLam;            /* Increment of the adjoint sensitivity w.r.t IC at stage */
26   Vec          *VecsDeltaMu;             /* Increment of the adjoint sensitivity w.r.t P at stage */
27   Vec          *VecsSensiTemp;           /* Vector to be timed with Jacobian transpose */
28   Vec          *VecsDeltaFwdSensi;       /* Increment of the forward sensitivity at stage */
29   Vec          VecIntegralSensiTemp;     /* Working vector for forward integral sensitivity */
30   Vec          VecIntegralSensipTemp;    /* Working vector for forward integral sensitivity */
31   Vec          *VecsFwdSensi0;           /* backup for roll-backs due to events */
32   Vec          *VecsIntegralSensi0;      /* backup for roll-backs due to events */
33   Vec          *VecsIntegralSensip0;     /* backup for roll-backs due to events */
34 
35   /* context for error estimation */
36   Vec          vec_sol_prev;
37   Vec          vec_lte_work;
38 } TS_Theta;
39 
40 static PetscErrorCode TSThetaGetX0AndXdot(TS ts,DM dm,Vec *X0,Vec *Xdot)
41 {
42   TS_Theta       *th = (TS_Theta*)ts->data;
43   PetscErrorCode ierr;
44 
45   PetscFunctionBegin;
46   if (X0) {
47     if (dm && dm != ts->dm) {
48       ierr = DMGetNamedGlobalVector(dm,"TSTheta_X0",X0);CHKERRQ(ierr);
49     } else *X0 = ts->vec_sol;
50   }
51   if (Xdot) {
52     if (dm && dm != ts->dm) {
53       ierr = DMGetNamedGlobalVector(dm,"TSTheta_Xdot",Xdot);CHKERRQ(ierr);
54     } else *Xdot = th->Xdot;
55   }
56   PetscFunctionReturn(0);
57 }
58 
59 static PetscErrorCode TSThetaRestoreX0AndXdot(TS ts,DM dm,Vec *X0,Vec *Xdot)
60 {
61   PetscErrorCode ierr;
62 
63   PetscFunctionBegin;
64   if (X0) {
65     if (dm && dm != ts->dm) {
66       ierr = DMRestoreNamedGlobalVector(dm,"TSTheta_X0",X0);CHKERRQ(ierr);
67     }
68   }
69   if (Xdot) {
70     if (dm && dm != ts->dm) {
71       ierr = DMRestoreNamedGlobalVector(dm,"TSTheta_Xdot",Xdot);CHKERRQ(ierr);
72     }
73   }
74   PetscFunctionReturn(0);
75 }
76 
77 static PetscErrorCode DMCoarsenHook_TSTheta(DM fine,DM coarse,void *ctx)
78 {
79   PetscFunctionBegin;
80   PetscFunctionReturn(0);
81 }
82 
83 static PetscErrorCode DMRestrictHook_TSTheta(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
84 {
85   TS             ts = (TS)ctx;
86   PetscErrorCode ierr;
87   Vec            X0,Xdot,X0_c,Xdot_c;
88 
89   PetscFunctionBegin;
90   ierr = TSThetaGetX0AndXdot(ts,fine,&X0,&Xdot);CHKERRQ(ierr);
91   ierr = TSThetaGetX0AndXdot(ts,coarse,&X0_c,&Xdot_c);CHKERRQ(ierr);
92   ierr = MatRestrict(restrct,X0,X0_c);CHKERRQ(ierr);
93   ierr = MatRestrict(restrct,Xdot,Xdot_c);CHKERRQ(ierr);
94   ierr = VecPointwiseMult(X0_c,rscale,X0_c);CHKERRQ(ierr);
95   ierr = VecPointwiseMult(Xdot_c,rscale,Xdot_c);CHKERRQ(ierr);
96   ierr = TSThetaRestoreX0AndXdot(ts,fine,&X0,&Xdot);CHKERRQ(ierr);
97   ierr = TSThetaRestoreX0AndXdot(ts,coarse,&X0_c,&Xdot_c);CHKERRQ(ierr);
98   PetscFunctionReturn(0);
99 }
100 
101 static PetscErrorCode DMSubDomainHook_TSTheta(DM dm,DM subdm,void *ctx)
102 {
103   PetscFunctionBegin;
104   PetscFunctionReturn(0);
105 }
106 
107 static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
108 {
109   TS             ts = (TS)ctx;
110   PetscErrorCode ierr;
111   Vec            X0,Xdot,X0_sub,Xdot_sub;
112 
113   PetscFunctionBegin;
114   ierr = TSThetaGetX0AndXdot(ts,dm,&X0,&Xdot);CHKERRQ(ierr);
115   ierr = TSThetaGetX0AndXdot(ts,subdm,&X0_sub,&Xdot_sub);CHKERRQ(ierr);
116 
117   ierr = VecScatterBegin(gscat,X0,X0_sub,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
118   ierr = VecScatterEnd(gscat,X0,X0_sub,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
119 
120   ierr = VecScatterBegin(gscat,Xdot,Xdot_sub,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
121   ierr = VecScatterEnd(gscat,Xdot,Xdot_sub,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
122 
123   ierr = TSThetaRestoreX0AndXdot(ts,dm,&X0,&Xdot);CHKERRQ(ierr);
124   ierr = TSThetaRestoreX0AndXdot(ts,subdm,&X0_sub,&Xdot_sub);CHKERRQ(ierr);
125   PetscFunctionReturn(0);
126 }
127 
128 static PetscErrorCode TSThetaEvaluateCostIntegral(TS ts)
129 {
130   TS_Theta       *th = (TS_Theta*)ts->data;
131   PetscErrorCode ierr;
132 
133   PetscFunctionBegin;
134   if (th->endpoint) {
135     /* Evolve ts->vec_costintegral to compute integrals */
136     if (th->Theta!=1.0) {
137       ierr = TSComputeCostIntegrand(ts,th->ptime,th->X0,ts->vec_costintegrand);CHKERRQ(ierr);
138       ierr = VecAXPY(ts->vec_costintegral,th->time_step*(1.0-th->Theta),ts->vec_costintegrand);CHKERRQ(ierr);
139     }
140     ierr = TSComputeCostIntegrand(ts,ts->ptime,ts->vec_sol,ts->vec_costintegrand);CHKERRQ(ierr);
141     ierr = VecAXPY(ts->vec_costintegral,th->time_step*th->Theta,ts->vec_costintegrand);CHKERRQ(ierr);
142   } else {
143     ierr = TSComputeCostIntegrand(ts,th->stage_time,th->X,ts->vec_costintegrand);CHKERRQ(ierr);
144     ierr = VecAXPY(ts->vec_costintegral,th->time_step,ts->vec_costintegrand);CHKERRQ(ierr);
145   }
146   PetscFunctionReturn(0);
147 }
148 
149 static PetscErrorCode TSForwardCostIntegral_Theta(TS ts)
150 {
151   TS_Theta       *th = (TS_Theta*)ts->data;
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   /* backup cost integral */
156   ierr = VecCopy(ts->vec_costintegral,th->VecCostIntegral0);CHKERRQ(ierr);
157   ierr = TSThetaEvaluateCostIntegral(ts);CHKERRQ(ierr);
158   PetscFunctionReturn(0);
159 }
160 
161 static PetscErrorCode TSAdjointCostIntegral_Theta(TS ts)
162 {
163   PetscErrorCode ierr;
164 
165   PetscFunctionBegin;
166   ierr = TSThetaEvaluateCostIntegral(ts);CHKERRQ(ierr);
167   PetscFunctionReturn(0);
168 }
169 
170 static PetscErrorCode TS_SNESSolve(TS ts,Vec b,Vec x)
171 {
172   PetscInt       nits,lits;
173   PetscErrorCode ierr;
174 
175   PetscFunctionBegin;
176   ierr = SNESSolve(ts->snes,b,x);CHKERRQ(ierr);
177   ierr = SNESGetIterationNumber(ts->snes,&nits);CHKERRQ(ierr);
178   ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr);
179   ts->snes_its += nits; ts->ksp_its += lits;
180   PetscFunctionReturn(0);
181 }
182 
183 static PetscErrorCode TSStep_Theta(TS ts)
184 {
185   TS_Theta       *th = (TS_Theta*)ts->data;
186   PetscInt       rejections = 0;
187   PetscBool      stageok,accept = PETSC_TRUE;
188   PetscReal      next_time_step = ts->time_step;
189   PetscErrorCode ierr;
190 
191   PetscFunctionBegin;
192   if (!ts->steprollback) {
193     if (th->vec_sol_prev) { ierr = VecCopy(th->X0,th->vec_sol_prev);CHKERRQ(ierr); }
194     ierr = VecCopy(ts->vec_sol,th->X0);CHKERRQ(ierr);
195   }
196 
197   th->status = TS_STEP_INCOMPLETE;
198   while (!ts->reason && th->status != TS_STEP_COMPLETE) {
199 
200     PetscReal shift = 1/(th->Theta*ts->time_step);
201     th->stage_time = ts->ptime + (th->endpoint ? (PetscReal)1 : th->Theta)*ts->time_step;
202 
203     ierr = VecCopy(th->X0,th->X);CHKERRQ(ierr);
204     if (th->extrapolate && !ts->steprestart) {
205       ierr = VecAXPY(th->X,1/shift,th->Xdot);CHKERRQ(ierr);
206     }
207     if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */
208       if (!th->affine) {ierr = VecDuplicate(ts->vec_sol,&th->affine);CHKERRQ(ierr);}
209       ierr = VecZeroEntries(th->Xdot);CHKERRQ(ierr);
210       ierr = TSComputeIFunction(ts,ts->ptime,th->X0,th->Xdot,th->affine,PETSC_FALSE);CHKERRQ(ierr);
211       ierr = VecScale(th->affine,(th->Theta-1)/th->Theta);CHKERRQ(ierr);
212     } else if (th->affine) { /* Just in case th->endpoint is changed between calls to TSStep_Theta() */
213       ierr = VecZeroEntries(th->affine);CHKERRQ(ierr);
214     }
215     ierr = TSPreStage(ts,th->stage_time);CHKERRQ(ierr);
216     ierr = TS_SNESSolve(ts,th->affine,th->X);CHKERRQ(ierr);
217     ierr = TSPostStage(ts,th->stage_time,0,&th->X);CHKERRQ(ierr);
218     ierr = TSAdaptCheckStage(ts->adapt,ts,th->stage_time,th->X,&stageok);CHKERRQ(ierr);
219     if (!stageok) goto reject_step;
220 
221     th->status = TS_STEP_PENDING;
222     if (th->endpoint) {
223       ierr = VecCopy(th->X,ts->vec_sol);CHKERRQ(ierr);
224     } else {
225       ierr = VecAXPBYPCZ(th->Xdot,-shift,shift,0,th->X0,th->X);CHKERRQ(ierr);
226       ierr = VecAXPY(ts->vec_sol,ts->time_step,th->Xdot);CHKERRQ(ierr);
227     }
228     ierr = TSAdaptChoose(ts->adapt,ts,ts->time_step,NULL,&next_time_step,&accept);CHKERRQ(ierr);
229     th->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
230     if (!accept) {
231       ierr = VecCopy(th->X0,ts->vec_sol);CHKERRQ(ierr);
232       ts->time_step = next_time_step;
233       goto reject_step;
234     }
235 
236     if (ts->forward_solve || ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */
237       th->ptime     = ts->ptime;
238       th->time_step = ts->time_step;
239     }
240 
241     ts->ptime += ts->time_step;
242     ts->time_step = next_time_step;
243     break;
244 
245   reject_step:
246     ts->reject++; accept = PETSC_FALSE;
247     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
248       ts->reason = TS_DIVERGED_STEP_REJECTED;
249       ierr = PetscInfo2(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,rejections);CHKERRQ(ierr);
250     }
251   }
252   PetscFunctionReturn(0);
253 }
254 
255 static PetscErrorCode TSAdjointStep_Theta(TS ts)
256 {
257   TS_Theta            *th = (TS_Theta*)ts->data;
258   Vec                 *VecsDeltaLam = th->VecsDeltaLam,*VecsDeltaMu = th->VecsDeltaMu,*VecsSensiTemp = th->VecsSensiTemp;
259   PetscInt            nadj;
260   PetscErrorCode      ierr;
261   Mat                 J,Jp;
262   KSP                 ksp;
263   PetscReal           shift;
264 
265   PetscFunctionBegin;
266   th->status = TS_STEP_INCOMPLETE;
267   ierr = SNESGetKSP(ts->snes,&ksp);CHKERRQ(ierr);
268   ierr = TSGetIJacobian(ts,&J,&Jp,NULL,NULL);CHKERRQ(ierr);
269 
270   /* If endpoint=1, th->ptime and th->X0 will be used; if endpoint=0, th->stage_time and th->X will be used. */
271   th->stage_time = th->endpoint ? ts->ptime : (ts->ptime+(1.-th->Theta)*ts->time_step); /* time_step is negative*/
272   th->ptime      = ts->ptime + ts->time_step;
273   th->time_step  = -ts->time_step;
274 
275   /* Build RHS */
276   if (ts->vec_costintegral) { /* Cost function has an integral term */
277     if (th->endpoint) {
278       ierr = TSAdjointComputeDRDYFunction(ts,th->stage_time,ts->vec_sol,ts->vecs_drdy);CHKERRQ(ierr);
279     } else {
280       ierr = TSAdjointComputeDRDYFunction(ts,th->stage_time,th->X,ts->vecs_drdy);CHKERRQ(ierr);
281     }
282   }
283   for (nadj=0; nadj<ts->numcost; nadj++) {
284     ierr = VecCopy(ts->vecs_sensi[nadj],VecsSensiTemp[nadj]);CHKERRQ(ierr);
285     ierr = VecScale(VecsSensiTemp[nadj],1./(th->Theta*th->time_step));CHKERRQ(ierr);
286     if (ts->vec_costintegral) {
287       ierr = VecAXPY(VecsSensiTemp[nadj],1.,ts->vecs_drdy[nadj]);CHKERRQ(ierr);
288     }
289   }
290 
291   /* Build LHS */
292   shift = 1./(th->Theta*th->time_step);
293   if (th->endpoint) {
294     ierr = TSComputeIJacobian(ts,th->stage_time,ts->vec_sol,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
295   } else {
296     ierr = TSComputeIJacobian(ts,th->stage_time,th->X,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
297   }
298   ierr = KSPSetOperators(ksp,J,Jp);CHKERRQ(ierr);
299 
300   /* Solve LHS X = RHS */
301   for (nadj=0; nadj<ts->numcost; nadj++) {
302     ierr = KSPSolveTranspose(ksp,VecsSensiTemp[nadj],VecsDeltaLam[nadj]);CHKERRQ(ierr);
303   }
304 
305   /* Update sensitivities, and evaluate integrals if there is any */
306   if(th->endpoint) { /* two-stage case */
307     if (th->Theta!=1.) {
308       shift = 1./((th->Theta-1.)*th->time_step);
309       ierr  = TSComputeIJacobian(ts,th->ptime,th->X0,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
310       if (ts->vec_costintegral) {
311         ierr = TSAdjointComputeDRDYFunction(ts,th->ptime,th->X0,ts->vecs_drdy);CHKERRQ(ierr);
312       }
313       for (nadj=0; nadj<ts->numcost; nadj++) {
314         ierr = MatMultTranspose(J,VecsDeltaLam[nadj],ts->vecs_sensi[nadj]);CHKERRQ(ierr);
315         if (ts->vec_costintegral) {
316           ierr = VecAXPY(ts->vecs_sensi[nadj],-1.,ts->vecs_drdy[nadj]);CHKERRQ(ierr);
317         }
318         ierr = VecScale(ts->vecs_sensi[nadj],1./shift);CHKERRQ(ierr);
319       }
320     } else { /* backward Euler */
321       shift = 0.0;
322       ierr  = TSComputeIJacobian(ts,th->stage_time,ts->vec_sol,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr); /* get -f_y */
323       for (nadj=0; nadj<ts->numcost; nadj++) {
324         ierr = MatMultTranspose(J,VecsDeltaLam[nadj],VecsSensiTemp[nadj]);CHKERRQ(ierr);
325         ierr = VecAXPY(ts->vecs_sensi[nadj],-th->time_step,VecsSensiTemp[nadj]);CHKERRQ(ierr);
326         if (ts->vec_costintegral) {
327           ierr = VecAXPY(ts->vecs_sensi[nadj],th->time_step,ts->vecs_drdy[nadj]);CHKERRQ(ierr);
328         }
329       }
330     }
331 
332     if (ts->vecs_sensip) { /* sensitivities wrt parameters */
333       ierr = TSAdjointComputeRHSJacobian(ts,th->stage_time,ts->vec_sol,ts->Jacp);CHKERRQ(ierr);
334       for (nadj=0; nadj<ts->numcost; nadj++) {
335         ierr = MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]);CHKERRQ(ierr);
336         ierr = VecAXPY(ts->vecs_sensip[nadj],th->time_step*th->Theta,VecsDeltaMu[nadj]);CHKERRQ(ierr);
337       }
338       if (th->Theta!=1.) {
339         ierr = TSAdjointComputeRHSJacobian(ts,th->ptime,th->X0,ts->Jacp);CHKERRQ(ierr);
340         for (nadj=0; nadj<ts->numcost; nadj++) {
341           ierr = MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]);CHKERRQ(ierr);
342           ierr = VecAXPY(ts->vecs_sensip[nadj],th->time_step*(1.-th->Theta),VecsDeltaMu[nadj]);CHKERRQ(ierr);
343         }
344       }
345       if (ts->vec_costintegral) {
346         ierr = TSAdjointComputeDRDPFunction(ts,th->stage_time,ts->vec_sol,ts->vecs_drdp);CHKERRQ(ierr);
347         for (nadj=0; nadj<ts->numcost; nadj++) {
348           ierr = VecAXPY(ts->vecs_sensip[nadj],th->time_step*th->Theta,ts->vecs_drdp[nadj]);CHKERRQ(ierr);
349         }
350         if (th->Theta!=1.) {
351           ierr = TSAdjointComputeDRDPFunction(ts,th->ptime,th->X0,ts->vecs_drdp);CHKERRQ(ierr);
352           for (nadj=0; nadj<ts->numcost; nadj++) {
353             ierr = VecAXPY(ts->vecs_sensip[nadj],th->time_step*(1.-th->Theta),ts->vecs_drdp[nadj]);CHKERRQ(ierr);
354           }
355         }
356       }
357     }
358   } else { /* one-stage case */
359     shift = 0.0;
360     ierr  = TSComputeIJacobian(ts,th->stage_time,th->X,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr); /* get -f_y */
361     if (ts->vec_costintegral) {
362       ierr = TSAdjointComputeDRDYFunction(ts,th->stage_time,th->X,ts->vecs_drdy);CHKERRQ(ierr);
363     }
364     for (nadj=0; nadj<ts->numcost; nadj++) {
365       ierr = MatMultTranspose(J,VecsDeltaLam[nadj],VecsSensiTemp[nadj]);CHKERRQ(ierr);
366       ierr = VecAXPY(ts->vecs_sensi[nadj],-th->time_step,VecsSensiTemp[nadj]);CHKERRQ(ierr);
367       if (ts->vec_costintegral) {
368         ierr = VecAXPY(ts->vecs_sensi[nadj],th->time_step,ts->vecs_drdy[nadj]);CHKERRQ(ierr);
369       }
370     }
371     if (ts->vecs_sensip) {
372       ierr = TSAdjointComputeRHSJacobian(ts,th->stage_time,th->X,ts->Jacp);CHKERRQ(ierr);
373       for (nadj=0; nadj<ts->numcost; nadj++) {
374         ierr = MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]);CHKERRQ(ierr);
375         ierr = VecAXPY(ts->vecs_sensip[nadj],th->time_step,VecsDeltaMu[nadj]);CHKERRQ(ierr);
376       }
377       if (ts->vec_costintegral) {
378         ierr = TSAdjointComputeDRDPFunction(ts,th->stage_time,th->X,ts->vecs_drdp);CHKERRQ(ierr);
379         for (nadj=0; nadj<ts->numcost; nadj++) {
380           ierr = VecAXPY(ts->vecs_sensip[nadj],th->time_step,ts->vecs_drdp[nadj]);CHKERRQ(ierr);
381         }
382       }
383     }
384   }
385 
386   th->status = TS_STEP_COMPLETE;
387   PetscFunctionReturn(0);
388 }
389 
390 static PetscErrorCode TSInterpolate_Theta(TS ts,PetscReal t,Vec X)
391 {
392   TS_Theta       *th = (TS_Theta*)ts->data;
393   PetscReal      dt  = t - ts->ptime;
394   PetscErrorCode ierr;
395 
396   PetscFunctionBegin;
397   ierr = VecCopy(ts->vec_sol,th->X);CHKERRQ(ierr);
398   if (th->endpoint) dt *= th->Theta;
399   ierr = VecWAXPY(X,dt,th->Xdot,th->X);CHKERRQ(ierr);
400   PetscFunctionReturn(0);
401 }
402 
403 static PetscErrorCode TSEvaluateWLTE_Theta(TS ts,NormType wnormtype,PetscInt *order,PetscReal *wlte)
404 {
405   TS_Theta       *th = (TS_Theta*)ts->data;
406   Vec            X = ts->vec_sol;      /* X = solution */
407   Vec            Y = th->vec_lte_work; /* Y = X + LTE  */
408   PetscReal      wltea,wlter;
409   PetscErrorCode ierr;
410 
411   PetscFunctionBegin;
412   if (!th->vec_sol_prev) {*wlte = -1; PetscFunctionReturn(0);}
413   /* Cannot compute LTE in first step or in restart after event */
414   if (ts->steprestart) {*wlte = -1; PetscFunctionReturn(0);}
415   /* Compute LTE using backward differences with non-constant time step */
416   {
417     PetscReal   h = ts->time_step, h_prev = ts->ptime - ts->ptime_prev;
418     PetscReal   a = 1 + h_prev/h;
419     PetscScalar scal[3]; Vec vecs[3];
420     scal[0] = +1/a; scal[1] = -1/(a-1); scal[2] = +1/(a*(a-1));
421     vecs[0] = X;    vecs[1] = th->X0;   vecs[2] = th->vec_sol_prev;
422     ierr = VecCopy(X,Y);CHKERRQ(ierr);
423     ierr = VecMAXPY(Y,3,scal,vecs);CHKERRQ(ierr);
424     ierr = TSErrorWeightedNorm(ts,X,Y,wnormtype,wlte,&wltea,&wlter);CHKERRQ(ierr);
425   }
426   if (order) *order = 2;
427   PetscFunctionReturn(0);
428 }
429 
430 static PetscErrorCode TSRollBack_Theta(TS ts)
431 {
432   TS_Theta       *th = (TS_Theta*)ts->data;
433   PetscInt       ntlm,ncost;
434   PetscErrorCode ierr;
435 
436   PetscFunctionBegin;
437   ierr = VecCopy(th->X0,ts->vec_sol);CHKERRQ(ierr);
438   if (ts->vec_costintegral && ts->costintegralfwd) {
439     ierr = VecCopy(th->VecCostIntegral0,ts->vec_costintegral);CHKERRQ(ierr);
440   }
441   th->status = TS_STEP_INCOMPLETE;
442 
443   for (ntlm=0;ntlm<th->num_tlm;ntlm++) {
444     ierr = VecCopy(th->VecsFwdSensi0[ntlm],ts->vecs_fwdsensipacked[ntlm]);CHKERRQ(ierr);
445   }
446   if (ts->vecs_integral_sensi) {
447     for (ncost=0;ncost<ts->numcost;ncost++) {
448       ierr = VecCopy(th->VecsIntegralSensi0[ncost],ts->vecs_integral_sensi[ncost]);CHKERRQ(ierr);
449     }
450   }
451   if (ts->vecs_integral_sensip) {
452     for (ncost=0;ncost<ts->numcost;ncost++) {
453       ierr = VecCopy(th->VecsIntegralSensip0[ncost],ts->vecs_integral_sensip[ncost]);CHKERRQ(ierr);
454     }
455   }
456   PetscFunctionReturn(0);
457 }
458 
459 static PetscErrorCode TSThetaIntegrandDerivative(TS ts,PetscInt numtlm,Vec DRncostDY,Vec* s,Vec DRncostDP,Vec VecIntegrandDerivative)
460 {
461   PetscInt    ntlm,low,high;
462   PetscScalar *v;
463   PetscErrorCode ierr;
464 
465   PetscFunctionBegin;
466 
467   ierr = VecGetOwnershipRange(VecIntegrandDerivative,&low,&high);CHKERRQ(ierr);
468   ierr = VecGetArray(VecIntegrandDerivative,&v);CHKERRQ(ierr);
469   for (ntlm=low; ntlm<high; ntlm++) {
470     ierr = VecDot(DRncostDY,s[ntlm],&v[ntlm-low]);CHKERRQ(ierr);
471   }
472   ierr = VecRestoreArray(VecIntegrandDerivative,&v);CHKERRQ(ierr);
473   if (DRncostDP) {
474     ierr = VecAXPY(VecIntegrandDerivative,1.,DRncostDP);CHKERRQ(ierr);
475   }
476   PetscFunctionReturn(0);
477 }
478 
479 static PetscErrorCode TSForwardStep_Theta(TS ts)
480 {
481   TS_Theta       *th = (TS_Theta*)ts->data;
482   Vec            *VecsDeltaFwdSensi  = th->VecsDeltaFwdSensi;
483   PetscInt       ntlm,ncost,np;
484   KSP            ksp;
485   Mat            J,Jp;
486   PetscReal      shift;
487   PetscErrorCode ierr;
488 
489   PetscFunctionBegin;
490   for (ntlm=0; ntlm<th->num_tlm; ntlm++) {
491     ierr = VecCopy(ts->vecs_fwdsensipacked[ntlm],th->VecsFwdSensi0[ntlm]);CHKERRQ(ierr);
492   }
493   for (ncost=0; ncost<ts->numcost; ncost++) {
494     if (ts->vecs_integral_sensi) {
495       ierr = VecCopy(ts->vecs_integral_sensi[ncost],th->VecsIntegralSensi0[ncost]);CHKERRQ(ierr);
496     }
497     if (ts->vecs_integral_sensip) {
498       ierr = VecCopy(ts->vecs_integral_sensip[ncost],th->VecsIntegralSensip0[ncost]);CHKERRQ(ierr);
499     }
500   }
501 
502   ierr = SNESGetKSP(ts->snes,&ksp);CHKERRQ(ierr);
503   ierr = TSGetIJacobian(ts,&J,&Jp,NULL,NULL);CHKERRQ(ierr);
504 
505   /* Build RHS */
506   if (th->endpoint) { /* 2-stage method*/
507     shift = 1./((th->Theta-1.)*th->time_step);
508     ierr = TSComputeIJacobian(ts,th->ptime,th->X0,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
509 
510     for (ntlm=0; ntlm<th->num_tlm; ntlm++) {
511       ierr = MatMult(J,ts->vecs_fwdsensipacked[ntlm],VecsDeltaFwdSensi[ntlm]);CHKERRQ(ierr);
512       ierr = VecScale(VecsDeltaFwdSensi[ntlm],(th->Theta-1.)/th->Theta);CHKERRQ(ierr);
513     }
514     /* Add the f_p forcing terms */
515     ierr = TSForwardComputeRHSJacobianP(ts,th->ptime,th->X0,ts->vecs_jacp);CHKERRQ(ierr);
516     for (np=0; np<ts->num_parameters; np++) {
517       ierr = VecAXPY(VecsDeltaFwdSensi[np+ts->num_initialvalues],(1.-th->Theta)/th->Theta,ts->vecs_jacp[np]);CHKERRQ(ierr);
518     }
519     ierr = TSForwardComputeRHSJacobianP(ts,th->stage_time,ts->vec_sol,ts->vecs_jacp);CHKERRQ(ierr);
520     for (np=0; np<ts->num_parameters; np++) {
521       ierr = VecAXPY(VecsDeltaFwdSensi[np+ts->num_initialvalues],1,ts->vecs_jacp[np]);CHKERRQ(ierr);
522     }
523   } else { /* 1-stage method */
524     shift = 0.0;
525     ierr = TSComputeIJacobian(ts,th->stage_time,th->X,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
526     for (ntlm=0; ntlm<ts->num_parameters; ntlm++) {
527       ierr = MatMult(J,ts->vecs_fwdsensipacked[ntlm],VecsDeltaFwdSensi[ntlm]);CHKERRQ(ierr);
528       ierr = VecScale(VecsDeltaFwdSensi[ntlm],-1);CHKERRQ(ierr);
529     }
530     /* Add the f_p forcing terms */
531     ierr = TSForwardComputeRHSJacobianP(ts,th->stage_time,th->X,ts->vecs_jacp);CHKERRQ(ierr);
532     for (np=0; np<ts->num_parameters; np++) {
533       ierr = VecAXPY(VecsDeltaFwdSensi[np+ts->num_initialvalues],1,ts->vecs_jacp[np]);CHKERRQ(ierr);
534     }
535   }
536 
537   /* Build LHS */
538   shift = 1/(th->Theta*th->time_step);
539   if (th->endpoint) {
540     ierr  = TSComputeIJacobian(ts,th->stage_time,ts->vec_sol,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
541   } else {
542     ierr = TSComputeIJacobian(ts,th->stage_time,th->X,th->Xdot,shift,J,Jp,PETSC_FALSE);CHKERRQ(ierr);
543   }
544   ierr = KSPSetOperators(ksp,J,Jp);CHKERRQ(ierr);
545 
546   /*
547     Evaluate the first stage of integral gradients with the 2-stage method:
548     drdy|t_n*S(t_n) + drdp|t_n
549     This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1})
550     It is important to note that sensitivitesi to parameters (sensip) and sensitivities to initial values (sensi) are independent of each other, but integral sensip relies on sensip and integral sensi requires sensi
551    */
552   if (th->endpoint) { /* 2-stage method only */
553     if (ts->vecs_integral_sensi || ts->vecs_integral_sensip) {
554       ierr = TSAdjointComputeDRDYFunction(ts,th->ptime,th->X0,ts->vecs_drdy);CHKERRQ(ierr);
555     }
556     if (ts->vecs_integral_sensip) {
557       ierr = TSAdjointComputeDRDPFunction(ts,th->ptime,th->X0,ts->vecs_drdp);CHKERRQ(ierr);
558       for (ncost=0; ncost<ts->numcost; ncost++) {
559         ierr = TSThetaIntegrandDerivative(ts,ts->num_parameters,ts->vecs_drdy[ncost],&ts->vecs_fwdsensipacked[ts->num_initialvalues],ts->vecs_drdp[ncost],th->VecIntegralSensipTemp);CHKERRQ(ierr);
560         ierr = VecAXPY(ts->vecs_integral_sensip[ncost],th->time_step*(1.-th->Theta),th->VecIntegralSensipTemp);CHKERRQ(ierr);
561       }
562     }
563     if (ts->vecs_integral_sensi) {
564       for (ncost=0; ncost<ts->numcost; ncost++) {
565         ierr = TSThetaIntegrandDerivative(ts,ts->num_initialvalues,ts->vecs_drdy[ncost],ts->vecs_fwdsensipacked,NULL,th->VecIntegralSensiTemp);CHKERRQ(ierr);
566         ierr = VecAXPY(ts->vecs_integral_sensi[ncost],th->time_step*(1.-th->Theta),th->VecIntegralSensiTemp);CHKERRQ(ierr);
567       }
568     }
569   }
570 
571   /* Solve the tangent linear equation for forward sensitivities to parameters */
572   for (ntlm=0; ntlm<th->num_tlm; ntlm++) {
573     if (th->endpoint) {
574       ierr = KSPSolve(ksp,VecsDeltaFwdSensi[ntlm],ts->vecs_fwdsensipacked[ntlm]);CHKERRQ(ierr);
575     } else {
576       ierr = KSPSolve(ksp,VecsDeltaFwdSensi[ntlm],VecsDeltaFwdSensi[ntlm]);CHKERRQ(ierr);
577       ierr = VecAXPY(ts->vecs_fwdsensipacked[ntlm],1.,VecsDeltaFwdSensi[ntlm]);CHKERRQ(ierr);
578     }
579   }
580   /* Evaluate the second stage of integral gradients with the 2-stage method:
581     drdy|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1}
582   */
583   if (ts->vecs_integral_sensi || ts->vecs_integral_sensip) {
584     ierr = TSAdjointComputeDRDYFunction(ts,th->stage_time,th->X,ts->vecs_drdy);CHKERRQ(ierr);
585   }
586   if (ts->vecs_integral_sensip) {
587     ierr = TSAdjointComputeDRDPFunction(ts,th->stage_time,th->X,ts->vecs_drdp);CHKERRQ(ierr);
588     for (ncost=0; ncost<ts->numcost; ncost++) {
589       ierr = TSThetaIntegrandDerivative(ts,ts->num_parameters,ts->vecs_drdy[ncost],&ts->vecs_fwdsensipacked[ts->num_initialvalues],ts->vecs_drdp[ncost],th->VecIntegralSensipTemp);CHKERRQ(ierr);
590       if (th->endpoint) {
591         ierr = VecAXPY(ts->vecs_integral_sensip[ncost],th->time_step*th->Theta,th->VecIntegralSensipTemp);CHKERRQ(ierr);
592       } else {
593         ierr = VecAXPY(ts->vecs_integral_sensip[ncost],th->time_step,th->VecIntegralSensipTemp);CHKERRQ(ierr);
594       }
595     }
596   }
597   if (ts->vecs_integral_sensi) {
598     for (ncost=0; ncost<ts->numcost; ncost++) {
599       ierr = TSThetaIntegrandDerivative(ts,ts->num_initialvalues,ts->vecs_drdy[ncost],ts->vecs_fwdsensipacked,NULL,th->VecIntegralSensiTemp);CHKERRQ(ierr);
600       if (th->endpoint) {
601         ierr = VecAXPY(ts->vecs_integral_sensi[ncost],th->time_step*th->Theta,th->VecIntegralSensiTemp);CHKERRQ(ierr);
602       } else {
603         ierr = VecAXPY(ts->vecs_integral_sensi[ncost],th->time_step,th->VecIntegralSensiTemp);CHKERRQ(ierr);
604       }
605     }
606   }
607 
608   if (!th->endpoint) { /* VecsDeltaFwdSensip are the increment for the stage values for the 1-stage method */
609     for (ntlm=0; ntlm<th->num_tlm; ntlm++) {
610       ierr = VecAXPY(ts->vecs_fwdsensipacked[ntlm],(1.-th->Theta)/th->Theta,VecsDeltaFwdSensi[ntlm]);CHKERRQ(ierr);
611     }
612   }
613   PetscFunctionReturn(0);
614 }
615 
616 /*------------------------------------------------------------*/
617 static PetscErrorCode TSReset_Theta(TS ts)
618 {
619   TS_Theta       *th = (TS_Theta*)ts->data;
620   PetscErrorCode ierr;
621 
622   PetscFunctionBegin;
623   ierr = VecDestroy(&th->X);CHKERRQ(ierr);
624   ierr = VecDestroy(&th->Xdot);CHKERRQ(ierr);
625   ierr = VecDestroy(&th->X0);CHKERRQ(ierr);
626   ierr = VecDestroy(&th->affine);CHKERRQ(ierr);
627 
628   ierr = VecDestroy(&th->vec_sol_prev);CHKERRQ(ierr);
629   ierr = VecDestroy(&th->vec_lte_work);CHKERRQ(ierr);
630 
631   ierr = VecDestroy(&th->VecCostIntegral0);CHKERRQ(ierr);
632   if (ts->forward_solve) {
633     ierr = VecDestroyVecs(th->num_tlm,&th->VecsDeltaFwdSensi);CHKERRQ(ierr);
634     ierr = VecDestroyVecs(th->num_tlm,&th->VecsFwdSensi0);CHKERRQ(ierr);
635     if (ts->vecs_integral_sensi) {
636       ierr = VecDestroy(&th->VecIntegralSensiTemp);CHKERRQ(ierr);
637       ierr = VecDestroyVecs(ts->numcost,&th->VecsIntegralSensi0);CHKERRQ(ierr);
638     }
639     if (ts->vecs_integral_sensip) {
640       ierr = VecDestroy(&th->VecIntegralSensipTemp);CHKERRQ(ierr);
641       ierr = VecDestroyVecs(ts->numcost,&th->VecsIntegralSensip0);CHKERRQ(ierr);
642     }
643   }
644   ierr = VecDestroyVecs(ts->numcost,&th->VecsDeltaLam);CHKERRQ(ierr);
645   ierr = VecDestroyVecs(ts->numcost,&th->VecsDeltaMu);CHKERRQ(ierr);
646   ierr = VecDestroyVecs(ts->numcost,&th->VecsSensiTemp);CHKERRQ(ierr);
647 
648   PetscFunctionReturn(0);
649 }
650 
651 static PetscErrorCode TSDestroy_Theta(TS ts)
652 {
653   PetscErrorCode ierr;
654 
655   PetscFunctionBegin;
656   ierr = TSReset_Theta(ts);CHKERRQ(ierr);
657   ierr = PetscFree(ts->data);CHKERRQ(ierr);
658   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetTheta_C",NULL);CHKERRQ(ierr);
659   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetTheta_C",NULL);CHKERRQ(ierr);
660   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetEndpoint_C",NULL);CHKERRQ(ierr);
661   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetEndpoint_C",NULL);CHKERRQ(ierr);
662   PetscFunctionReturn(0);
663 }
664 
665 /*
666   This defines the nonlinear equation that is to be solved with SNES
667   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
668 */
669 static PetscErrorCode SNESTSFormFunction_Theta(SNES snes,Vec x,Vec y,TS ts)
670 {
671   TS_Theta       *th = (TS_Theta*)ts->data;
672   PetscErrorCode ierr;
673   Vec            X0,Xdot;
674   DM             dm,dmsave;
675   PetscReal      shift = 1/(th->Theta*ts->time_step);
676 
677   PetscFunctionBegin;
678   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
679   /* When using the endpoint variant, this is actually 1/Theta * Xdot */
680   ierr = TSThetaGetX0AndXdot(ts,dm,&X0,&Xdot);CHKERRQ(ierr);
681   ierr = VecAXPBYPCZ(Xdot,-shift,shift,0,X0,x);CHKERRQ(ierr);
682 
683   /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
684   dmsave = ts->dm;
685   ts->dm = dm;
686   ierr   = TSComputeIFunction(ts,th->stage_time,x,Xdot,y,PETSC_FALSE);CHKERRQ(ierr);
687   ts->dm = dmsave;
688   ierr   = TSThetaRestoreX0AndXdot(ts,dm,&X0,&Xdot);CHKERRQ(ierr);
689   PetscFunctionReturn(0);
690 }
691 
692 static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes,Vec x,Mat A,Mat B,TS ts)
693 {
694   TS_Theta       *th = (TS_Theta*)ts->data;
695   PetscErrorCode ierr;
696   Vec            Xdot;
697   DM             dm,dmsave;
698   PetscReal      shift = 1/(th->Theta*ts->time_step);
699 
700   PetscFunctionBegin;
701   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
702   /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */
703   ierr = TSThetaGetX0AndXdot(ts,dm,NULL,&Xdot);CHKERRQ(ierr);
704 
705   dmsave = ts->dm;
706   ts->dm = dm;
707   ierr   = TSComputeIJacobian(ts,th->stage_time,x,Xdot,shift,A,B,PETSC_FALSE);CHKERRQ(ierr);
708   ts->dm = dmsave;
709   ierr   = TSThetaRestoreX0AndXdot(ts,dm,NULL,&Xdot);CHKERRQ(ierr);
710   PetscFunctionReturn(0);
711 }
712 
713 static PetscErrorCode TSForwardSetUp_Theta(TS ts)
714 {
715   TS_Theta       *th = (TS_Theta*)ts->data;
716   PetscErrorCode ierr;
717 
718   PetscFunctionBegin;
719   /* combine sensitivities to parameters and sensitivities to initial values into one array */
720   th->num_tlm = ts->num_parameters + ts->num_initialvalues;
721   ierr = VecDuplicateVecs(ts->vecs_fwdsensipacked[0],th->num_tlm,&th->VecsDeltaFwdSensi);CHKERRQ(ierr);
722   if (ts->vecs_integral_sensi) {
723     ierr = VecDuplicate(ts->vecs_integral_sensi[0],&th->VecIntegralSensiTemp);CHKERRQ(ierr);
724   }
725   if (ts->vecs_integral_sensip) {
726     ierr = VecDuplicate(ts->vecs_integral_sensip[0],&th->VecIntegralSensipTemp);CHKERRQ(ierr);
727   }
728   /* backup sensitivity results for roll-backs */
729   ierr = VecDuplicateVecs(ts->vecs_fwdsensipacked[0],th->num_tlm,&th->VecsFwdSensi0);CHKERRQ(ierr);
730   if (ts->vecs_integral_sensi) {
731     ierr = VecDuplicateVecs(ts->vecs_integral_sensi[0],ts->numcost,&th->VecsIntegralSensi0);CHKERRQ(ierr);
732   }
733   if (ts->vecs_integral_sensip) {
734     ierr = VecDuplicateVecs(ts->vecs_integral_sensip[0],ts->numcost,&th->VecsIntegralSensip0);CHKERRQ(ierr);
735   }
736   PetscFunctionReturn(0);
737 }
738 
739 static PetscErrorCode TSSetUp_Theta(TS ts)
740 {
741   TS_Theta       *th = (TS_Theta*)ts->data;
742   PetscBool      match;
743   PetscErrorCode ierr;
744 
745   PetscFunctionBegin;
746   if (!th->VecCostIntegral0 && ts->vec_costintegral && ts->costintegralfwd) { /* back up cost integral */
747     ierr = VecDuplicate(ts->vec_costintegral,&th->VecCostIntegral0);CHKERRQ(ierr);
748   }
749   if (!th->X) {
750     ierr = VecDuplicate(ts->vec_sol,&th->X);CHKERRQ(ierr);
751   }
752   if (!th->Xdot) {
753     ierr = VecDuplicate(ts->vec_sol,&th->Xdot);CHKERRQ(ierr);
754   }
755   if (!th->X0) {
756     ierr = VecDuplicate(ts->vec_sol,&th->X0);CHKERRQ(ierr);
757   }
758   if (th->endpoint) {
759     ierr = VecDuplicate(ts->vec_sol,&th->affine);CHKERRQ(ierr);
760   }
761 
762   th->order = (th->Theta == 0.5) ? 2 : 1;
763 
764   ierr = TSGetDM(ts,&ts->dm);CHKERRQ(ierr);
765   ierr = DMCoarsenHookAdd(ts->dm,DMCoarsenHook_TSTheta,DMRestrictHook_TSTheta,ts);CHKERRQ(ierr);
766   ierr = DMSubDomainHookAdd(ts->dm,DMSubDomainHook_TSTheta,DMSubDomainRestrictHook_TSTheta,ts);CHKERRQ(ierr);
767 
768   ierr = TSGetAdapt(ts,&ts->adapt);CHKERRQ(ierr);
769   ierr = TSAdaptCandidatesClear(ts->adapt);CHKERRQ(ierr);
770   ierr = PetscObjectTypeCompare((PetscObject)ts->adapt,TSADAPTNONE,&match);CHKERRQ(ierr);
771   if (!match) {
772     ierr = VecDuplicate(ts->vec_sol,&th->vec_sol_prev);CHKERRQ(ierr);
773     ierr = VecDuplicate(ts->vec_sol,&th->vec_lte_work);CHKERRQ(ierr);
774   }
775   ierr = TSGetSNES(ts,&ts->snes);CHKERRQ(ierr);
776   PetscFunctionReturn(0);
777 }
778 
779 /*------------------------------------------------------------*/
780 
781 static PetscErrorCode TSAdjointSetUp_Theta(TS ts)
782 {
783   TS_Theta       *th = (TS_Theta*)ts->data;
784   PetscErrorCode ierr;
785 
786   PetscFunctionBegin;
787   ierr = VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&th->VecsDeltaLam);CHKERRQ(ierr);
788   if(ts->vecs_sensip) {
789     ierr = VecDuplicateVecs(ts->vecs_sensip[0],ts->numcost,&th->VecsDeltaMu);CHKERRQ(ierr);
790   }
791   ierr = VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&th->VecsSensiTemp);CHKERRQ(ierr);
792   PetscFunctionReturn(0);
793 }
794 
795 static PetscErrorCode TSSetFromOptions_Theta(PetscOptionItems *PetscOptionsObject,TS ts)
796 {
797   TS_Theta       *th = (TS_Theta*)ts->data;
798   PetscErrorCode ierr;
799 
800   PetscFunctionBegin;
801   ierr = PetscOptionsHead(PetscOptionsObject,"Theta ODE solver options");CHKERRQ(ierr);
802   {
803     ierr = PetscOptionsReal("-ts_theta_theta","Location of stage (0<Theta<=1)","TSThetaSetTheta",th->Theta,&th->Theta,NULL);CHKERRQ(ierr);
804     ierr = PetscOptionsBool("-ts_theta_endpoint","Use the endpoint instead of midpoint form of the Theta method","TSThetaSetEndpoint",th->endpoint,&th->endpoint,NULL);CHKERRQ(ierr);
805     ierr = PetscOptionsBool("-ts_theta_initial_guess_extrapolate","Extrapolate stage initial guess from previous solution (sometimes unstable)","TSThetaSetExtrapolate",th->extrapolate,&th->extrapolate,NULL);CHKERRQ(ierr);
806   }
807   ierr = PetscOptionsTail();CHKERRQ(ierr);
808   PetscFunctionReturn(0);
809 }
810 
811 static PetscErrorCode TSView_Theta(TS ts,PetscViewer viewer)
812 {
813   TS_Theta       *th = (TS_Theta*)ts->data;
814   PetscBool      iascii;
815   PetscErrorCode ierr;
816 
817   PetscFunctionBegin;
818   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
819   if (iascii) {
820     ierr = PetscViewerASCIIPrintf(viewer,"  Theta=%g\n",(double)th->Theta);CHKERRQ(ierr);
821     ierr = PetscViewerASCIIPrintf(viewer,"  Extrapolation=%s\n",th->extrapolate ? "yes" : "no");CHKERRQ(ierr);
822   }
823   PetscFunctionReturn(0);
824 }
825 
826 static PetscErrorCode TSThetaGetTheta_Theta(TS ts,PetscReal *theta)
827 {
828   TS_Theta *th = (TS_Theta*)ts->data;
829 
830   PetscFunctionBegin;
831   *theta = th->Theta;
832   PetscFunctionReturn(0);
833 }
834 
835 static PetscErrorCode TSThetaSetTheta_Theta(TS ts,PetscReal theta)
836 {
837   TS_Theta *th = (TS_Theta*)ts->data;
838 
839   PetscFunctionBegin;
840   if (theta <= 0 || 1 < theta) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Theta %g not in range (0,1]",(double)theta);
841   th->Theta = theta;
842   th->order = (th->Theta == 0.5) ? 2 : 1;
843   PetscFunctionReturn(0);
844 }
845 
846 static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts,PetscBool *endpoint)
847 {
848   TS_Theta *th = (TS_Theta*)ts->data;
849 
850   PetscFunctionBegin;
851   *endpoint = th->endpoint;
852   PetscFunctionReturn(0);
853 }
854 
855 static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts,PetscBool flg)
856 {
857   TS_Theta *th = (TS_Theta*)ts->data;
858 
859   PetscFunctionBegin;
860   th->endpoint = flg;
861   PetscFunctionReturn(0);
862 }
863 
864 #if defined(PETSC_HAVE_COMPLEX)
865 static PetscErrorCode TSComputeLinearStability_Theta(TS ts,PetscReal xr,PetscReal xi,PetscReal *yr,PetscReal *yi)
866 {
867   PetscComplex   z   = xr + xi*PETSC_i,f;
868   TS_Theta       *th = (TS_Theta*)ts->data;
869   const PetscReal one = 1.0;
870 
871   PetscFunctionBegin;
872   f   = (one + (one - th->Theta)*z)/(one - th->Theta*z);
873   *yr = PetscRealPartComplex(f);
874   *yi = PetscImaginaryPartComplex(f);
875   PetscFunctionReturn(0);
876 }
877 #endif
878 
879 static PetscErrorCode TSGetStages_Theta(TS ts,PetscInt *ns,Vec **Y)
880 {
881   TS_Theta     *th = (TS_Theta*)ts->data;
882 
883   PetscFunctionBegin;
884   if (ns) *ns = 1;
885   if (Y)  *Y  = th->endpoint ? &(th->X0) : &(th->X);
886   PetscFunctionReturn(0);
887 }
888 
889 /* ------------------------------------------------------------ */
890 /*MC
891       TSTHETA - DAE solver using the implicit Theta method
892 
893    Level: beginner
894 
895    Options Database:
896 +  -ts_theta_theta <Theta> - Location of stage (0<Theta<=1)
897 .  -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method
898 -  -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable)
899 
900    Notes:
901 $  -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER)
902 $  -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule
903 $  -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN)
904 
905    This method can be applied to DAE.
906 
907    This method is cast as a 1-stage implicit Runge-Kutta method.
908 
909 .vb
910   Theta | Theta
911   -------------
912         |  1
913 .ve
914 
915    For the default Theta=0.5, this is also known as the implicit midpoint rule.
916 
917    When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit:
918 
919 .vb
920   0 | 0         0
921   1 | 1-Theta   Theta
922   -------------------
923     | 1-Theta   Theta
924 .ve
925 
926    For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN).
927 
928    To apply a diagonally implicit RK method to DAE, the stage formula
929 
930 $  Y_i = X + h sum_j a_ij Y'_j
931 
932    is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i)
933 
934 .seealso:  TSCreate(), TS, TSSetType(), TSCN, TSBEULER, TSThetaSetTheta(), TSThetaSetEndpoint()
935 
936 M*/
937 PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts)
938 {
939   TS_Theta       *th;
940   PetscErrorCode ierr;
941 
942   PetscFunctionBegin;
943   ts->ops->reset           = TSReset_Theta;
944   ts->ops->destroy         = TSDestroy_Theta;
945   ts->ops->view            = TSView_Theta;
946   ts->ops->setup           = TSSetUp_Theta;
947   ts->ops->adjointsetup    = TSAdjointSetUp_Theta;
948   ts->ops->step            = TSStep_Theta;
949   ts->ops->interpolate     = TSInterpolate_Theta;
950   ts->ops->evaluatewlte    = TSEvaluateWLTE_Theta;
951   ts->ops->rollback        = TSRollBack_Theta;
952   ts->ops->setfromoptions  = TSSetFromOptions_Theta;
953   ts->ops->snesfunction    = SNESTSFormFunction_Theta;
954   ts->ops->snesjacobian    = SNESTSFormJacobian_Theta;
955 #if defined(PETSC_HAVE_COMPLEX)
956   ts->ops->linearstability = TSComputeLinearStability_Theta;
957 #endif
958   ts->ops->getstages       = TSGetStages_Theta;
959   ts->ops->adjointstep     = TSAdjointStep_Theta;
960   ts->ops->adjointintegral = TSAdjointCostIntegral_Theta;
961   ts->ops->forwardintegral = TSForwardCostIntegral_Theta;
962   ts->default_adapt_type   = TSADAPTNONE;
963   ts->ops->forwardsetup    = TSForwardSetUp_Theta;
964   ts->ops->forwardstep     = TSForwardStep_Theta;
965 
966   ts->usessnes = PETSC_TRUE;
967 
968   ierr = PetscNewLog(ts,&th);CHKERRQ(ierr);
969   ts->data = (void*)th;
970 
971   th->VecsDeltaLam   = NULL;
972   th->VecsDeltaMu    = NULL;
973   th->VecsSensiTemp  = NULL;
974 
975   th->extrapolate = PETSC_FALSE;
976   th->Theta       = 0.5;
977   th->order       = 2;
978   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetTheta_C",TSThetaGetTheta_Theta);CHKERRQ(ierr);
979   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetTheta_C",TSThetaSetTheta_Theta);CHKERRQ(ierr);
980   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetEndpoint_C",TSThetaGetEndpoint_Theta);CHKERRQ(ierr);
981   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetEndpoint_C",TSThetaSetEndpoint_Theta);CHKERRQ(ierr);
982   PetscFunctionReturn(0);
983 }
984 
985 /*@
986   TSThetaGetTheta - Get the abscissa of the stage in (0,1].
987 
988   Not Collective
989 
990   Input Parameter:
991 .  ts - timestepping context
992 
993   Output Parameter:
994 .  theta - stage abscissa
995 
996   Note:
997   Use of this function is normally only required to hack TSTHETA to use a modified integration scheme.
998 
999   Level: Advanced
1000 
1001 .seealso: TSThetaSetTheta()
1002 @*/
1003 PetscErrorCode  TSThetaGetTheta(TS ts,PetscReal *theta)
1004 {
1005   PetscErrorCode ierr;
1006 
1007   PetscFunctionBegin;
1008   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1009   PetscValidPointer(theta,2);
1010   ierr = PetscUseMethod(ts,"TSThetaGetTheta_C",(TS,PetscReal*),(ts,theta));CHKERRQ(ierr);
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 /*@
1015   TSThetaSetTheta - Set the abscissa of the stage in (0,1].
1016 
1017   Not Collective
1018 
1019   Input Parameter:
1020 +  ts - timestepping context
1021 -  theta - stage abscissa
1022 
1023   Options Database:
1024 .  -ts_theta_theta <theta>
1025 
1026   Level: Intermediate
1027 
1028 .seealso: TSThetaGetTheta()
1029 @*/
1030 PetscErrorCode  TSThetaSetTheta(TS ts,PetscReal theta)
1031 {
1032   PetscErrorCode ierr;
1033 
1034   PetscFunctionBegin;
1035   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1036   ierr = PetscTryMethod(ts,"TSThetaSetTheta_C",(TS,PetscReal),(ts,theta));CHKERRQ(ierr);
1037   PetscFunctionReturn(0);
1038 }
1039 
1040 /*@
1041   TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule).
1042 
1043   Not Collective
1044 
1045   Input Parameter:
1046 .  ts - timestepping context
1047 
1048   Output Parameter:
1049 .  endpoint - PETSC_TRUE when using the endpoint variant
1050 
1051   Level: Advanced
1052 
1053 .seealso: TSThetaSetEndpoint(), TSTHETA, TSCN
1054 @*/
1055 PetscErrorCode TSThetaGetEndpoint(TS ts,PetscBool *endpoint)
1056 {
1057   PetscErrorCode ierr;
1058 
1059   PetscFunctionBegin;
1060   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1061   PetscValidPointer(endpoint,2);
1062   ierr = PetscUseMethod(ts,"TSThetaGetEndpoint_C",(TS,PetscBool*),(ts,endpoint));CHKERRQ(ierr);
1063   PetscFunctionReturn(0);
1064 }
1065 
1066 /*@
1067   TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule).
1068 
1069   Not Collective
1070 
1071   Input Parameter:
1072 +  ts - timestepping context
1073 -  flg - PETSC_TRUE to use the endpoint variant
1074 
1075   Options Database:
1076 .  -ts_theta_endpoint <flg>
1077 
1078   Level: Intermediate
1079 
1080 .seealso: TSTHETA, TSCN
1081 @*/
1082 PetscErrorCode TSThetaSetEndpoint(TS ts,PetscBool flg)
1083 {
1084   PetscErrorCode ierr;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1088   ierr = PetscTryMethod(ts,"TSThetaSetEndpoint_C",(TS,PetscBool),(ts,flg));CHKERRQ(ierr);
1089   PetscFunctionReturn(0);
1090 }
1091 
1092 /*
1093  * TSBEULER and TSCN are straightforward specializations of TSTHETA.
1094  * The creation functions for these specializations are below.
1095  */
1096 
1097 static PetscErrorCode TSSetUp_BEuler(TS ts)
1098 {
1099   TS_Theta       *th = (TS_Theta*)ts->data;
1100   PetscErrorCode ierr;
1101 
1102   PetscFunctionBegin;
1103   if (th->Theta != 1.0) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change the default value (1) of theta when using backward Euler\n");
1104   if (th->endpoint) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change to the endpoint form of the Theta methods when using backward Euler\n");
1105   ierr = TSSetUp_Theta(ts);CHKERRQ(ierr);
1106   PetscFunctionReturn(0);
1107 }
1108 
1109 static PetscErrorCode TSView_BEuler(TS ts,PetscViewer viewer)
1110 {
1111   PetscFunctionBegin;
1112   PetscFunctionReturn(0);
1113 }
1114 
1115 /*MC
1116       TSBEULER - ODE solver using the implicit backward Euler method
1117 
1118   Level: beginner
1119 
1120   Notes:
1121   TSBEULER is equivalent to TSTHETA with Theta=1.0
1122 
1123 $  -ts_type theta -ts_theta_theta 1.0
1124 
1125 .seealso:  TSCreate(), TS, TSSetType(), TSEULER, TSCN, TSTHETA
1126 
1127 M*/
1128 PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts)
1129 {
1130   PetscErrorCode ierr;
1131 
1132   PetscFunctionBegin;
1133   ierr = TSCreate_Theta(ts);CHKERRQ(ierr);
1134   ierr = TSThetaSetTheta(ts,1.0);CHKERRQ(ierr);
1135   ierr = TSThetaSetEndpoint(ts,PETSC_FALSE);CHKERRQ(ierr);
1136   ts->ops->setup = TSSetUp_BEuler;
1137   ts->ops->view  = TSView_BEuler;
1138   PetscFunctionReturn(0);
1139 }
1140 
1141 static PetscErrorCode TSSetUp_CN(TS ts)
1142 {
1143   TS_Theta       *th = (TS_Theta*)ts->data;
1144   PetscErrorCode ierr;
1145 
1146   PetscFunctionBegin;
1147   if (th->Theta != 0.5) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change the default value (0.5) of theta when using Crank-Nicolson\n");
1148   if (!th->endpoint) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change to the midpoint form of the Theta methods when using Crank-Nicolson\n");
1149   ierr = TSSetUp_Theta(ts);CHKERRQ(ierr);
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 static PetscErrorCode TSView_CN(TS ts,PetscViewer viewer)
1154 {
1155   PetscFunctionBegin;
1156   PetscFunctionReturn(0);
1157 }
1158 
1159 /*MC
1160       TSCN - ODE solver using the implicit Crank-Nicolson method.
1161 
1162   Level: beginner
1163 
1164   Notes:
1165   TSCN is equivalent to TSTHETA with Theta=0.5 and the "endpoint" option set. I.e.
1166 
1167 $  -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint
1168 
1169 .seealso:  TSCreate(), TS, TSSetType(), TSBEULER, TSTHETA
1170 
1171 M*/
1172 PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts)
1173 {
1174   PetscErrorCode ierr;
1175 
1176   PetscFunctionBegin;
1177   ierr = TSCreate_Theta(ts);CHKERRQ(ierr);
1178   ierr = TSThetaSetTheta(ts,0.5);CHKERRQ(ierr);
1179   ierr = TSThetaSetEndpoint(ts,PETSC_TRUE);CHKERRQ(ierr);
1180   ts->ops->setup = TSSetUp_CN;
1181   ts->ops->view  = TSView_CN;
1182   PetscFunctionReturn(0);
1183 }
1184