xref: /petsc/src/ts/impls/implicit/theta/theta.c (revision 28b400f66ebc7ae0049166a2294dfcd3df27e64b)
1316643e7SJed Brown /*
2316643e7SJed Brown   Code for timestepping with implicit Theta method
3316643e7SJed Brown */
4af0996ceSBarry Smith #include <petsc/private/tsimpl.h>                /*I   "petscts.h"   I*/
5a055c8caSBarry Smith #include <petscsnes.h>
61e25c274SJed Brown #include <petscdm.h>
73c54f92cSHong Zhang #include <petscmat.h>
8316643e7SJed Brown 
9316643e7SJed Brown typedef struct {
10715f1b00SHong Zhang   /* context for time stepping */
111566a47fSLisandro Dalcin   PetscReal    stage_time;
12cc4f23bcSHong Zhang   Vec          Stages[2];                 /* Storage for stage solutions */
13cc4f23bcSHong Zhang   Vec          X0,X,Xdot;                /* Storage for u^n, u^n + dt a_{11} k_1, and time derivative u^{n+1}_t */
141566a47fSLisandro Dalcin   Vec          affine;                   /* Affine vector needed for residual at beginning of step in endpoint formulation */
151566a47fSLisandro Dalcin   PetscReal    Theta;
161a352fa8SHong Zhang   PetscReal    shift;                    /* Shift parameter for SNES Jacobian, used by forward, TLM and adjoint */
171566a47fSLisandro Dalcin   PetscInt     order;
181566a47fSLisandro Dalcin   PetscBool    endpoint;
191566a47fSLisandro Dalcin   PetscBool    extrapolate;
20715f1b00SHong Zhang   TSStepStatus status;
211a352fa8SHong Zhang   Vec          VecCostIntegral0;         /* Backup for roll-backs due to events, used by cost integral */
221a352fa8SHong Zhang   PetscReal    ptime0;                   /* Backup for ts->ptime, the start time of current time step, used by TLM and cost integral */
231a352fa8SHong Zhang   PetscReal    time_step0;               /* Backup for ts->timestep, the step size of current time step, used by TLM and cost integral*/
241566a47fSLisandro Dalcin 
25715f1b00SHong Zhang   /* context for sensitivity analysis */
26022c081aSHong Zhang   PetscInt     num_tlm;                  /* Total number of tangent linear equations */
27b5e0532dSHong Zhang   Vec          *VecsDeltaLam;            /* Increment of the adjoint sensitivity w.r.t IC at stage */
28b5e0532dSHong Zhang   Vec          *VecsDeltaMu;             /* Increment of the adjoint sensitivity w.r.t P at stage */
2913b1b0ffSHong Zhang   Vec          *VecsSensiTemp;           /* Vector to be multiplied with Jacobian transpose */
30cc4f23bcSHong Zhang   Mat          MatFwdStages[2];          /* TLM Stages */
3113b1b0ffSHong Zhang   Mat          MatDeltaFwdSensip;        /* Increment of the forward sensitivity at stage */
32b5b4017aSHong Zhang   Vec          VecDeltaFwdSensipCol;     /* Working vector for holding one column of the sensitivity matrix */
3313b1b0ffSHong Zhang   Mat          MatFwdSensip0;            /* backup for roll-backs due to events */
347207e0fdSHong Zhang   Mat          MatIntegralSensipTemp;    /* Working vector for forward integral sensitivity */
357207e0fdSHong Zhang   Mat          MatIntegralSensip0;       /* backup for roll-backs due to events */
36b5b4017aSHong Zhang   Vec          *VecsDeltaLam2;           /* Increment of the 2nd-order adjoint sensitivity w.r.t IC at stage */
37b5b4017aSHong Zhang   Vec          *VecsDeltaMu2;            /* Increment of the 2nd-order adjoint sensitivity w.r.t P at stage */
38b5b4017aSHong Zhang   Vec          *VecsSensi2Temp;          /* Working vectors that holds the residual for the second-order adjoint */
39b5b4017aSHong Zhang   Vec          *VecsAffine;              /* Working vectors to store residuals */
40715f1b00SHong Zhang   /* context for error estimation */
411566a47fSLisandro Dalcin   Vec          vec_sol_prev;
421566a47fSLisandro Dalcin   Vec          vec_lte_work;
43316643e7SJed Brown } TS_Theta;
44316643e7SJed Brown 
457445fe48SJed Brown static PetscErrorCode TSThetaGetX0AndXdot(TS ts,DM dm,Vec *X0,Vec *Xdot)
467445fe48SJed Brown {
477445fe48SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
487445fe48SJed Brown 
497445fe48SJed Brown   PetscFunctionBegin;
507445fe48SJed Brown   if (X0) {
517445fe48SJed Brown     if (dm && dm != ts->dm) {
525f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetNamedGlobalVector(dm,"TSTheta_X0",X0));
537445fe48SJed Brown     } else *X0 = ts->vec_sol;
547445fe48SJed Brown   }
557445fe48SJed Brown   if (Xdot) {
567445fe48SJed Brown     if (dm && dm != ts->dm) {
575f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetNamedGlobalVector(dm,"TSTheta_Xdot",Xdot));
587445fe48SJed Brown     } else *Xdot = th->Xdot;
597445fe48SJed Brown   }
607445fe48SJed Brown   PetscFunctionReturn(0);
617445fe48SJed Brown }
627445fe48SJed Brown 
630d0b770aSPeter Brune static PetscErrorCode TSThetaRestoreX0AndXdot(TS ts,DM dm,Vec *X0,Vec *Xdot)
640d0b770aSPeter Brune {
650d0b770aSPeter Brune   PetscFunctionBegin;
660d0b770aSPeter Brune   if (X0) {
670d0b770aSPeter Brune     if (dm && dm != ts->dm) {
685f80ce2aSJacob Faibussowitsch       CHKERRQ(DMRestoreNamedGlobalVector(dm,"TSTheta_X0",X0));
690d0b770aSPeter Brune     }
700d0b770aSPeter Brune   }
710d0b770aSPeter Brune   if (Xdot) {
720d0b770aSPeter Brune     if (dm && dm != ts->dm) {
735f80ce2aSJacob Faibussowitsch       CHKERRQ(DMRestoreNamedGlobalVector(dm,"TSTheta_Xdot",Xdot));
740d0b770aSPeter Brune     }
750d0b770aSPeter Brune   }
760d0b770aSPeter Brune   PetscFunctionReturn(0);
770d0b770aSPeter Brune }
780d0b770aSPeter Brune 
797445fe48SJed Brown static PetscErrorCode DMCoarsenHook_TSTheta(DM fine,DM coarse,void *ctx)
807445fe48SJed Brown {
817445fe48SJed Brown   PetscFunctionBegin;
827445fe48SJed Brown   PetscFunctionReturn(0);
837445fe48SJed Brown }
847445fe48SJed Brown 
857445fe48SJed Brown static PetscErrorCode DMRestrictHook_TSTheta(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
867445fe48SJed Brown {
877445fe48SJed Brown   TS             ts = (TS)ctx;
887445fe48SJed Brown   Vec            X0,Xdot,X0_c,Xdot_c;
897445fe48SJed Brown 
907445fe48SJed Brown   PetscFunctionBegin;
915f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaGetX0AndXdot(ts,fine,&X0,&Xdot));
925f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaGetX0AndXdot(ts,coarse,&X0_c,&Xdot_c));
935f80ce2aSJacob Faibussowitsch   CHKERRQ(MatRestrict(restrct,X0,X0_c));
945f80ce2aSJacob Faibussowitsch   CHKERRQ(MatRestrict(restrct,Xdot,Xdot_c));
955f80ce2aSJacob Faibussowitsch   CHKERRQ(VecPointwiseMult(X0_c,rscale,X0_c));
965f80ce2aSJacob Faibussowitsch   CHKERRQ(VecPointwiseMult(Xdot_c,rscale,Xdot_c));
975f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaRestoreX0AndXdot(ts,fine,&X0,&Xdot));
985f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaRestoreX0AndXdot(ts,coarse,&X0_c,&Xdot_c));
997445fe48SJed Brown   PetscFunctionReturn(0);
1007445fe48SJed Brown }
1017445fe48SJed Brown 
102258e1594SPeter Brune static PetscErrorCode DMSubDomainHook_TSTheta(DM dm,DM subdm,void *ctx)
103258e1594SPeter Brune {
104258e1594SPeter Brune   PetscFunctionBegin;
105258e1594SPeter Brune   PetscFunctionReturn(0);
106258e1594SPeter Brune }
107258e1594SPeter Brune 
108258e1594SPeter Brune static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
109258e1594SPeter Brune {
110258e1594SPeter Brune   TS             ts = (TS)ctx;
111258e1594SPeter Brune   Vec            X0,Xdot,X0_sub,Xdot_sub;
112258e1594SPeter Brune 
113258e1594SPeter Brune   PetscFunctionBegin;
1145f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaGetX0AndXdot(ts,dm,&X0,&Xdot));
1155f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaGetX0AndXdot(ts,subdm,&X0_sub,&Xdot_sub));
116258e1594SPeter Brune 
1175f80ce2aSJacob Faibussowitsch   CHKERRQ(VecScatterBegin(gscat,X0,X0_sub,INSERT_VALUES,SCATTER_FORWARD));
1185f80ce2aSJacob Faibussowitsch   CHKERRQ(VecScatterEnd(gscat,X0,X0_sub,INSERT_VALUES,SCATTER_FORWARD));
119258e1594SPeter Brune 
1205f80ce2aSJacob Faibussowitsch   CHKERRQ(VecScatterBegin(gscat,Xdot,Xdot_sub,INSERT_VALUES,SCATTER_FORWARD));
1215f80ce2aSJacob Faibussowitsch   CHKERRQ(VecScatterEnd(gscat,Xdot,Xdot_sub,INSERT_VALUES,SCATTER_FORWARD));
122258e1594SPeter Brune 
1235f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaRestoreX0AndXdot(ts,dm,&X0,&Xdot));
1245f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaRestoreX0AndXdot(ts,subdm,&X0_sub,&Xdot_sub));
125258e1594SPeter Brune   PetscFunctionReturn(0);
126258e1594SPeter Brune }
127258e1594SPeter Brune 
128022c081aSHong Zhang static PetscErrorCode TSThetaEvaluateCostIntegral(TS ts)
129022c081aSHong Zhang {
130022c081aSHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
131cd4cee2dSHong Zhang   TS             quadts = ts->quadraturets;
132022c081aSHong Zhang 
133022c081aSHong Zhang   PetscFunctionBegin;
134022c081aSHong Zhang   if (th->endpoint) {
135022c081aSHong Zhang     /* Evolve ts->vec_costintegral to compute integrals */
136022c081aSHong Zhang     if (th->Theta!=1.0) {
1375f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSFunction(quadts,th->ptime0,th->X0,ts->vec_costintegrand));
1385f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(quadts->vec_sol,th->time_step0*(1.0-th->Theta),ts->vec_costintegrand));
139022c081aSHong Zhang     }
1405f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeRHSFunction(quadts,ts->ptime,ts->vec_sol,ts->vec_costintegrand));
1415f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPY(quadts->vec_sol,th->time_step0*th->Theta,ts->vec_costintegrand));
142022c081aSHong Zhang   } else {
1435f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeRHSFunction(quadts,th->stage_time,th->X,ts->vec_costintegrand));
1445f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPY(quadts->vec_sol,th->time_step0,ts->vec_costintegrand));
145022c081aSHong Zhang   }
146022c081aSHong Zhang   PetscFunctionReturn(0);
147022c081aSHong Zhang }
148022c081aSHong Zhang 
149b1cb36f3SHong Zhang static PetscErrorCode TSForwardCostIntegral_Theta(TS ts)
150b1cb36f3SHong Zhang {
151b1cb36f3SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
152cd4cee2dSHong Zhang   TS             quadts = ts->quadraturets;
153b1cb36f3SHong Zhang 
154b1cb36f3SHong Zhang   PetscFunctionBegin;
155b1cb36f3SHong Zhang   /* backup cost integral */
1565f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCopy(quadts->vec_sol,th->VecCostIntegral0));
1575f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaEvaluateCostIntegral(ts));
158b1cb36f3SHong Zhang   PetscFunctionReturn(0);
159b1cb36f3SHong Zhang }
160b1cb36f3SHong Zhang 
161b1cb36f3SHong Zhang static PetscErrorCode TSAdjointCostIntegral_Theta(TS ts)
162b1cb36f3SHong Zhang {
1631a352fa8SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
164b1cb36f3SHong Zhang 
165b1cb36f3SHong Zhang   PetscFunctionBegin;
1661a352fa8SHong Zhang   /* Like TSForwardCostIntegral(), the adjoint cost integral evaluation relies on ptime0 and time_step0. */
1671a352fa8SHong Zhang   th->ptime0     = ts->ptime + ts->time_step;
1681a352fa8SHong Zhang   th->time_step0 = -ts->time_step;
1695f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaEvaluateCostIntegral(ts));
17024655328SShri   PetscFunctionReturn(0);
17124655328SShri }
17224655328SShri 
173470880abSPatrick Sanan static PetscErrorCode TSTheta_SNESSolve(TS ts,Vec b,Vec x)
1741566a47fSLisandro Dalcin {
1751566a47fSLisandro Dalcin   PetscInt       nits,lits;
1761566a47fSLisandro Dalcin 
1771566a47fSLisandro Dalcin   PetscFunctionBegin;
1785f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSolve(ts->snes,b,x));
1795f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetIterationNumber(ts->snes,&nits));
1805f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetLinearSolveIterations(ts->snes,&lits));
1811566a47fSLisandro Dalcin   ts->snes_its += nits; ts->ksp_its += lits;
1821566a47fSLisandro Dalcin   PetscFunctionReturn(0);
1831566a47fSLisandro Dalcin }
1841566a47fSLisandro Dalcin 
185193ac0bcSJed Brown static PetscErrorCode TSStep_Theta(TS ts)
186316643e7SJed Brown {
187316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
1881566a47fSLisandro Dalcin   PetscInt       rejections = 0;
1894957b756SLisandro Dalcin   PetscBool      stageok,accept = PETSC_TRUE;
1901566a47fSLisandro Dalcin   PetscReal      next_time_step = ts->time_step;
191316643e7SJed Brown 
192316643e7SJed Brown   PetscFunctionBegin;
1931566a47fSLisandro Dalcin   if (!ts->steprollback) {
1945f80ce2aSJacob Faibussowitsch     if (th->vec_sol_prev) CHKERRQ(VecCopy(th->X0,th->vec_sol_prev));
1955f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCopy(ts->vec_sol,th->X0));
1961566a47fSLisandro Dalcin   }
1971566a47fSLisandro Dalcin 
1981566a47fSLisandro Dalcin   th->status     = TS_STEP_INCOMPLETE;
19999260352SHong Zhang   while (!ts->reason && th->status != TS_STEP_COMPLETE) {
2003e05ceb1SHong Zhang     th->shift      = 1/(th->Theta*ts->time_step);
2011566a47fSLisandro Dalcin     th->stage_time = ts->ptime + (th->endpoint ? (PetscReal)1 : th->Theta)*ts->time_step;
2025f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCopy(th->X0,th->X));
203fecfb714SLisandro Dalcin     if (th->extrapolate && !ts->steprestart) {
2045f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(th->X,1/th->shift,th->Xdot));
205be5899b3SLisandro Dalcin     }
206eb284becSJed Brown     if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */
2075f80ce2aSJacob Faibussowitsch       if (!th->affine) CHKERRQ(VecDuplicate(ts->vec_sol,&th->affine));
2085f80ce2aSJacob Faibussowitsch       CHKERRQ(VecZeroEntries(th->Xdot));
2095f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIFunction(ts,ts->ptime,th->X0,th->Xdot,th->affine,PETSC_FALSE));
2105f80ce2aSJacob Faibussowitsch       CHKERRQ(VecScale(th->affine,(th->Theta-1)/th->Theta));
2111566a47fSLisandro Dalcin     } else if (th->affine) { /* Just in case th->endpoint is changed between calls to TSStep_Theta() */
2125f80ce2aSJacob Faibussowitsch       CHKERRQ(VecZeroEntries(th->affine));
213eb284becSJed Brown     }
2145f80ce2aSJacob Faibussowitsch     CHKERRQ(TSPreStage(ts,th->stage_time));
2155f80ce2aSJacob Faibussowitsch     CHKERRQ(TSTheta_SNESSolve(ts,th->affine,th->X));
2165f80ce2aSJacob Faibussowitsch     CHKERRQ(TSPostStage(ts,th->stage_time,0,&th->X));
2175f80ce2aSJacob Faibussowitsch     CHKERRQ(TSAdaptCheckStage(ts->adapt,ts,th->stage_time,th->X,&stageok));
218fecfb714SLisandro Dalcin     if (!stageok) goto reject_step;
219051f2191SLisandro Dalcin 
220051f2191SLisandro Dalcin     th->status = TS_STEP_PENDING;
2211566a47fSLisandro Dalcin     if (th->endpoint) {
2225f80ce2aSJacob Faibussowitsch       CHKERRQ(VecCopy(th->X,ts->vec_sol));
2231566a47fSLisandro Dalcin     } else {
2245f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPBYPCZ(th->Xdot,-th->shift,th->shift,0,th->X0,th->X));
2255f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(ts->vec_sol,ts->time_step,th->Xdot));
2261566a47fSLisandro Dalcin     }
2275f80ce2aSJacob Faibussowitsch     CHKERRQ(TSAdaptChoose(ts->adapt,ts,ts->time_step,NULL,&next_time_step,&accept));
2281566a47fSLisandro Dalcin     th->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
2291566a47fSLisandro Dalcin     if (!accept) {
2305f80ce2aSJacob Faibussowitsch       CHKERRQ(VecCopy(th->X0,ts->vec_sol));
231be5899b3SLisandro Dalcin       ts->time_step = next_time_step;
232be5899b3SLisandro Dalcin       goto reject_step;
233051f2191SLisandro Dalcin     }
2343b1890cdSShri Abhyankar 
235715f1b00SHong Zhang     if (ts->forward_solve || ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */
2361a352fa8SHong Zhang       th->ptime0     = ts->ptime;
2371a352fa8SHong Zhang       th->time_step0 = ts->time_step;
23817145e75SHong Zhang     }
2392b5a38e1SLisandro Dalcin     ts->ptime += ts->time_step;
240cdbf8f93SLisandro Dalcin     ts->time_step = next_time_step;
241051f2191SLisandro Dalcin     break;
242051f2191SLisandro Dalcin 
243051f2191SLisandro Dalcin   reject_step:
244fecfb714SLisandro Dalcin     ts->reject++; accept = PETSC_FALSE;
2451566a47fSLisandro Dalcin     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
246051f2191SLisandro Dalcin       ts->reason = TS_DIVERGED_STEP_REJECTED;
2475f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,rejections));
2483b1890cdSShri Abhyankar     }
2493b1890cdSShri Abhyankar   }
250316643e7SJed Brown   PetscFunctionReturn(0);
251316643e7SJed Brown }
252316643e7SJed Brown 
253c9681e5dSHong Zhang static PetscErrorCode TSAdjointStepBEuler_Private(TS ts)
254c9681e5dSHong Zhang {
255c9681e5dSHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
256cd4cee2dSHong Zhang   TS             quadts = ts->quadraturets;
257c9681e5dSHong Zhang   Vec            *VecsDeltaLam = th->VecsDeltaLam,*VecsDeltaMu = th->VecsDeltaMu,*VecsSensiTemp = th->VecsSensiTemp;
258c9681e5dSHong Zhang   Vec            *VecsDeltaLam2 = th->VecsDeltaLam2,*VecsDeltaMu2 = th->VecsDeltaMu2,*VecsSensi2Temp = th->VecsSensi2Temp;
259c9681e5dSHong Zhang   PetscInt       nadj;
2607207e0fdSHong Zhang   Mat            J,Jpre,quadJ = NULL,quadJp = NULL;
261c9681e5dSHong Zhang   KSP            ksp;
262c9681e5dSHong Zhang   PetscScalar    *xarr;
263077c4feaSHong Zhang   TSEquationType eqtype;
264077c4feaSHong Zhang   PetscBool      isexplicitode = PETSC_FALSE;
2651a352fa8SHong Zhang   PetscReal      adjoint_time_step;
266c9681e5dSHong Zhang 
267c9681e5dSHong Zhang   PetscFunctionBegin;
2685f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetEquationType(ts,&eqtype));
269077c4feaSHong Zhang   if (eqtype == TS_EQ_ODE_EXPLICIT) {
270077c4feaSHong Zhang     isexplicitode  = PETSC_TRUE;
271077c4feaSHong Zhang     VecsDeltaLam  = ts->vecs_sensi;
272077c4feaSHong Zhang     VecsDeltaLam2 = ts->vecs_sensi2;
273077c4feaSHong Zhang   }
274c9681e5dSHong Zhang   th->status = TS_STEP_INCOMPLETE;
2755f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetKSP(ts->snes,&ksp));
2765f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetIJacobian(ts,&J,&Jpre,NULL,NULL));
2777207e0fdSHong Zhang   if (quadts) {
2785f80ce2aSJacob Faibussowitsch     CHKERRQ(TSGetRHSJacobian(quadts,&quadJ,NULL,NULL,NULL));
2795f80ce2aSJacob Faibussowitsch     CHKERRQ(TSGetRHSJacobianP(quadts,&quadJp,NULL,NULL));
2807207e0fdSHong Zhang   }
281c9681e5dSHong Zhang 
2821a352fa8SHong Zhang   th->stage_time    = ts->ptime;
2831a352fa8SHong Zhang   adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */
284c9681e5dSHong Zhang 
28533f72c5dSHong Zhang   /* Build RHS for first-order adjoint lambda_{n+1}/h + r_u^T(n+1) */
2867207e0fdSHong Zhang   if (quadts) {
2875f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeRHSJacobian(quadts,th->stage_time,ts->vec_sol,quadJ,NULL));
2887207e0fdSHong Zhang   }
289cd4cee2dSHong Zhang 
290c9681e5dSHong Zhang   for (nadj=0; nadj<ts->numcost; nadj++) {
2915f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCopy(ts->vecs_sensi[nadj],VecsSensiTemp[nadj]));
2925f80ce2aSJacob Faibussowitsch     CHKERRQ(VecScale(VecsSensiTemp[nadj],1./adjoint_time_step)); /* lambda_{n+1}/h */
293cd4cee2dSHong Zhang     if (quadJ) {
2945f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseGetColumn(quadJ,nadj,&xarr));
2955f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(ts->vec_drdu_col,xarr));
2965f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(VecsSensiTemp[nadj],1.,ts->vec_drdu_col));
2975f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(ts->vec_drdu_col));
2985f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseRestoreColumn(quadJ,&xarr));
299c9681e5dSHong Zhang     }
300c9681e5dSHong Zhang   }
301c9681e5dSHong Zhang 
302c9681e5dSHong Zhang   /* Build LHS for first-order adjoint */
303c87ba875SIvan Yashchuk   th->shift = 1./adjoint_time_step;
3045f80ce2aSJacob Faibussowitsch   CHKERRQ(TSComputeSNESJacobian(ts,ts->vec_sol,J,Jpre));
3055f80ce2aSJacob Faibussowitsch   CHKERRQ(KSPSetOperators(ksp,J,Jpre));
306c9681e5dSHong Zhang 
307c9681e5dSHong Zhang   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
308c9681e5dSHong Zhang   for (nadj=0; nadj<ts->numcost; nadj++) {
309c9681e5dSHong Zhang     KSPConvergedReason kspreason;
3105f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSolveTranspose(ksp,VecsSensiTemp[nadj],VecsDeltaLam[nadj]));
3115f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPGetConvergedReason(ksp,&kspreason));
312c9681e5dSHong Zhang     if (kspreason < 0) {
313c9681e5dSHong Zhang       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
3145f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(ts,"Step=%D, %Dth cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n",ts->steps,nadj));
315c9681e5dSHong Zhang     }
316c9681e5dSHong Zhang   }
317c9681e5dSHong Zhang 
318c9681e5dSHong Zhang   if (ts->vecs_sensi2) { /* U_{n+1} */
319c9681e5dSHong Zhang     /* Get w1 at t_{n+1} from TLM matrix */
3205f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetColumn(ts->mat_sensip,0,&xarr));
3215f80ce2aSJacob Faibussowitsch     CHKERRQ(VecPlaceArray(ts->vec_sensip_col,xarr));
322c9681e5dSHong Zhang     /* lambda_s^T F_UU w_1 */
3235f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIHessianProductFunctionUU(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_sensip_col,ts->vecs_fuu));
324c9681e5dSHong Zhang     /* lambda_s^T F_UP w_2 */
3255f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIHessianProductFunctionUP(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_dir,ts->vecs_fup));
326c9681e5dSHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) { /* compute the residual */
3275f80ce2aSJacob Faibussowitsch       CHKERRQ(VecCopy(ts->vecs_sensi2[nadj],VecsSensi2Temp[nadj]));
3285f80ce2aSJacob Faibussowitsch       CHKERRQ(VecScale(VecsSensi2Temp[nadj],1./adjoint_time_step));
3295f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(VecsSensi2Temp[nadj],-1.,ts->vecs_fuu[nadj]));
330c9681e5dSHong Zhang       if (ts->vecs_fup) {
3315f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(VecsSensi2Temp[nadj],-1.,ts->vecs_fup[nadj]));
332c9681e5dSHong Zhang       }
333c9681e5dSHong Zhang     }
334c9681e5dSHong Zhang     /* Solve stage equation LHS X = RHS for second-order adjoint */
335c9681e5dSHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
33605c9950eSHong Zhang       KSPConvergedReason kspreason;
3375f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSolveTranspose(ksp,VecsSensi2Temp[nadj],VecsDeltaLam2[nadj]));
3385f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPGetConvergedReason(ksp,&kspreason));
33905c9950eSHong Zhang       if (kspreason < 0) {
34005c9950eSHong Zhang         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
3415f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscInfo(ts,"Step=%D, %Dth cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n",ts->steps,nadj));
34205c9950eSHong Zhang       }
343c9681e5dSHong Zhang     }
344c9681e5dSHong Zhang   }
345c9681e5dSHong Zhang 
346c9681e5dSHong Zhang   /* Update sensitivities, and evaluate integrals if there is any */
347077c4feaSHong Zhang   if (!isexplicitode) {
3483e05ceb1SHong Zhang     th->shift = 0.0;
3495f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeSNESJacobian(ts,ts->vec_sol,J,Jpre));
3505f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSetOperators(ksp,J,Jpre));
351c9681e5dSHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
35233f72c5dSHong Zhang       /* Add f_U \lambda_s to the original RHS */
3535f80ce2aSJacob Faibussowitsch       CHKERRQ(VecScale(VecsSensiTemp[nadj],-1.));
3545f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTransposeAdd(J,VecsDeltaLam[nadj],VecsSensiTemp[nadj],VecsSensiTemp[nadj]));
3555f80ce2aSJacob Faibussowitsch       CHKERRQ(VecScale(VecsSensiTemp[nadj],-adjoint_time_step));
3565f80ce2aSJacob Faibussowitsch       CHKERRQ(VecCopy(VecsSensiTemp[nadj],ts->vecs_sensi[nadj]));
357c9681e5dSHong Zhang       if (ts->vecs_sensi2) {
3585f80ce2aSJacob Faibussowitsch         CHKERRQ(MatMultTransposeAdd(J,VecsDeltaLam2[nadj],VecsSensi2Temp[nadj],VecsSensi2Temp[nadj]));
3595f80ce2aSJacob Faibussowitsch         CHKERRQ(VecScale(VecsSensi2Temp[nadj],-adjoint_time_step));
3605f80ce2aSJacob Faibussowitsch         CHKERRQ(VecCopy(VecsSensi2Temp[nadj],ts->vecs_sensi2[nadj]));
361c9681e5dSHong Zhang       }
362c9681e5dSHong Zhang     }
363077c4feaSHong Zhang   }
364c9681e5dSHong Zhang   if (ts->vecs_sensip) {
3655f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPBYPCZ(th->Xdot,-1./adjoint_time_step,1.0/adjoint_time_step,0,th->X0,ts->vec_sol));
3665f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIJacobianP(ts,th->stage_time,ts->vec_sol,th->Xdot,1./adjoint_time_step,ts->Jacp,PETSC_FALSE)); /* get -f_p */
3677207e0fdSHong Zhang     if (quadts) {
3685f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobianP(quadts,th->stage_time,ts->vec_sol,quadJp));
3697207e0fdSHong Zhang     }
370c9681e5dSHong Zhang     if (ts->vecs_sensi2p) {
371c9681e5dSHong Zhang       /* lambda_s^T F_PU w_1 */
3725f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIHessianProductFunctionPU(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_sensip_col,ts->vecs_fpu));
37333f72c5dSHong Zhang       /* lambda_s^T F_PP w_2 */
3745f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIHessianProductFunctionPP(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_dir,ts->vecs_fpp));
375c9681e5dSHong Zhang     }
376cd4cee2dSHong Zhang 
377c9681e5dSHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
3785f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]));
3795f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],-adjoint_time_step,VecsDeltaMu[nadj]));
380cd4cee2dSHong Zhang       if (quadJp) {
3815f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseGetColumn(quadJp,nadj,&xarr));
3825f80ce2aSJacob Faibussowitsch         CHKERRQ(VecPlaceArray(ts->vec_drdp_col,xarr));
3835f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],adjoint_time_step,ts->vec_drdp_col));
3845f80ce2aSJacob Faibussowitsch         CHKERRQ(VecResetArray(ts->vec_drdp_col));
3855f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseRestoreColumn(quadJp,&xarr));
38633f72c5dSHong Zhang       }
387c9681e5dSHong Zhang       if (ts->vecs_sensi2p) {
3885f80ce2aSJacob Faibussowitsch         CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam2[nadj],VecsDeltaMu2[nadj]));
3895f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step,VecsDeltaMu2[nadj]));
390c9681e5dSHong Zhang         if (ts->vecs_fpu) {
3915f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step,ts->vecs_fpu[nadj]));
392c9681e5dSHong Zhang         }
393c9681e5dSHong Zhang         if (ts->vecs_fpp) {
3945f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step,ts->vecs_fpp[nadj]));
395c9681e5dSHong Zhang         }
396c9681e5dSHong Zhang       }
397c9681e5dSHong Zhang     }
398c9681e5dSHong Zhang   }
399c9681e5dSHong Zhang 
400c9681e5dSHong Zhang   if (ts->vecs_sensi2) {
4015f80ce2aSJacob Faibussowitsch     CHKERRQ(VecResetArray(ts->vec_sensip_col));
4025f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreColumn(ts->mat_sensip,&xarr));
403c9681e5dSHong Zhang   }
404c9681e5dSHong Zhang   th->status = TS_STEP_COMPLETE;
405c9681e5dSHong Zhang   PetscFunctionReturn(0);
406c9681e5dSHong Zhang }
407c9681e5dSHong Zhang 
40842f2b339SBarry Smith static PetscErrorCode TSAdjointStep_Theta(TS ts)
4092ca6e920SHong Zhang {
4102ca6e920SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
411cd4cee2dSHong Zhang   TS             quadts = ts->quadraturets;
412b5e0532dSHong Zhang   Vec            *VecsDeltaLam = th->VecsDeltaLam,*VecsDeltaMu = th->VecsDeltaMu,*VecsSensiTemp = th->VecsSensiTemp;
413b5b4017aSHong Zhang   Vec            *VecsDeltaLam2 = th->VecsDeltaLam2,*VecsDeltaMu2 = th->VecsDeltaMu2,*VecsSensi2Temp = th->VecsSensi2Temp;
4142ca6e920SHong Zhang   PetscInt       nadj;
4157207e0fdSHong Zhang   Mat            J,Jpre,quadJ = NULL,quadJp = NULL;
4162ca6e920SHong Zhang   KSP            ksp;
417b5b4017aSHong Zhang   PetscScalar    *xarr;
4181a352fa8SHong Zhang   PetscReal      adjoint_time_step;
4191a352fa8SHong Zhang   PetscReal      adjoint_ptime; /* end time of the adjoint time step (ts->ptime is the start time, ususally ts->ptime is larger than adjoint_ptime) */
4202ca6e920SHong Zhang 
4212ca6e920SHong Zhang   PetscFunctionBegin;
422c9681e5dSHong Zhang   if (th->Theta == 1.) {
4235f80ce2aSJacob Faibussowitsch     CHKERRQ(TSAdjointStepBEuler_Private(ts));
424c9681e5dSHong Zhang     PetscFunctionReturn(0);
425c9681e5dSHong Zhang   }
4262ca6e920SHong Zhang   th->status = TS_STEP_INCOMPLETE;
4275f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetKSP(ts->snes,&ksp));
4285f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetIJacobian(ts,&J,&Jpre,NULL,NULL));
4297207e0fdSHong Zhang   if (quadts) {
4305f80ce2aSJacob Faibussowitsch     CHKERRQ(TSGetRHSJacobian(quadts,&quadJ,NULL,NULL,NULL));
4315f80ce2aSJacob Faibussowitsch     CHKERRQ(TSGetRHSJacobianP(quadts,&quadJp,NULL,NULL));
4327207e0fdSHong Zhang   }
433b5e0532dSHong Zhang   /* If endpoint=1, th->ptime and th->X0 will be used; if endpoint=0, th->stage_time and th->X will be used. */
4341a352fa8SHong Zhang   th->stage_time    = th->endpoint ? ts->ptime : (ts->ptime+(1.-th->Theta)*ts->time_step);
4351a352fa8SHong Zhang   adjoint_ptime     = ts->ptime + ts->time_step;
4361a352fa8SHong Zhang   adjoint_time_step = -ts->time_step;  /* always positive since time_step is negative */
4372ca6e920SHong Zhang 
43882ad9101SHong Zhang   if (!th->endpoint) {
4395072d23cSHong Zhang     /* recover th->X0 using vec_sol and the stage value th->X */
4405f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPBYPCZ(th->X0,1.0/(1.0-th->Theta),th->Theta/(th->Theta-1.0),0,th->X,ts->vec_sol));
44182ad9101SHong Zhang   }
44282ad9101SHong Zhang 
443b5b4017aSHong Zhang   /* Build RHS for first-order adjoint */
44433f72c5dSHong Zhang   /* Cost function has an integral term */
4457207e0fdSHong Zhang   if (quadts) {
44605755b9cSHong Zhang     if (th->endpoint) {
4475f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,th->stage_time,ts->vec_sol,quadJ,NULL));
44805755b9cSHong Zhang     } else {
4495f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,th->stage_time,th->X,quadJ,NULL));
45005755b9cSHong Zhang     }
4517207e0fdSHong Zhang   }
45233f72c5dSHong Zhang 
453abc2977eSBarry Smith   for (nadj=0; nadj<ts->numcost; nadj++) {
4545f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCopy(ts->vecs_sensi[nadj],VecsSensiTemp[nadj]));
4555f80ce2aSJacob Faibussowitsch     CHKERRQ(VecScale(VecsSensiTemp[nadj],1./(th->Theta*adjoint_time_step)));
456cd4cee2dSHong Zhang     if (quadJ) {
4575f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseGetColumn(quadJ,nadj,&xarr));
4585f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(ts->vec_drdu_col,xarr));
4595f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(VecsSensiTemp[nadj],1.,ts->vec_drdu_col));
4605f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(ts->vec_drdu_col));
4615f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseRestoreColumn(quadJ,&xarr));
46236eaed60SHong Zhang     }
4632ca6e920SHong Zhang   }
4643c54f92cSHong Zhang 
465b5b4017aSHong Zhang   /* Build LHS for first-order adjoint */
4661a352fa8SHong Zhang   th->shift = 1./(th->Theta*adjoint_time_step);
4673c54f92cSHong Zhang   if (th->endpoint) {
4685f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeSNESJacobian(ts,ts->vec_sol,J,Jpre));
4693c54f92cSHong Zhang   } else {
4705f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeSNESJacobian(ts,th->X,J,Jpre));
4713c54f92cSHong Zhang   }
4725f80ce2aSJacob Faibussowitsch   CHKERRQ(KSPSetOperators(ksp,J,Jpre));
4732ca6e920SHong Zhang 
474b5b4017aSHong Zhang   /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */
475abc2977eSBarry Smith   for (nadj=0; nadj<ts->numcost; nadj++) {
4761d14d03bSHong Zhang     KSPConvergedReason kspreason;
4775f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSolveTranspose(ksp,VecsSensiTemp[nadj],VecsDeltaLam[nadj]));
4785f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPGetConvergedReason(ksp,&kspreason));
4791d14d03bSHong Zhang     if (kspreason < 0) {
4801d14d03bSHong Zhang       ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
4815f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(ts,"Step=%D, %Dth cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n",ts->steps,nadj));
4821d14d03bSHong Zhang     }
4832ca6e920SHong Zhang   }
4843c54f92cSHong Zhang 
4851d14d03bSHong Zhang   /* Second-order adjoint */
486b5b4017aSHong Zhang   if (ts->vecs_sensi2) { /* U_{n+1} */
4873c633725SBarry Smith     PetscCheck(th->endpoint,PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"Operation not implemented in TS_Theta");
488b5b4017aSHong Zhang     /* Get w1 at t_{n+1} from TLM matrix */
4895f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetColumn(ts->mat_sensip,0,&xarr));
4905f80ce2aSJacob Faibussowitsch     CHKERRQ(VecPlaceArray(ts->vec_sensip_col,xarr));
491b5b4017aSHong Zhang     /* lambda_s^T F_UU w_1 */
4925f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIHessianProductFunctionUU(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_sensip_col,ts->vecs_fuu));
4935f80ce2aSJacob Faibussowitsch     CHKERRQ(VecResetArray(ts->vec_sensip_col));
4945f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreColumn(ts->mat_sensip,&xarr));
495b5b4017aSHong Zhang     /* lambda_s^T F_UP w_2 */
4965f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIHessianProductFunctionUP(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_dir,ts->vecs_fup));
497b5b4017aSHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) { /* compute the residual */
4985f80ce2aSJacob Faibussowitsch       CHKERRQ(VecCopy(ts->vecs_sensi2[nadj],VecsSensi2Temp[nadj]));
4995f80ce2aSJacob Faibussowitsch       CHKERRQ(VecScale(VecsSensi2Temp[nadj],th->shift));
5005f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(VecsSensi2Temp[nadj],-1.,ts->vecs_fuu[nadj]));
501b5b4017aSHong Zhang       if (ts->vecs_fup) {
5025f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(VecsSensi2Temp[nadj],-1.,ts->vecs_fup[nadj]));
503b5b4017aSHong Zhang       }
504b5b4017aSHong Zhang     }
505b5b4017aSHong Zhang     /* Solve stage equation LHS X = RHS for second-order adjoint */
506b5b4017aSHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
5071d14d03bSHong Zhang       KSPConvergedReason kspreason;
5085f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSolveTranspose(ksp,VecsSensi2Temp[nadj],VecsDeltaLam2[nadj]));
5095f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPGetConvergedReason(ksp,&kspreason));
5101d14d03bSHong Zhang       if (kspreason < 0) {
5111d14d03bSHong Zhang         ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE;
5125f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscInfo(ts,"Step=%D, %Dth cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n",ts->steps,nadj));
5131d14d03bSHong Zhang       }
514b5b4017aSHong Zhang     }
515b5b4017aSHong Zhang   }
516b5b4017aSHong Zhang 
51736eaed60SHong Zhang   /* Update sensitivities, and evaluate integrals if there is any */
5181d14d03bSHong Zhang   if (th->endpoint) { /* two-stage Theta methods with th->Theta!=1, th->Theta==1 leads to BEuler */
5191a352fa8SHong Zhang     th->shift      = 1./((th->Theta-1.)*adjoint_time_step);
5201a352fa8SHong Zhang     th->stage_time = adjoint_ptime;
5215f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeSNESJacobian(ts,th->X0,J,Jpre));
5225f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSetOperators(ksp,J,Jpre));
52333f72c5dSHong Zhang     /* R_U at t_n */
5247207e0fdSHong Zhang     if (quadts) {
5255f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,adjoint_ptime,th->X0,quadJ,NULL));
5267207e0fdSHong Zhang     }
527abc2977eSBarry Smith     for (nadj=0; nadj<ts->numcost; nadj++) {
5285f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTranspose(J,VecsDeltaLam[nadj],ts->vecs_sensi[nadj]));
529cd4cee2dSHong Zhang       if (quadJ) {
5305f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseGetColumn(quadJ,nadj,&xarr));
5315f80ce2aSJacob Faibussowitsch         CHKERRQ(VecPlaceArray(ts->vec_drdu_col,xarr));
5325f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensi[nadj],-1.,ts->vec_drdu_col));
5335f80ce2aSJacob Faibussowitsch         CHKERRQ(VecResetArray(ts->vec_drdu_col));
5345f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseRestoreColumn(quadJ,&xarr));
535b5b4017aSHong Zhang       }
5365f80ce2aSJacob Faibussowitsch       CHKERRQ(VecScale(ts->vecs_sensi[nadj],1./th->shift));
537b5b4017aSHong Zhang     }
5381d14d03bSHong Zhang 
5391d14d03bSHong Zhang     /* Second-order adjoint */
5401d14d03bSHong Zhang     if (ts->vecs_sensi2) { /* U_n */
541b5b4017aSHong Zhang       /* Get w1 at t_n from TLM matrix */
5425f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseGetColumn(th->MatFwdSensip0,0,&xarr));
5435f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(ts->vec_sensip_col,xarr));
544b5b4017aSHong Zhang       /* lambda_s^T F_UU w_1 */
5455f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIHessianProductFunctionUU(ts,adjoint_ptime,th->X0,VecsDeltaLam,ts->vec_sensip_col,ts->vecs_fuu));
5465f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(ts->vec_sensip_col));
5475f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseRestoreColumn(th->MatFwdSensip0,&xarr));
548b5b4017aSHong Zhang       /* lambda_s^T F_UU w_2 */
5495f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIHessianProductFunctionUP(ts,adjoint_ptime,th->X0,VecsDeltaLam,ts->vec_dir,ts->vecs_fup));
550b5b4017aSHong Zhang       for (nadj=0; nadj<ts->numcost; nadj++) {
55133f72c5dSHong Zhang         /* M^T Lambda_s + h(1-theta) F_U^T Lambda_s + h(1-theta) lambda_s^T F_UU w_1 + lambda_s^T F_UP w_2  */
5525f80ce2aSJacob Faibussowitsch         CHKERRQ(MatMultTranspose(J,VecsDeltaLam2[nadj],ts->vecs_sensi2[nadj]));
5535f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensi2[nadj],1.,ts->vecs_fuu[nadj]));
554b5b4017aSHong Zhang         if (ts->vecs_fup) {
5555f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensi2[nadj],1.,ts->vecs_fup[nadj]));
556b5b4017aSHong Zhang         }
5575f80ce2aSJacob Faibussowitsch         CHKERRQ(VecScale(ts->vecs_sensi2[nadj],1./th->shift));
558b5b4017aSHong Zhang       }
559b5e0532dSHong Zhang     }
5603fd52205SHong Zhang 
561c586f2e8SHong Zhang     th->stage_time = ts->ptime; /* recover the old value */
562c586f2e8SHong Zhang 
5633fd52205SHong Zhang     if (ts->vecs_sensip) { /* sensitivities wrt parameters */
564b5b4017aSHong Zhang       /* U_{n+1} */
56582ad9101SHong Zhang       th->shift = 1.0/(adjoint_time_step*th->Theta);
5665f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPBYPCZ(th->Xdot,-th->shift,th->shift,0,th->X0,ts->vec_sol));
5675f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIJacobianP(ts,th->stage_time,ts->vec_sol,th->Xdot,-1./(th->Theta*adjoint_time_step),ts->Jacp,PETSC_FALSE));
5687207e0fdSHong Zhang       if (quadts) {
5695f80ce2aSJacob Faibussowitsch         CHKERRQ(TSComputeRHSJacobianP(quadts,th->stage_time,ts->vec_sol,quadJp));
5707207e0fdSHong Zhang       }
571abc2977eSBarry Smith       for (nadj=0; nadj<ts->numcost; nadj++) {
5725f80ce2aSJacob Faibussowitsch         CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]));
5735f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],-adjoint_time_step*th->Theta,VecsDeltaMu[nadj]));
5743b711c3fSHong Zhang         if (quadJp) {
5755f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseGetColumn(quadJp,nadj,&xarr));
5765f80ce2aSJacob Faibussowitsch           CHKERRQ(VecPlaceArray(ts->vec_drdp_col,xarr));
5775f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],adjoint_time_step*th->Theta,ts->vec_drdp_col));
5785f80ce2aSJacob Faibussowitsch           CHKERRQ(VecResetArray(ts->vec_drdp_col));
5795f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseRestoreColumn(quadJp,&xarr));
5803b711c3fSHong Zhang         }
5813fd52205SHong Zhang       }
58233f72c5dSHong Zhang       if (ts->vecs_sensi2p) { /* second-order */
58333f72c5dSHong Zhang         /* Get w1 at t_{n+1} from TLM matrix */
5845f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseGetColumn(ts->mat_sensip,0,&xarr));
5855f80ce2aSJacob Faibussowitsch         CHKERRQ(VecPlaceArray(ts->vec_sensip_col,xarr));
586b5b4017aSHong Zhang         /* lambda_s^T F_PU w_1 */
5875f80ce2aSJacob Faibussowitsch         CHKERRQ(TSComputeIHessianProductFunctionPU(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_sensip_col,ts->vecs_fpu));
5885f80ce2aSJacob Faibussowitsch         CHKERRQ(VecResetArray(ts->vec_sensip_col));
5895f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseRestoreColumn(ts->mat_sensip,&xarr));
59033f72c5dSHong Zhang 
591b5b4017aSHong Zhang         /* lambda_s^T F_PP w_2 */
5925f80ce2aSJacob Faibussowitsch         CHKERRQ(TSComputeIHessianProductFunctionPP(ts,th->stage_time,ts->vec_sol,VecsDeltaLam,ts->vec_dir,ts->vecs_fpp));
593b5b4017aSHong Zhang         for (nadj=0; nadj<ts->numcost; nadj++) {
59433f72c5dSHong Zhang           /* Mu2 <- Mu2 + h theta F_P^T Lambda_s + h theta (lambda_s^T F_UU w_1 + lambda_s^T F_UP w_2)  */
5955f80ce2aSJacob Faibussowitsch           CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam2[nadj],VecsDeltaMu2[nadj]));
5965f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step*th->Theta,VecsDeltaMu2[nadj]));
597b5b4017aSHong Zhang           if (ts->vecs_fpu) {
5985f80ce2aSJacob Faibussowitsch             CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step*th->Theta,ts->vecs_fpu[nadj]));
599b5b4017aSHong Zhang           }
600b5b4017aSHong Zhang           if (ts->vecs_fpp) {
6015f80ce2aSJacob Faibussowitsch             CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step*th->Theta,ts->vecs_fpp[nadj]));
602b5b4017aSHong Zhang           }
603b5b4017aSHong Zhang         }
604b5b4017aSHong Zhang       }
605b5b4017aSHong Zhang 
606b5b4017aSHong Zhang       /* U_s */
6075f80ce2aSJacob Faibussowitsch       CHKERRQ(VecZeroEntries(th->Xdot));
6085f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIJacobianP(ts,adjoint_ptime,th->X0,th->Xdot,1./((th->Theta-1.0)*adjoint_time_step),ts->Jacp,PETSC_FALSE));
6097207e0fdSHong Zhang       if (quadts) {
6105f80ce2aSJacob Faibussowitsch         CHKERRQ(TSComputeRHSJacobianP(quadts,adjoint_ptime,th->X0,quadJp));
6117207e0fdSHong Zhang       }
612abc2977eSBarry Smith       for (nadj=0; nadj<ts->numcost; nadj++) {
6135f80ce2aSJacob Faibussowitsch         CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]));
6145f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],-adjoint_time_step*(1.0-th->Theta),VecsDeltaMu[nadj]));
6153b711c3fSHong Zhang         if (quadJp) {
6165f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseGetColumn(quadJp,nadj,&xarr));
6175f80ce2aSJacob Faibussowitsch           CHKERRQ(VecPlaceArray(ts->vec_drdp_col,xarr));
6185f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],adjoint_time_step*(1.0-th->Theta),ts->vec_drdp_col));
6195f80ce2aSJacob Faibussowitsch           CHKERRQ(VecResetArray(ts->vec_drdp_col));
6205f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseRestoreColumn(quadJp,&xarr));
6213b711c3fSHong Zhang         }
62233f72c5dSHong Zhang         if (ts->vecs_sensi2p) { /* second-order */
62333f72c5dSHong Zhang           /* Get w1 at t_n from TLM matrix */
6245f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseGetColumn(th->MatFwdSensip0,0,&xarr));
6255f80ce2aSJacob Faibussowitsch           CHKERRQ(VecPlaceArray(ts->vec_sensip_col,xarr));
626b5b4017aSHong Zhang           /* lambda_s^T F_PU w_1 */
6275f80ce2aSJacob Faibussowitsch           CHKERRQ(TSComputeIHessianProductFunctionPU(ts,adjoint_ptime,th->X0,VecsDeltaLam,ts->vec_sensip_col,ts->vecs_fpu));
6285f80ce2aSJacob Faibussowitsch           CHKERRQ(VecResetArray(ts->vec_sensip_col));
6295f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseRestoreColumn(th->MatFwdSensip0,&xarr));
630b5b4017aSHong Zhang           /* lambda_s^T F_PP w_2 */
6315f80ce2aSJacob Faibussowitsch           CHKERRQ(TSComputeIHessianProductFunctionPP(ts,adjoint_ptime,th->X0,VecsDeltaLam,ts->vec_dir,ts->vecs_fpp));
632b5b4017aSHong Zhang           for (nadj=0; nadj<ts->numcost; nadj++) {
63333f72c5dSHong Zhang             /* Mu2 <- Mu2 + h(1-theta) F_P^T Lambda_s + h(1-theta) (lambda_s^T F_UU w_1 + lambda_s^T F_UP w_2) */
6345f80ce2aSJacob Faibussowitsch             CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam2[nadj],VecsDeltaMu2[nadj]));
6355f80ce2aSJacob Faibussowitsch             CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step*(1.0-th->Theta),VecsDeltaMu2[nadj]));
636b5b4017aSHong Zhang             if (ts->vecs_fpu) {
6375f80ce2aSJacob Faibussowitsch               CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step*(1.0-th->Theta),ts->vecs_fpu[nadj]));
638b5e0532dSHong Zhang             }
639b5b4017aSHong Zhang             if (ts->vecs_fpp) {
6405f80ce2aSJacob Faibussowitsch               CHKERRQ(VecAXPY(ts->vecs_sensi2p[nadj],-adjoint_time_step*(1.0-th->Theta),ts->vecs_fpp[nadj]));
641b5b4017aSHong Zhang             }
64236eaed60SHong Zhang           }
64336eaed60SHong Zhang         }
6443fd52205SHong Zhang       }
645b5e0532dSHong Zhang     }
6463fd52205SHong Zhang   } else { /* one-stage case */
6473e05ceb1SHong Zhang     th->shift = 0.0;
6485f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeSNESJacobian(ts,th->X,J,Jpre)); /* get -f_y */
6495f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSetOperators(ksp,J,Jpre));
6507207e0fdSHong Zhang     if (quadts) {
6515f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,th->stage_time,th->X,quadJ,NULL));
6527207e0fdSHong Zhang     }
653abc2977eSBarry Smith     for (nadj=0; nadj<ts->numcost; nadj++) {
6545f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMultTranspose(J,VecsDeltaLam[nadj],VecsSensiTemp[nadj]));
6555f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPY(ts->vecs_sensi[nadj],-adjoint_time_step,VecsSensiTemp[nadj]));
656cd4cee2dSHong Zhang       if (quadJ) {
6575f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseGetColumn(quadJ,nadj,&xarr));
6585f80ce2aSJacob Faibussowitsch         CHKERRQ(VecPlaceArray(ts->vec_drdu_col,xarr));
6595f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensi[nadj],adjoint_time_step,ts->vec_drdu_col));
6605f80ce2aSJacob Faibussowitsch         CHKERRQ(VecResetArray(ts->vec_drdu_col));
6615f80ce2aSJacob Faibussowitsch         CHKERRQ(MatDenseRestoreColumn(quadJ,&xarr));
66236eaed60SHong Zhang       }
6632ca6e920SHong Zhang     }
6643fd52205SHong Zhang     if (ts->vecs_sensip) {
66582ad9101SHong Zhang       th->shift = 1.0/(adjoint_time_step*th->Theta);
6665f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPBYPCZ(th->Xdot,-th->shift,th->shift,0,th->X0,th->X));
6675f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIJacobianP(ts,th->stage_time,th->X,th->Xdot,th->shift,ts->Jacp,PETSC_FALSE));
6687207e0fdSHong Zhang       if (quadts) {
6695f80ce2aSJacob Faibussowitsch         CHKERRQ(TSComputeRHSJacobianP(quadts,th->stage_time,th->X,quadJp));
6707207e0fdSHong Zhang       }
671abc2977eSBarry Smith       for (nadj=0; nadj<ts->numcost; nadj++) {
6725f80ce2aSJacob Faibussowitsch         CHKERRQ(MatMultTranspose(ts->Jacp,VecsDeltaLam[nadj],VecsDeltaMu[nadj]));
6735f80ce2aSJacob Faibussowitsch         CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],-adjoint_time_step,VecsDeltaMu[nadj]));
674cd4cee2dSHong Zhang         if (quadJp) {
6755f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseGetColumn(quadJp,nadj,&xarr));
6765f80ce2aSJacob Faibussowitsch           CHKERRQ(VecPlaceArray(ts->vec_drdp_col,xarr));
6775f80ce2aSJacob Faibussowitsch           CHKERRQ(VecAXPY(ts->vecs_sensip[nadj],adjoint_time_step,ts->vec_drdp_col));
6785f80ce2aSJacob Faibussowitsch           CHKERRQ(VecResetArray(ts->vec_drdp_col));
6795f80ce2aSJacob Faibussowitsch           CHKERRQ(MatDenseRestoreColumn(quadJp,&xarr));
68036eaed60SHong Zhang         }
68136eaed60SHong Zhang       }
6823fd52205SHong Zhang     }
6832ca6e920SHong Zhang   }
6842ca6e920SHong Zhang 
6852ca6e920SHong Zhang   th->status = TS_STEP_COMPLETE;
6862ca6e920SHong Zhang   PetscFunctionReturn(0);
6872ca6e920SHong Zhang }
6882ca6e920SHong Zhang 
689cd652676SJed Brown static PetscErrorCode TSInterpolate_Theta(TS ts,PetscReal t,Vec X)
690cd652676SJed Brown {
691cd652676SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
692be5899b3SLisandro Dalcin   PetscReal      dt  = t - ts->ptime;
693cd652676SJed Brown 
694cd652676SJed Brown   PetscFunctionBegin;
6955f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCopy(ts->vec_sol,th->X));
696be5899b3SLisandro Dalcin   if (th->endpoint) dt *= th->Theta;
6975f80ce2aSJacob Faibussowitsch   CHKERRQ(VecWAXPY(X,dt,th->Xdot,th->X));
698cd652676SJed Brown   PetscFunctionReturn(0);
699cd652676SJed Brown }
700cd652676SJed Brown 
7011566a47fSLisandro Dalcin static PetscErrorCode TSEvaluateWLTE_Theta(TS ts,NormType wnormtype,PetscInt *order,PetscReal *wlte)
7021566a47fSLisandro Dalcin {
7031566a47fSLisandro Dalcin   TS_Theta       *th = (TS_Theta*)ts->data;
7041566a47fSLisandro Dalcin   Vec            X = ts->vec_sol;      /* X = solution */
7051566a47fSLisandro Dalcin   Vec            Y = th->vec_lte_work; /* Y = X + LTE  */
7067453f775SEmil Constantinescu   PetscReal      wltea,wlter;
7071566a47fSLisandro Dalcin 
7081566a47fSLisandro Dalcin   PetscFunctionBegin;
7092ffb9264SLisandro Dalcin   if (!th->vec_sol_prev) {*wlte = -1; PetscFunctionReturn(0);}
7101566a47fSLisandro Dalcin   /* Cannot compute LTE in first step or in restart after event */
711fecfb714SLisandro Dalcin   if (ts->steprestart) {*wlte = -1; PetscFunctionReturn(0);}
7121566a47fSLisandro Dalcin   /* Compute LTE using backward differences with non-constant time step */
713fecfb714SLisandro Dalcin   {
714be5899b3SLisandro Dalcin     PetscReal   h = ts->time_step, h_prev = ts->ptime - ts->ptime_prev;
715be5899b3SLisandro Dalcin     PetscReal   a = 1 + h_prev/h;
7161566a47fSLisandro Dalcin     PetscScalar scal[3]; Vec vecs[3];
7171566a47fSLisandro Dalcin     scal[0] = +1/a; scal[1] = -1/(a-1); scal[2] = +1/(a*(a-1));
7181566a47fSLisandro Dalcin     vecs[0] = X;    vecs[1] = th->X0;   vecs[2] = th->vec_sol_prev;
7195f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCopy(X,Y));
7205f80ce2aSJacob Faibussowitsch     CHKERRQ(VecMAXPY(Y,3,scal,vecs));
7215f80ce2aSJacob Faibussowitsch     CHKERRQ(TSErrorWeightedNorm(ts,X,Y,wnormtype,wlte,&wltea,&wlter));
7221566a47fSLisandro Dalcin   }
7231566a47fSLisandro Dalcin   if (order) *order = 2;
7241566a47fSLisandro Dalcin   PetscFunctionReturn(0);
7251566a47fSLisandro Dalcin }
7261566a47fSLisandro Dalcin 
7271566a47fSLisandro Dalcin static PetscErrorCode TSRollBack_Theta(TS ts)
7281566a47fSLisandro Dalcin {
7291566a47fSLisandro Dalcin   TS_Theta       *th = (TS_Theta*)ts->data;
7307207e0fdSHong Zhang   TS             quadts = ts->quadraturets;
7311566a47fSLisandro Dalcin 
7321566a47fSLisandro Dalcin   PetscFunctionBegin;
7335f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCopy(th->X0,ts->vec_sol));
734cd4cee2dSHong Zhang   if (quadts && ts->costintegralfwd) {
7355f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCopy(th->VecCostIntegral0,quadts->vec_sol));
7361566a47fSLisandro Dalcin   }
737715f1b00SHong Zhang   th->status = TS_STEP_INCOMPLETE;
73813b1b0ffSHong Zhang   if (ts->mat_sensip) {
7395f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCopy(th->MatFwdSensip0,ts->mat_sensip,SAME_NONZERO_PATTERN));
7406f92202bSHong Zhang   }
7417207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
7425f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCopy(th->MatIntegralSensip0,quadts->mat_sensip,SAME_NONZERO_PATTERN));
7436f92202bSHong Zhang   }
744715f1b00SHong Zhang   PetscFunctionReturn(0);
745715f1b00SHong Zhang }
746715f1b00SHong Zhang 
747715f1b00SHong Zhang static PetscErrorCode TSForwardStep_Theta(TS ts)
748715f1b00SHong Zhang {
749715f1b00SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
750cd4cee2dSHong Zhang   TS             quadts = ts->quadraturets;
75113b1b0ffSHong Zhang   Mat            MatDeltaFwdSensip = th->MatDeltaFwdSensip;
752b5b4017aSHong Zhang   Vec            VecDeltaFwdSensipCol = th->VecDeltaFwdSensipCol;
7537207e0fdSHong Zhang   PetscInt       ntlm;
754715f1b00SHong Zhang   KSP            ksp;
7557207e0fdSHong Zhang   Mat            J,Jpre,quadJ = NULL,quadJp = NULL;
75613b1b0ffSHong Zhang   PetscScalar    *barr,*xarr;
7571a352fa8SHong Zhang   PetscReal      previous_shift;
758715f1b00SHong Zhang 
759715f1b00SHong Zhang   PetscFunctionBegin;
7601a352fa8SHong Zhang   previous_shift = th->shift;
7615f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCopy(ts->mat_sensip,th->MatFwdSensip0,SAME_NONZERO_PATTERN));
76213b1b0ffSHong Zhang 
7637207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
7645f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCopy(quadts->mat_sensip,th->MatIntegralSensip0,SAME_NONZERO_PATTERN));
7656f92202bSHong Zhang   }
7665f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetKSP(ts->snes,&ksp));
7675f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetIJacobian(ts,&J,&Jpre,NULL,NULL));
7687207e0fdSHong Zhang   if (quadts) {
7695f80ce2aSJacob Faibussowitsch     CHKERRQ(TSGetRHSJacobian(quadts,&quadJ,NULL,NULL,NULL));
7705f80ce2aSJacob Faibussowitsch     CHKERRQ(TSGetRHSJacobianP(quadts,&quadJp,NULL,NULL));
7717207e0fdSHong Zhang   }
772715f1b00SHong Zhang 
773715f1b00SHong Zhang   /* Build RHS */
774715f1b00SHong Zhang   if (th->endpoint) { /* 2-stage method*/
7751a352fa8SHong Zhang     th->shift = 1./((th->Theta-1.)*th->time_step0);
7765f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIJacobian(ts,th->ptime0,th->X0,th->Xdot,th->shift,J,Jpre,PETSC_FALSE));
7775f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMatMult(J,ts->mat_sensip,MAT_REUSE_MATRIX,PETSC_DEFAULT,&MatDeltaFwdSensip));
7785f80ce2aSJacob Faibussowitsch     CHKERRQ(MatScale(MatDeltaFwdSensip,(th->Theta-1.)/th->Theta));
779715f1b00SHong Zhang 
780022c081aSHong Zhang     /* Add the f_p forcing terms */
7810e11c21fSHong Zhang     if (ts->Jacp) {
7825f80ce2aSJacob Faibussowitsch       CHKERRQ(VecZeroEntries(th->Xdot));
7835f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIJacobianP(ts,th->ptime0,th->X0,th->Xdot,th->shift,ts->Jacp,PETSC_FALSE));
7845f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(MatDeltaFwdSensip,(th->Theta-1.)/th->Theta,ts->Jacp,SUBSET_NONZERO_PATTERN));
78582ad9101SHong Zhang       th->shift = previous_shift;
7865f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPBYPCZ(th->Xdot,-th->shift,th->shift,0,th->X0,ts->vec_sol));
7875f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIJacobianP(ts,th->stage_time,ts->vec_sol,th->Xdot,th->shift,ts->Jacp,PETSC_FALSE));
7885f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(MatDeltaFwdSensip,-1.,ts->Jacp,SUBSET_NONZERO_PATTERN));
7890e11c21fSHong Zhang     }
790715f1b00SHong Zhang   } else { /* 1-stage method */
7913e05ceb1SHong Zhang     th->shift = 0.0;
7925f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIJacobian(ts,th->stage_time,th->X,th->Xdot,th->shift,J,Jpre,PETSC_FALSE));
7935f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMatMult(J,ts->mat_sensip,MAT_REUSE_MATRIX,PETSC_DEFAULT,&MatDeltaFwdSensip));
7945f80ce2aSJacob Faibussowitsch     CHKERRQ(MatScale(MatDeltaFwdSensip,-1.));
79513b1b0ffSHong Zhang 
796022c081aSHong Zhang     /* Add the f_p forcing terms */
7970e11c21fSHong Zhang     if (ts->Jacp) {
79882ad9101SHong Zhang       th->shift = previous_shift;
7995f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPBYPCZ(th->Xdot,-th->shift,th->shift,0,th->X0,th->X));
8005f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeIJacobianP(ts,th->stage_time,th->X,th->Xdot,th->shift,ts->Jacp,PETSC_FALSE));
8015f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(MatDeltaFwdSensip,-1.,ts->Jacp,SUBSET_NONZERO_PATTERN));
802715f1b00SHong Zhang     }
8030e11c21fSHong Zhang   }
804715f1b00SHong Zhang 
805715f1b00SHong Zhang   /* Build LHS */
8061a352fa8SHong Zhang   th->shift = previous_shift; /* recover the previous shift used in TSStep_Theta() */
807715f1b00SHong Zhang   if (th->endpoint) {
8085f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIJacobian(ts,th->stage_time,ts->vec_sol,th->Xdot,th->shift,J,Jpre,PETSC_FALSE));
809715f1b00SHong Zhang   } else {
8105f80ce2aSJacob Faibussowitsch     CHKERRQ(TSComputeIJacobian(ts,th->stage_time,th->X,th->Xdot,th->shift,J,Jpre,PETSC_FALSE));
811715f1b00SHong Zhang   }
8125f80ce2aSJacob Faibussowitsch   CHKERRQ(KSPSetOperators(ksp,J,Jpre));
813715f1b00SHong Zhang 
814715f1b00SHong Zhang   /*
815715f1b00SHong Zhang     Evaluate the first stage of integral gradients with the 2-stage method:
816c9ad9de0SHong Zhang     drdu|t_n*S(t_n) + drdp|t_n
817715f1b00SHong Zhang     This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1})
818715f1b00SHong Zhang   */
819715f1b00SHong Zhang   if (th->endpoint) { /* 2-stage method only */
8207207e0fdSHong Zhang     if (quadts && quadts->mat_sensip) {
8215f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,th->ptime0,th->X0,quadJ,NULL));
8225f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobianP(quadts,th->ptime0,th->X0,quadJp));
8235f80ce2aSJacob Faibussowitsch       CHKERRQ(MatTransposeMatMult(ts->mat_sensip,quadJ,MAT_REUSE_MATRIX,PETSC_DEFAULT,&th->MatIntegralSensipTemp));
8245f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(th->MatIntegralSensipTemp,1,quadJp,SAME_NONZERO_PATTERN));
8255f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(quadts->mat_sensip,th->time_step0*(1.-th->Theta),th->MatIntegralSensipTemp,SAME_NONZERO_PATTERN));
826715f1b00SHong Zhang     }
827715f1b00SHong Zhang   }
828715f1b00SHong Zhang 
829715f1b00SHong Zhang   /* Solve the tangent linear equation for forward sensitivities to parameters */
830022c081aSHong Zhang   for (ntlm=0; ntlm<th->num_tlm; ntlm++) {
831b5b4017aSHong Zhang     KSPConvergedReason kspreason;
8325f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetColumn(MatDeltaFwdSensip,ntlm,&barr));
8335f80ce2aSJacob Faibussowitsch     CHKERRQ(VecPlaceArray(VecDeltaFwdSensipCol,barr));
834715f1b00SHong Zhang     if (th->endpoint) {
8355f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseGetColumn(ts->mat_sensip,ntlm,&xarr));
8365f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(ts->vec_sensip_col,xarr));
8375f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSolve(ksp,VecDeltaFwdSensipCol,ts->vec_sensip_col));
8385f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(ts->vec_sensip_col));
8395f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseRestoreColumn(ts->mat_sensip,&xarr));
840715f1b00SHong Zhang     } else {
8415f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSolve(ksp,VecDeltaFwdSensipCol,VecDeltaFwdSensipCol));
842715f1b00SHong Zhang     }
8435f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPGetConvergedReason(ksp,&kspreason));
844b5b4017aSHong Zhang     if (kspreason < 0) {
845b5b4017aSHong Zhang       ts->reason = TSFORWARD_DIVERGED_LINEAR_SOLVE;
8465f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(ts,"Step=%D, %Dth tangent linear solve, linear solve fails, stopping tangent linear solve\n",ts->steps,ntlm));
847b5b4017aSHong Zhang     }
8485f80ce2aSJacob Faibussowitsch     CHKERRQ(VecResetArray(VecDeltaFwdSensipCol));
8495f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreColumn(MatDeltaFwdSensip,&barr));
850715f1b00SHong Zhang   }
851715f1b00SHong Zhang 
85213b1b0ffSHong Zhang   /*
85313b1b0ffSHong Zhang     Evaluate the second stage of integral gradients with the 2-stage method:
854c9ad9de0SHong Zhang     drdu|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1}
85513b1b0ffSHong Zhang   */
8567207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
85713b1b0ffSHong Zhang     if (!th->endpoint) {
8585f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(ts->mat_sensip,1,MatDeltaFwdSensip,SAME_NONZERO_PATTERN)); /* stage sensitivity */
8595f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,th->stage_time,th->X,quadJ,NULL));
8605f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobianP(quadts,th->stage_time,th->X,quadJp));
8615f80ce2aSJacob Faibussowitsch       CHKERRQ(MatTransposeMatMult(ts->mat_sensip,quadJ,MAT_REUSE_MATRIX,PETSC_DEFAULT,&th->MatIntegralSensipTemp));
8625f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(th->MatIntegralSensipTemp,1,quadJp,SAME_NONZERO_PATTERN));
8635f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(quadts->mat_sensip,th->time_step0,th->MatIntegralSensipTemp,SAME_NONZERO_PATTERN));
8645f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(ts->mat_sensip,(1.-th->Theta)/th->Theta,MatDeltaFwdSensip,SAME_NONZERO_PATTERN));
86513b1b0ffSHong Zhang     } else {
8665f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobian(quadts,th->stage_time,ts->vec_sol,quadJ,NULL));
8675f80ce2aSJacob Faibussowitsch       CHKERRQ(TSComputeRHSJacobianP(quadts,th->stage_time,ts->vec_sol,quadJp));
8685f80ce2aSJacob Faibussowitsch       CHKERRQ(MatTransposeMatMult(ts->mat_sensip,quadJ,MAT_REUSE_MATRIX,PETSC_DEFAULT,&th->MatIntegralSensipTemp));
8695f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(th->MatIntegralSensipTemp,1,quadJp,SAME_NONZERO_PATTERN));
8705f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(quadts->mat_sensip,th->time_step0*th->Theta,th->MatIntegralSensipTemp,SAME_NONZERO_PATTERN));
87113b1b0ffSHong Zhang     }
87213b1b0ffSHong Zhang   } else {
87313b1b0ffSHong Zhang     if (!th->endpoint) {
8745f80ce2aSJacob Faibussowitsch       CHKERRQ(MatAXPY(ts->mat_sensip,1./th->Theta,MatDeltaFwdSensip,SAME_NONZERO_PATTERN));
875715f1b00SHong Zhang     }
876715f1b00SHong Zhang   }
8771566a47fSLisandro Dalcin   PetscFunctionReturn(0);
8781566a47fSLisandro Dalcin }
8791566a47fSLisandro Dalcin 
880cc4f23bcSHong Zhang static PetscErrorCode TSForwardGetStages_Theta(TS ts,PetscInt *ns,Mat *stagesensip[])
8816affb6f8SHong Zhang {
8826affb6f8SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
8836affb6f8SHong Zhang 
8846affb6f8SHong Zhang   PetscFunctionBegin;
8857409eceaSHong Zhang   if (ns) {
8867409eceaSHong Zhang     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
8877409eceaSHong Zhang     else *ns = 2; /* endpoint form */
8887409eceaSHong Zhang   }
8895072d23cSHong Zhang   if (stagesensip) {
890cc4f23bcSHong Zhang     if (!th->endpoint && th->Theta != 1.0) {
8917409eceaSHong Zhang       th->MatFwdStages[0] = th->MatDeltaFwdSensip;
892cc4f23bcSHong Zhang     } else {
893cc4f23bcSHong Zhang       th->MatFwdStages[0] = th->MatFwdSensip0;
894cc4f23bcSHong Zhang       th->MatFwdStages[1] = ts->mat_sensip; /* stiffly accurate */
895cc4f23bcSHong Zhang     }
896cc4f23bcSHong Zhang     *stagesensip = th->MatFwdStages;
8975072d23cSHong Zhang   }
8986affb6f8SHong Zhang   PetscFunctionReturn(0);
8996affb6f8SHong Zhang }
9006affb6f8SHong Zhang 
901316643e7SJed Brown /*------------------------------------------------------------*/
902277b19d0SLisandro Dalcin static PetscErrorCode TSReset_Theta(TS ts)
903316643e7SJed Brown {
904316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
905316643e7SJed Brown 
906316643e7SJed Brown   PetscFunctionBegin;
9075f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->X));
9085f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->Xdot));
9095f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->X0));
9105f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->affine));
9111566a47fSLisandro Dalcin 
9125f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->vec_sol_prev));
9135f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->vec_lte_work));
9141566a47fSLisandro Dalcin 
9155f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->VecCostIntegral0));
916277b19d0SLisandro Dalcin   PetscFunctionReturn(0);
917277b19d0SLisandro Dalcin }
918277b19d0SLisandro Dalcin 
919ece46509SHong Zhang static PetscErrorCode TSAdjointReset_Theta(TS ts)
920ece46509SHong Zhang {
921ece46509SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
922ece46509SHong Zhang 
923ece46509SHong Zhang   PetscFunctionBegin;
9245f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroyVecs(ts->numcost,&th->VecsDeltaLam));
9255f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroyVecs(ts->numcost,&th->VecsDeltaMu));
9265f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroyVecs(ts->numcost,&th->VecsDeltaLam2));
9275f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroyVecs(ts->numcost,&th->VecsDeltaMu2));
9285f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroyVecs(ts->numcost,&th->VecsSensiTemp));
9295f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroyVecs(ts->numcost,&th->VecsSensi2Temp));
930ece46509SHong Zhang   PetscFunctionReturn(0);
931ece46509SHong Zhang }
932ece46509SHong Zhang 
933277b19d0SLisandro Dalcin static PetscErrorCode TSDestroy_Theta(TS ts)
934277b19d0SLisandro Dalcin {
935277b19d0SLisandro Dalcin   PetscFunctionBegin;
9365f80ce2aSJacob Faibussowitsch   CHKERRQ(TSReset_Theta(ts));
937b3a6b972SJed Brown   if (ts->dm) {
9385f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCoarsenHookRemove(ts->dm,DMCoarsenHook_TSTheta,DMRestrictHook_TSTheta,ts));
9395f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSubDomainHookRemove(ts->dm,DMSubDomainHook_TSTheta,DMSubDomainRestrictHook_TSTheta,ts));
940b3a6b972SJed Brown   }
9415f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(ts->data));
9425f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetTheta_C",NULL));
9435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetTheta_C",NULL));
9445f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetEndpoint_C",NULL));
9455f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetEndpoint_C",NULL));
946316643e7SJed Brown   PetscFunctionReturn(0);
947316643e7SJed Brown }
948316643e7SJed Brown 
949316643e7SJed Brown /*
950316643e7SJed Brown   This defines the nonlinear equation that is to be solved with SNES
9512b5a38e1SLisandro Dalcin   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
9520fd10508SMatthew Knepley 
9530fd10508SMatthew Knepley   Note that U here is the stage argument. This means that U = U_{n+1} only if endpoint = true,
9540fd10508SMatthew Knepley   otherwise U = theta U_{n+1} + (1 - theta) U0, which for the case of implicit midpoint is
9550fd10508SMatthew Knepley   U = (U_{n+1} + U0)/2
956316643e7SJed Brown */
9570f5c6efeSJed Brown static PetscErrorCode SNESTSFormFunction_Theta(SNES snes,Vec x,Vec y,TS ts)
958316643e7SJed Brown {
959316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
9607445fe48SJed Brown   Vec            X0,Xdot;
9617445fe48SJed Brown   DM             dm,dmsave;
9623e05ceb1SHong Zhang   PetscReal      shift = th->shift;
963316643e7SJed Brown 
964316643e7SJed Brown   PetscFunctionBegin;
9655f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetDM(snes,&dm));
9665a3a76d0SJed Brown   /* When using the endpoint variant, this is actually 1/Theta * Xdot */
9675f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaGetX0AndXdot(ts,dm,&X0,&Xdot));
968494ce9fcSHong Zhang   if (x != X0) {
9695f80ce2aSJacob Faibussowitsch     CHKERRQ(VecAXPBYPCZ(Xdot,-shift,shift,0,X0,x));
970494ce9fcSHong Zhang   } else {
9715f80ce2aSJacob Faibussowitsch     CHKERRQ(VecZeroEntries(Xdot));
972494ce9fcSHong Zhang   }
9737445fe48SJed Brown   /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */
9747445fe48SJed Brown   dmsave = ts->dm;
9757445fe48SJed Brown   ts->dm = dm;
9765f80ce2aSJacob Faibussowitsch   CHKERRQ(TSComputeIFunction(ts,th->stage_time,x,Xdot,y,PETSC_FALSE));
9777445fe48SJed Brown   ts->dm = dmsave;
9785f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaRestoreX0AndXdot(ts,dm,&X0,&Xdot));
979316643e7SJed Brown   PetscFunctionReturn(0);
980316643e7SJed Brown }
981316643e7SJed Brown 
982d1e9a80fSBarry Smith static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes,Vec x,Mat A,Mat B,TS ts)
983316643e7SJed Brown {
984316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
9857445fe48SJed Brown   Vec            Xdot;
9867445fe48SJed Brown   DM             dm,dmsave;
9873e05ceb1SHong Zhang   PetscReal      shift = th->shift;
988316643e7SJed Brown 
989316643e7SJed Brown   PetscFunctionBegin;
9905f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetDM(snes,&dm));
991be5899b3SLisandro Dalcin   /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */
9925f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaGetX0AndXdot(ts,dm,NULL,&Xdot));
9937445fe48SJed Brown 
9947445fe48SJed Brown   dmsave = ts->dm;
9957445fe48SJed Brown   ts->dm = dm;
9965f80ce2aSJacob Faibussowitsch   CHKERRQ(TSComputeIJacobian(ts,th->stage_time,x,Xdot,shift,A,B,PETSC_FALSE));
9977445fe48SJed Brown   ts->dm = dmsave;
9985f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaRestoreX0AndXdot(ts,dm,NULL,&Xdot));
999316643e7SJed Brown   PetscFunctionReturn(0);
1000316643e7SJed Brown }
1001316643e7SJed Brown 
1002715f1b00SHong Zhang static PetscErrorCode TSForwardSetUp_Theta(TS ts)
1003715f1b00SHong Zhang {
1004715f1b00SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
10057207e0fdSHong Zhang   TS             quadts = ts->quadraturets;
1006715f1b00SHong Zhang 
1007715f1b00SHong Zhang   PetscFunctionBegin;
1008022c081aSHong Zhang   /* combine sensitivities to parameters and sensitivities to initial values into one array */
100913b1b0ffSHong Zhang   th->num_tlm = ts->num_parameters;
10105f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDuplicate(ts->mat_sensip,MAT_DO_NOT_COPY_VALUES,&th->MatDeltaFwdSensip));
10117207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
10125f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(quadts->mat_sensip,MAT_DO_NOT_COPY_VALUES,&th->MatIntegralSensipTemp));
10135f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(quadts->mat_sensip,MAT_DO_NOT_COPY_VALUES,&th->MatIntegralSensip0));
1014715f1b00SHong Zhang   }
10156f92202bSHong Zhang   /* backup sensitivity results for roll-backs */
10165f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDuplicate(ts->mat_sensip,MAT_DO_NOT_COPY_VALUES,&th->MatFwdSensip0));
101713b1b0ffSHong Zhang 
10185f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(ts->vec_sol,&th->VecDeltaFwdSensipCol));
1019715f1b00SHong Zhang   PetscFunctionReturn(0);
1020715f1b00SHong Zhang }
1021715f1b00SHong Zhang 
10227adebddeSHong Zhang static PetscErrorCode TSForwardReset_Theta(TS ts)
10237adebddeSHong Zhang {
10247adebddeSHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
10257207e0fdSHong Zhang   TS             quadts = ts->quadraturets;
10267adebddeSHong Zhang 
10277adebddeSHong Zhang   PetscFunctionBegin;
10287207e0fdSHong Zhang   if (quadts && quadts->mat_sensip) {
10295f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&th->MatIntegralSensipTemp));
10305f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&th->MatIntegralSensip0));
10317adebddeSHong Zhang   }
10325f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&th->VecDeltaFwdSensipCol));
10335f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&th->MatDeltaFwdSensip));
10345f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&th->MatFwdSensip0));
10357adebddeSHong Zhang   PetscFunctionReturn(0);
10367adebddeSHong Zhang }
10377adebddeSHong Zhang 
1038316643e7SJed Brown static PetscErrorCode TSSetUp_Theta(TS ts)
1039316643e7SJed Brown {
1040316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
1041cd4cee2dSHong Zhang   TS             quadts = ts->quadraturets;
10422ffb9264SLisandro Dalcin   PetscBool      match;
1043316643e7SJed Brown 
1044316643e7SJed Brown   PetscFunctionBegin;
1045cd4cee2dSHong Zhang   if (!th->VecCostIntegral0 && quadts && ts->costintegralfwd) { /* back up cost integral */
10465f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(quadts->vec_sol,&th->VecCostIntegral0));
1047b1cb36f3SHong Zhang   }
104839d13666SHong Zhang   if (!th->X) {
10495f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(ts->vec_sol,&th->X));
105039d13666SHong Zhang   }
105139d13666SHong Zhang   if (!th->Xdot) {
10525f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(ts->vec_sol,&th->Xdot));
105339d13666SHong Zhang   }
105439d13666SHong Zhang   if (!th->X0) {
10555f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(ts->vec_sol,&th->X0));
105639d13666SHong Zhang   }
10571566a47fSLisandro Dalcin   if (th->endpoint) {
10585f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(ts->vec_sol,&th->affine));
10597445fe48SJed Brown   }
10603b1890cdSShri Abhyankar 
10611566a47fSLisandro Dalcin   th->order = (th->Theta == 0.5) ? 2 : 1;
106220d49056SMatthew G. Knepley   th->shift = 1/(th->Theta*ts->time_step);
10631566a47fSLisandro Dalcin 
10645f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetDM(ts,&ts->dm));
10655f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCoarsenHookAdd(ts->dm,DMCoarsenHook_TSTheta,DMRestrictHook_TSTheta,ts));
10665f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSubDomainHookAdd(ts->dm,DMSubDomainHook_TSTheta,DMSubDomainRestrictHook_TSTheta,ts));
10671566a47fSLisandro Dalcin 
10685f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetAdapt(ts,&ts->adapt));
10695f80ce2aSJacob Faibussowitsch   CHKERRQ(TSAdaptCandidatesClear(ts->adapt));
10705f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)ts->adapt,TSADAPTNONE,&match));
10712ffb9264SLisandro Dalcin   if (!match) {
10725f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(ts->vec_sol,&th->vec_sol_prev));
10735f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(ts->vec_sol,&th->vec_lte_work));
10743b1890cdSShri Abhyankar   }
10755f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetSNES(ts,&ts->snes));
1076cc4f23bcSHong Zhang 
1077cc4f23bcSHong Zhang   ts->stifflyaccurate = (!th->endpoint && th->Theta != 1.0) ? PETSC_FALSE : PETSC_TRUE;
1078b4dd3bf9SBarry Smith   PetscFunctionReturn(0);
1079b4dd3bf9SBarry Smith }
10800c7376e5SHong Zhang 
1081b4dd3bf9SBarry Smith /*------------------------------------------------------------*/
1082b4dd3bf9SBarry Smith 
1083b4dd3bf9SBarry Smith static PetscErrorCode TSAdjointSetUp_Theta(TS ts)
1084b4dd3bf9SBarry Smith {
1085b4dd3bf9SBarry Smith   TS_Theta       *th = (TS_Theta*)ts->data;
1086b4dd3bf9SBarry Smith 
1087b4dd3bf9SBarry Smith   PetscFunctionBegin;
10885f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&th->VecsDeltaLam));
10895f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&th->VecsSensiTemp));
10902ca6e920SHong Zhang   if (ts->vecs_sensip) {
10915f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicateVecs(ts->vecs_sensip[0],ts->numcost,&th->VecsDeltaMu));
10922ca6e920SHong Zhang   }
1093b5b4017aSHong Zhang   if (ts->vecs_sensi2) {
10945f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&th->VecsDeltaLam2));
10955f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicateVecs(ts->vecs_sensi2[0],ts->numcost,&th->VecsSensi2Temp));
109667633408SHong Zhang     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
109767633408SHong Zhang     if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu;
109867633408SHong Zhang     if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup;
1099b5b4017aSHong Zhang   }
1100c9681e5dSHong Zhang   if (ts->vecs_sensi2p) {
11015f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicateVecs(ts->vecs_sensi2p[0],ts->numcost,&th->VecsDeltaMu2));
110267633408SHong Zhang     /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */
110367633408SHong Zhang     if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu;
110467633408SHong Zhang     if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp;
1105b5b4017aSHong Zhang   }
1106316643e7SJed Brown   PetscFunctionReturn(0);
1107316643e7SJed Brown }
1108316643e7SJed Brown 
11094416b707SBarry Smith static PetscErrorCode TSSetFromOptions_Theta(PetscOptionItems *PetscOptionsObject,TS ts)
1110316643e7SJed Brown {
1111316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
1112316643e7SJed Brown 
1113316643e7SJed Brown   PetscFunctionBegin;
11145f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHead(PetscOptionsObject,"Theta ODE solver options"));
1115316643e7SJed Brown   {
11165f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscOptionsReal("-ts_theta_theta","Location of stage (0<Theta<=1)","TSThetaSetTheta",th->Theta,&th->Theta,NULL));
11175f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscOptionsBool("-ts_theta_endpoint","Use the endpoint instead of midpoint form of the Theta method","TSThetaSetEndpoint",th->endpoint,&th->endpoint,NULL));
11185f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscOptionsBool("-ts_theta_initial_guess_extrapolate","Extrapolate stage initial guess from previous solution (sometimes unstable)","TSThetaSetExtrapolate",th->extrapolate,&th->extrapolate,NULL));
1119316643e7SJed Brown   }
11205f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsTail());
1121316643e7SJed Brown   PetscFunctionReturn(0);
1122316643e7SJed Brown }
1123316643e7SJed Brown 
1124316643e7SJed Brown static PetscErrorCode TSView_Theta(TS ts,PetscViewer viewer)
1125316643e7SJed Brown {
1126316643e7SJed Brown   TS_Theta       *th = (TS_Theta*)ts->data;
1127ace3abfcSBarry Smith   PetscBool      iascii;
1128316643e7SJed Brown 
1129316643e7SJed Brown   PetscFunctionBegin;
11305f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1131316643e7SJed Brown   if (iascii) {
11325f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer,"  Theta=%g\n",(double)th->Theta));
11335f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer,"  Extrapolation=%s\n",th->extrapolate ? "yes" : "no"));
1134316643e7SJed Brown   }
1135316643e7SJed Brown   PetscFunctionReturn(0);
1136316643e7SJed Brown }
1137316643e7SJed Brown 
1138560360afSLisandro Dalcin static PetscErrorCode TSThetaGetTheta_Theta(TS ts,PetscReal *theta)
11390de4c49aSJed Brown {
11400de4c49aSJed Brown   TS_Theta *th = (TS_Theta*)ts->data;
11410de4c49aSJed Brown 
11420de4c49aSJed Brown   PetscFunctionBegin;
11430de4c49aSJed Brown   *theta = th->Theta;
11440de4c49aSJed Brown   PetscFunctionReturn(0);
11450de4c49aSJed Brown }
11460de4c49aSJed Brown 
1147560360afSLisandro Dalcin static PetscErrorCode TSThetaSetTheta_Theta(TS ts,PetscReal theta)
11480de4c49aSJed Brown {
11490de4c49aSJed Brown   TS_Theta *th = (TS_Theta*)ts->data;
11500de4c49aSJed Brown 
11510de4c49aSJed Brown   PetscFunctionBegin;
11522c71b3e2SJacob Faibussowitsch   PetscCheckFalse(theta <= 0 || 1 < theta,PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Theta %g not in range (0,1]",(double)theta);
11530de4c49aSJed Brown   th->Theta = theta;
11541566a47fSLisandro Dalcin   th->order = (th->Theta == 0.5) ? 2 : 1;
11550de4c49aSJed Brown   PetscFunctionReturn(0);
11560de4c49aSJed Brown }
1157eb284becSJed Brown 
1158560360afSLisandro Dalcin static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts,PetscBool *endpoint)
115926f2ff8fSLisandro Dalcin {
116026f2ff8fSLisandro Dalcin   TS_Theta *th = (TS_Theta*)ts->data;
116126f2ff8fSLisandro Dalcin 
116226f2ff8fSLisandro Dalcin   PetscFunctionBegin;
116326f2ff8fSLisandro Dalcin   *endpoint = th->endpoint;
116426f2ff8fSLisandro Dalcin   PetscFunctionReturn(0);
116526f2ff8fSLisandro Dalcin }
116626f2ff8fSLisandro Dalcin 
1167560360afSLisandro Dalcin static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts,PetscBool flg)
1168eb284becSJed Brown {
1169eb284becSJed Brown   TS_Theta *th = (TS_Theta*)ts->data;
1170eb284becSJed Brown 
1171eb284becSJed Brown   PetscFunctionBegin;
1172eb284becSJed Brown   th->endpoint = flg;
1173eb284becSJed Brown   PetscFunctionReturn(0);
1174eb284becSJed Brown }
11750de4c49aSJed Brown 
1176f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX)
1177f9c1d6abSBarry Smith static PetscErrorCode TSComputeLinearStability_Theta(TS ts,PetscReal xr,PetscReal xi,PetscReal *yr,PetscReal *yi)
1178f9c1d6abSBarry Smith {
1179f9c1d6abSBarry Smith   PetscComplex   z   = xr + xi*PETSC_i,f;
1180f9c1d6abSBarry Smith   TS_Theta       *th = (TS_Theta*)ts->data;
11813fd8ae06SJed Brown   const PetscReal one = 1.0;
1182f9c1d6abSBarry Smith 
1183f9c1d6abSBarry Smith   PetscFunctionBegin;
11843fd8ae06SJed Brown   f   = (one + (one - th->Theta)*z)/(one - th->Theta*z);
1185f9c1d6abSBarry Smith   *yr = PetscRealPartComplex(f);
1186f9c1d6abSBarry Smith   *yi = PetscImaginaryPartComplex(f);
1187f9c1d6abSBarry Smith   PetscFunctionReturn(0);
1188f9c1d6abSBarry Smith }
1189f9c1d6abSBarry Smith #endif
1190f9c1d6abSBarry Smith 
1191cc4f23bcSHong Zhang static PetscErrorCode TSGetStages_Theta(TS ts,PetscInt *ns,Vec *Y[])
119242682096SHong Zhang {
119342682096SHong Zhang   TS_Theta       *th = (TS_Theta*)ts->data;
119442682096SHong Zhang 
119542682096SHong Zhang   PetscFunctionBegin;
11967409eceaSHong Zhang   if (ns) {
11977409eceaSHong Zhang     if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */
11987409eceaSHong Zhang     else *ns = 2; /* endpoint form */
11997409eceaSHong Zhang   }
12005072d23cSHong Zhang   if (Y) {
1201cc4f23bcSHong Zhang     if (!th->endpoint && th->Theta != 1.0) {
12027409eceaSHong Zhang       th->Stages[0] = th->X;
1203cc4f23bcSHong Zhang     } else {
1204cc4f23bcSHong Zhang       th->Stages[0] = th->X0;
1205cc4f23bcSHong Zhang       th->Stages[1] = ts->vec_sol; /* stiffly accurate */
1206cc4f23bcSHong Zhang     }
1207cc4f23bcSHong Zhang     *Y = th->Stages;
12085072d23cSHong Zhang   }
120942682096SHong Zhang   PetscFunctionReturn(0);
121042682096SHong Zhang }
1211f9c1d6abSBarry Smith 
1212316643e7SJed Brown /* ------------------------------------------------------------ */
1213316643e7SJed Brown /*MC
121496f5712cSJed Brown       TSTHETA - DAE solver using the implicit Theta method
1215316643e7SJed Brown 
1216316643e7SJed Brown    Level: beginner
1217316643e7SJed Brown 
12184eb428fdSBarry Smith    Options Database:
1219c82ed962SBarry Smith +  -ts_theta_theta <Theta> - Location of stage (0<Theta<=1)
1220c82ed962SBarry Smith .  -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method
122103842d09SLisandro Dalcin -  -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable)
12224eb428fdSBarry Smith 
1223eb284becSJed Brown    Notes:
12240c3ba866SJed Brown $  -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER)
12250c3ba866SJed Brown $  -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule
12264eb428fdSBarry Smith $  -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN)
12274eb428fdSBarry Smith 
12287409eceaSHong Zhang    The endpoint variant of the Theta method and backward Euler can be applied to DAE. The midpoint variant is not suitable for DAEs because it is not stiffly accurate.
1229eb284becSJed Brown 
12307409eceaSHong Zhang    The midpoint variant is cast as a 1-stage implicit Runge-Kutta method.
1231eb284becSJed Brown 
1232eb284becSJed Brown .vb
1233eb284becSJed Brown   Theta | Theta
1234eb284becSJed Brown   -------------
1235eb284becSJed Brown         |  1
1236eb284becSJed Brown .ve
1237eb284becSJed Brown 
1238eb284becSJed Brown    For the default Theta=0.5, this is also known as the implicit midpoint rule.
1239eb284becSJed Brown 
1240eb284becSJed Brown    When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit:
1241eb284becSJed Brown 
1242eb284becSJed Brown .vb
1243eb284becSJed Brown   0 | 0         0
1244eb284becSJed Brown   1 | 1-Theta   Theta
1245eb284becSJed Brown   -------------------
1246eb284becSJed Brown     | 1-Theta   Theta
1247eb284becSJed Brown .ve
1248eb284becSJed Brown 
1249eb284becSJed Brown    For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN).
1250eb284becSJed Brown 
1251eb284becSJed Brown    To apply a diagonally implicit RK method to DAE, the stage formula
1252eb284becSJed Brown 
1253eb284becSJed Brown $  Y_i = X + h sum_j a_ij Y'_j
1254eb284becSJed Brown 
12554eb428fdSBarry Smith    is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i)
1256eb284becSJed Brown 
1257eb284becSJed Brown .seealso:  TSCreate(), TS, TSSetType(), TSCN, TSBEULER, TSThetaSetTheta(), TSThetaSetEndpoint()
1258316643e7SJed Brown 
1259316643e7SJed Brown M*/
12608cc058d9SJed Brown PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts)
1261316643e7SJed Brown {
1262316643e7SJed Brown   TS_Theta       *th;
1263316643e7SJed Brown 
1264316643e7SJed Brown   PetscFunctionBegin;
1265277b19d0SLisandro Dalcin   ts->ops->reset           = TSReset_Theta;
1266ece46509SHong Zhang   ts->ops->adjointreset    = TSAdjointReset_Theta;
1267316643e7SJed Brown   ts->ops->destroy         = TSDestroy_Theta;
1268316643e7SJed Brown   ts->ops->view            = TSView_Theta;
1269316643e7SJed Brown   ts->ops->setup           = TSSetUp_Theta;
127042f2b339SBarry Smith   ts->ops->adjointsetup    = TSAdjointSetUp_Theta;
1271ece46509SHong Zhang   ts->ops->adjointreset    = TSAdjointReset_Theta;
1272316643e7SJed Brown   ts->ops->step            = TSStep_Theta;
1273cd652676SJed Brown   ts->ops->interpolate     = TSInterpolate_Theta;
12741566a47fSLisandro Dalcin   ts->ops->evaluatewlte    = TSEvaluateWLTE_Theta;
127524655328SShri   ts->ops->rollback        = TSRollBack_Theta;
1276316643e7SJed Brown   ts->ops->setfromoptions  = TSSetFromOptions_Theta;
12770f5c6efeSJed Brown   ts->ops->snesfunction    = SNESTSFormFunction_Theta;
12780f5c6efeSJed Brown   ts->ops->snesjacobian    = SNESTSFormJacobian_Theta;
1279f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX)
1280f9c1d6abSBarry Smith   ts->ops->linearstability = TSComputeLinearStability_Theta;
1281f9c1d6abSBarry Smith #endif
128242682096SHong Zhang   ts->ops->getstages       = TSGetStages_Theta;
128342f2b339SBarry Smith   ts->ops->adjointstep     = TSAdjointStep_Theta;
1284b1cb36f3SHong Zhang   ts->ops->adjointintegral = TSAdjointCostIntegral_Theta;
1285b1cb36f3SHong Zhang   ts->ops->forwardintegral = TSForwardCostIntegral_Theta;
12862ffb9264SLisandro Dalcin   ts->default_adapt_type   = TSADAPTNONE;
12876affb6f8SHong Zhang 
1288715f1b00SHong Zhang   ts->ops->forwardsetup     = TSForwardSetUp_Theta;
12897adebddeSHong Zhang   ts->ops->forwardreset     = TSForwardReset_Theta;
1290715f1b00SHong Zhang   ts->ops->forwardstep      = TSForwardStep_Theta;
12916affb6f8SHong Zhang   ts->ops->forwardgetstages = TSForwardGetStages_Theta;
1292316643e7SJed Brown 
1293efd4aadfSBarry Smith   ts->usessnes = PETSC_TRUE;
1294efd4aadfSBarry Smith 
12955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNewLog(ts,&th));
1296316643e7SJed Brown   ts->data = (void*)th;
1297316643e7SJed Brown 
1298715f1b00SHong Zhang   th->VecsDeltaLam    = NULL;
1299715f1b00SHong Zhang   th->VecsDeltaMu     = NULL;
1300715f1b00SHong Zhang   th->VecsSensiTemp   = NULL;
1301b5b4017aSHong Zhang   th->VecsSensi2Temp  = NULL;
1302715f1b00SHong Zhang 
13036f700aefSJed Brown   th->extrapolate = PETSC_FALSE;
1304316643e7SJed Brown   th->Theta       = 0.5;
13051566a47fSLisandro Dalcin   th->order       = 2;
13065f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetTheta_C",TSThetaGetTheta_Theta));
13075f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetTheta_C",TSThetaSetTheta_Theta));
13085f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaGetEndpoint_C",TSThetaGetEndpoint_Theta));
13095f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)ts,"TSThetaSetEndpoint_C",TSThetaSetEndpoint_Theta));
1310316643e7SJed Brown   PetscFunctionReturn(0);
1311316643e7SJed Brown }
13120de4c49aSJed Brown 
13130de4c49aSJed Brown /*@
13140de4c49aSJed Brown   TSThetaGetTheta - Get the abscissa of the stage in (0,1].
13150de4c49aSJed Brown 
13160de4c49aSJed Brown   Not Collective
13170de4c49aSJed Brown 
13180de4c49aSJed Brown   Input Parameter:
13190de4c49aSJed Brown .  ts - timestepping context
13200de4c49aSJed Brown 
13210de4c49aSJed Brown   Output Parameter:
13220de4c49aSJed Brown .  theta - stage abscissa
13230de4c49aSJed Brown 
13240de4c49aSJed Brown   Note:
13250de4c49aSJed Brown   Use of this function is normally only required to hack TSTHETA to use a modified integration scheme.
13260de4c49aSJed Brown 
13270de4c49aSJed Brown   Level: Advanced
13280de4c49aSJed Brown 
13290de4c49aSJed Brown .seealso: TSThetaSetTheta()
13300de4c49aSJed Brown @*/
13317087cfbeSBarry Smith PetscErrorCode  TSThetaGetTheta(TS ts,PetscReal *theta)
13320de4c49aSJed Brown {
13330de4c49aSJed Brown   PetscFunctionBegin;
1334afb20b64SJed Brown   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
13350de4c49aSJed Brown   PetscValidPointer(theta,2);
13365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscUseMethod(ts,"TSThetaGetTheta_C",(TS,PetscReal*),(ts,theta)));
13370de4c49aSJed Brown   PetscFunctionReturn(0);
13380de4c49aSJed Brown }
13390de4c49aSJed Brown 
13400de4c49aSJed Brown /*@
13410de4c49aSJed Brown   TSThetaSetTheta - Set the abscissa of the stage in (0,1].
13420de4c49aSJed Brown 
13430de4c49aSJed Brown   Not Collective
13440de4c49aSJed Brown 
1345d8d19677SJose E. Roman   Input Parameters:
13460de4c49aSJed Brown +  ts - timestepping context
13470de4c49aSJed Brown -  theta - stage abscissa
13480de4c49aSJed Brown 
13490de4c49aSJed Brown   Options Database:
135067b8a455SSatish Balay .  -ts_theta_theta <theta> - set theta
13510de4c49aSJed Brown 
13520de4c49aSJed Brown   Level: Intermediate
13530de4c49aSJed Brown 
13540de4c49aSJed Brown .seealso: TSThetaGetTheta()
13550de4c49aSJed Brown @*/
13567087cfbeSBarry Smith PetscErrorCode  TSThetaSetTheta(TS ts,PetscReal theta)
13570de4c49aSJed Brown {
13580de4c49aSJed Brown   PetscFunctionBegin;
1359afb20b64SJed Brown   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
13605f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTryMethod(ts,"TSThetaSetTheta_C",(TS,PetscReal),(ts,theta)));
13610de4c49aSJed Brown   PetscFunctionReturn(0);
13620de4c49aSJed Brown }
1363f33bbcb6SJed Brown 
136426f2ff8fSLisandro Dalcin /*@
136526f2ff8fSLisandro Dalcin   TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule).
136626f2ff8fSLisandro Dalcin 
136726f2ff8fSLisandro Dalcin   Not Collective
136826f2ff8fSLisandro Dalcin 
136926f2ff8fSLisandro Dalcin   Input Parameter:
137026f2ff8fSLisandro Dalcin .  ts - timestepping context
137126f2ff8fSLisandro Dalcin 
137226f2ff8fSLisandro Dalcin   Output Parameter:
137326f2ff8fSLisandro Dalcin .  endpoint - PETSC_TRUE when using the endpoint variant
137426f2ff8fSLisandro Dalcin 
137526f2ff8fSLisandro Dalcin   Level: Advanced
137626f2ff8fSLisandro Dalcin 
137726f2ff8fSLisandro Dalcin .seealso: TSThetaSetEndpoint(), TSTHETA, TSCN
137826f2ff8fSLisandro Dalcin @*/
137926f2ff8fSLisandro Dalcin PetscErrorCode TSThetaGetEndpoint(TS ts,PetscBool *endpoint)
138026f2ff8fSLisandro Dalcin {
138126f2ff8fSLisandro Dalcin   PetscFunctionBegin;
138226f2ff8fSLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
138326f2ff8fSLisandro Dalcin   PetscValidPointer(endpoint,2);
13845f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscUseMethod(ts,"TSThetaGetEndpoint_C",(TS,PetscBool*),(ts,endpoint)));
138526f2ff8fSLisandro Dalcin   PetscFunctionReturn(0);
138626f2ff8fSLisandro Dalcin }
138726f2ff8fSLisandro Dalcin 
1388eb284becSJed Brown /*@
1389eb284becSJed Brown   TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule).
1390eb284becSJed Brown 
1391eb284becSJed Brown   Not Collective
1392eb284becSJed Brown 
1393d8d19677SJose E. Roman   Input Parameters:
1394eb284becSJed Brown +  ts - timestepping context
1395eb284becSJed Brown -  flg - PETSC_TRUE to use the endpoint variant
1396eb284becSJed Brown 
1397eb284becSJed Brown   Options Database:
139867b8a455SSatish Balay .  -ts_theta_endpoint <flg> - use the endpoint variant
1399eb284becSJed Brown 
1400eb284becSJed Brown   Level: Intermediate
1401eb284becSJed Brown 
1402eb284becSJed Brown .seealso: TSTHETA, TSCN
1403eb284becSJed Brown @*/
1404eb284becSJed Brown PetscErrorCode TSThetaSetEndpoint(TS ts,PetscBool flg)
1405eb284becSJed Brown {
1406eb284becSJed Brown   PetscFunctionBegin;
1407eb284becSJed Brown   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
14085f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTryMethod(ts,"TSThetaSetEndpoint_C",(TS,PetscBool),(ts,flg)));
1409eb284becSJed Brown   PetscFunctionReturn(0);
1410eb284becSJed Brown }
1411eb284becSJed Brown 
1412f33bbcb6SJed Brown /*
1413f33bbcb6SJed Brown  * TSBEULER and TSCN are straightforward specializations of TSTHETA.
1414f33bbcb6SJed Brown  * The creation functions for these specializations are below.
1415f33bbcb6SJed Brown  */
1416f33bbcb6SJed Brown 
14171566a47fSLisandro Dalcin static PetscErrorCode TSSetUp_BEuler(TS ts)
14181566a47fSLisandro Dalcin {
14191566a47fSLisandro Dalcin   TS_Theta       *th = (TS_Theta*)ts->data;
14201566a47fSLisandro Dalcin 
14211566a47fSLisandro Dalcin   PetscFunctionBegin;
14222c71b3e2SJacob Faibussowitsch   PetscCheckFalse(th->Theta != 1.0,PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change the default value (1) of theta when using backward Euler");
1423*28b400f6SJacob Faibussowitsch   PetscCheck(!th->endpoint,PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change to the endpoint form of the Theta methods when using backward Euler");
14245f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetUp_Theta(ts));
14251566a47fSLisandro Dalcin   PetscFunctionReturn(0);
14261566a47fSLisandro Dalcin }
14271566a47fSLisandro Dalcin 
1428f33bbcb6SJed Brown static PetscErrorCode TSView_BEuler(TS ts,PetscViewer viewer)
1429f33bbcb6SJed Brown {
1430f33bbcb6SJed Brown   PetscFunctionBegin;
1431f33bbcb6SJed Brown   PetscFunctionReturn(0);
1432f33bbcb6SJed Brown }
1433f33bbcb6SJed Brown 
1434f33bbcb6SJed Brown /*MC
1435f33bbcb6SJed Brown       TSBEULER - ODE solver using the implicit backward Euler method
1436f33bbcb6SJed Brown 
1437f33bbcb6SJed Brown   Level: beginner
1438f33bbcb6SJed Brown 
14394eb428fdSBarry Smith   Notes:
1440c7eb6c99SShri Abhyankar   TSBEULER is equivalent to TSTHETA with Theta=1.0
14414eb428fdSBarry Smith 
14421566a47fSLisandro Dalcin $  -ts_type theta -ts_theta_theta 1.0
14434eb428fdSBarry Smith 
1444f33bbcb6SJed Brown .seealso:  TSCreate(), TS, TSSetType(), TSEULER, TSCN, TSTHETA
1445f33bbcb6SJed Brown 
1446f33bbcb6SJed Brown M*/
14478cc058d9SJed Brown PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts)
1448f33bbcb6SJed Brown {
1449f33bbcb6SJed Brown   PetscFunctionBegin;
14505f80ce2aSJacob Faibussowitsch   CHKERRQ(TSCreate_Theta(ts));
14515f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaSetTheta(ts,1.0));
14525f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaSetEndpoint(ts,PETSC_FALSE));
14530c7376e5SHong Zhang   ts->ops->setup = TSSetUp_BEuler;
1454f33bbcb6SJed Brown   ts->ops->view  = TSView_BEuler;
1455f33bbcb6SJed Brown   PetscFunctionReturn(0);
1456f33bbcb6SJed Brown }
1457f33bbcb6SJed Brown 
14581566a47fSLisandro Dalcin static PetscErrorCode TSSetUp_CN(TS ts)
14591566a47fSLisandro Dalcin {
14601566a47fSLisandro Dalcin   TS_Theta       *th = (TS_Theta*)ts->data;
14611566a47fSLisandro Dalcin 
14621566a47fSLisandro Dalcin   PetscFunctionBegin;
14632c71b3e2SJacob Faibussowitsch   PetscCheckFalse(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");
14643c633725SBarry Smith   PetscCheck(th->endpoint,PetscObjectComm((PetscObject)ts),PETSC_ERR_OPT_OVERWRITE,"Can not change to the midpoint form of the Theta methods when using Crank-Nicolson");
14655f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetUp_Theta(ts));
14661566a47fSLisandro Dalcin   PetscFunctionReturn(0);
14671566a47fSLisandro Dalcin }
14681566a47fSLisandro Dalcin 
1469f33bbcb6SJed Brown static PetscErrorCode TSView_CN(TS ts,PetscViewer viewer)
1470f33bbcb6SJed Brown {
1471f33bbcb6SJed Brown   PetscFunctionBegin;
1472f33bbcb6SJed Brown   PetscFunctionReturn(0);
1473f33bbcb6SJed Brown }
1474f33bbcb6SJed Brown 
1475f33bbcb6SJed Brown /*MC
1476f33bbcb6SJed Brown       TSCN - ODE solver using the implicit Crank-Nicolson method.
1477f33bbcb6SJed Brown 
1478f33bbcb6SJed Brown   Level: beginner
1479f33bbcb6SJed Brown 
1480f33bbcb6SJed Brown   Notes:
14817cf5af47SJed Brown   TSCN is equivalent to TSTHETA with Theta=0.5 and the "endpoint" option set. I.e.
14827cf5af47SJed Brown 
14837cf5af47SJed Brown $  -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint
1484f33bbcb6SJed Brown 
1485f33bbcb6SJed Brown .seealso:  TSCreate(), TS, TSSetType(), TSBEULER, TSTHETA
1486f33bbcb6SJed Brown 
1487f33bbcb6SJed Brown M*/
14888cc058d9SJed Brown PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts)
1489f33bbcb6SJed Brown {
1490f33bbcb6SJed Brown   PetscFunctionBegin;
14915f80ce2aSJacob Faibussowitsch   CHKERRQ(TSCreate_Theta(ts));
14925f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaSetTheta(ts,0.5));
14935f80ce2aSJacob Faibussowitsch   CHKERRQ(TSThetaSetEndpoint(ts,PETSC_TRUE));
14940c7376e5SHong Zhang   ts->ops->setup = TSSetUp_CN;
1495f33bbcb6SJed Brown   ts->ops->view  = TSView_CN;
1496f33bbcb6SJed Brown   PetscFunctionReturn(0);
1497f33bbcb6SJed Brown }
1498