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