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 45d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot) 46d71ae5a4SJacob Faibussowitsch { 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) { 529566063dSJacob Faibussowitsch PetscCall(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) { 579566063dSJacob Faibussowitsch PetscCall(DMGetNamedGlobalVector(dm, "TSTheta_Xdot", Xdot)); 587445fe48SJed Brown } else *Xdot = th->Xdot; 597445fe48SJed Brown } 603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 617445fe48SJed Brown } 627445fe48SJed Brown 63d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaRestoreX0AndXdot(TS ts, DM dm, Vec *X0, Vec *Xdot) 64d71ae5a4SJacob Faibussowitsch { 650d0b770aSPeter Brune PetscFunctionBegin; 660d0b770aSPeter Brune if (X0) { 6748a46eb9SPierre Jolivet if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_X0", X0)); 680d0b770aSPeter Brune } 690d0b770aSPeter Brune if (Xdot) { 7048a46eb9SPierre Jolivet if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSTheta_Xdot", Xdot)); 710d0b770aSPeter Brune } 723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 730d0b770aSPeter Brune } 740d0b770aSPeter Brune 75d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_TSTheta(DM fine, DM coarse, void *ctx) 76d71ae5a4SJacob Faibussowitsch { 777445fe48SJed Brown PetscFunctionBegin; 783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 797445fe48SJed Brown } 807445fe48SJed Brown 81d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_TSTheta(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx) 82d71ae5a4SJacob Faibussowitsch { 837445fe48SJed Brown TS ts = (TS)ctx; 847445fe48SJed Brown Vec X0, Xdot, X0_c, Xdot_c; 857445fe48SJed Brown 867445fe48SJed Brown PetscFunctionBegin; 879566063dSJacob Faibussowitsch PetscCall(TSThetaGetX0AndXdot(ts, fine, &X0, &Xdot)); 889566063dSJacob Faibussowitsch PetscCall(TSThetaGetX0AndXdot(ts, coarse, &X0_c, &Xdot_c)); 899566063dSJacob Faibussowitsch PetscCall(MatRestrict(restrct, X0, X0_c)); 909566063dSJacob Faibussowitsch PetscCall(MatRestrict(restrct, Xdot, Xdot_c)); 919566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(X0_c, rscale, X0_c)); 929566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(Xdot_c, rscale, Xdot_c)); 939566063dSJacob Faibussowitsch PetscCall(TSThetaRestoreX0AndXdot(ts, fine, &X0, &Xdot)); 949566063dSJacob Faibussowitsch PetscCall(TSThetaRestoreX0AndXdot(ts, coarse, &X0_c, &Xdot_c)); 953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 967445fe48SJed Brown } 977445fe48SJed Brown 98d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_TSTheta(DM dm, DM subdm, void *ctx) 99d71ae5a4SJacob Faibussowitsch { 100258e1594SPeter Brune PetscFunctionBegin; 1013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 102258e1594SPeter Brune } 103258e1594SPeter Brune 104d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx) 105d71ae5a4SJacob Faibussowitsch { 106258e1594SPeter Brune TS ts = (TS)ctx; 107258e1594SPeter Brune Vec X0, Xdot, X0_sub, Xdot_sub; 108258e1594SPeter Brune 109258e1594SPeter Brune PetscFunctionBegin; 1109566063dSJacob Faibussowitsch PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot)); 1119566063dSJacob Faibussowitsch PetscCall(TSThetaGetX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub)); 112258e1594SPeter Brune 1139566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD)); 1149566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(gscat, X0, X0_sub, INSERT_VALUES, SCATTER_FORWARD)); 115258e1594SPeter Brune 1169566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD)); 1179566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(gscat, Xdot, Xdot_sub, INSERT_VALUES, SCATTER_FORWARD)); 118258e1594SPeter Brune 1199566063dSJacob Faibussowitsch PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot)); 1209566063dSJacob Faibussowitsch PetscCall(TSThetaRestoreX0AndXdot(ts, subdm, &X0_sub, &Xdot_sub)); 1213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 122258e1594SPeter Brune } 123258e1594SPeter Brune 124d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaEvaluateCostIntegral(TS ts) 125d71ae5a4SJacob Faibussowitsch { 126022c081aSHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 127cd4cee2dSHong Zhang TS quadts = ts->quadraturets; 128022c081aSHong Zhang 129022c081aSHong Zhang PetscFunctionBegin; 130022c081aSHong Zhang if (th->endpoint) { 131022c081aSHong Zhang /* Evolve ts->vec_costintegral to compute integrals */ 132022c081aSHong Zhang if (th->Theta != 1.0) { 1339566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(quadts, th->ptime0, th->X0, ts->vec_costintegrand)); 1349566063dSJacob Faibussowitsch PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * (1.0 - th->Theta), ts->vec_costintegrand)); 135022c081aSHong Zhang } 1369566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(quadts, ts->ptime, ts->vec_sol, ts->vec_costintegrand)); 1379566063dSJacob Faibussowitsch PetscCall(VecAXPY(quadts->vec_sol, th->time_step0 * th->Theta, ts->vec_costintegrand)); 138022c081aSHong Zhang } else { 1399566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(quadts, th->stage_time, th->X, ts->vec_costintegrand)); 1409566063dSJacob Faibussowitsch PetscCall(VecAXPY(quadts->vec_sol, th->time_step0, ts->vec_costintegrand)); 141022c081aSHong Zhang } 1423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 143022c081aSHong Zhang } 144022c081aSHong Zhang 145d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardCostIntegral_Theta(TS ts) 146d71ae5a4SJacob Faibussowitsch { 147b1cb36f3SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 148cd4cee2dSHong Zhang TS quadts = ts->quadraturets; 149b1cb36f3SHong Zhang 150b1cb36f3SHong Zhang PetscFunctionBegin; 151b1cb36f3SHong Zhang /* backup cost integral */ 1529566063dSJacob Faibussowitsch PetscCall(VecCopy(quadts->vec_sol, th->VecCostIntegral0)); 1539566063dSJacob Faibussowitsch PetscCall(TSThetaEvaluateCostIntegral(ts)); 1543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 155b1cb36f3SHong Zhang } 156b1cb36f3SHong Zhang 157d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointCostIntegral_Theta(TS ts) 158d71ae5a4SJacob Faibussowitsch { 1591a352fa8SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 160b1cb36f3SHong Zhang 161b1cb36f3SHong Zhang PetscFunctionBegin; 1621a352fa8SHong Zhang /* Like TSForwardCostIntegral(), the adjoint cost integral evaluation relies on ptime0 and time_step0. */ 1631a352fa8SHong Zhang th->ptime0 = ts->ptime + ts->time_step; 1641a352fa8SHong Zhang th->time_step0 = -ts->time_step; 1659566063dSJacob Faibussowitsch PetscCall(TSThetaEvaluateCostIntegral(ts)); 1663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16724655328SShri } 16824655328SShri 169d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSTheta_SNESSolve(TS ts, Vec b, Vec x) 170d71ae5a4SJacob Faibussowitsch { 1711566a47fSLisandro Dalcin PetscInt nits, lits; 1721566a47fSLisandro Dalcin 1731566a47fSLisandro Dalcin PetscFunctionBegin; 1749566063dSJacob Faibussowitsch PetscCall(SNESSolve(ts->snes, b, x)); 1759566063dSJacob Faibussowitsch PetscCall(SNESGetIterationNumber(ts->snes, &nits)); 1769566063dSJacob Faibussowitsch PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits)); 1779371c9d4SSatish Balay ts->snes_its += nits; 1789371c9d4SSatish Balay ts->ksp_its += lits; 1793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1801566a47fSLisandro Dalcin } 1811566a47fSLisandro Dalcin 18226b5f05dSStefano Zampini static PetscErrorCode TSResizeRegister_Theta(TS ts, PetscBool reg) 18326b5f05dSStefano Zampini { 18426b5f05dSStefano Zampini TS_Theta *th = (TS_Theta *)ts->data; 18526b5f05dSStefano Zampini 18626b5f05dSStefano Zampini PetscFunctionBegin; 187ecc87898SStefano Zampini if (reg) { 188ecc87898SStefano Zampini PetscCall(TSResizeRegisterVec(ts, "ts:theta:sol_prev", th->vec_sol_prev)); 189ecc87898SStefano Zampini PetscCall(TSResizeRegisterVec(ts, "ts:theta:X0", th->X0)); 190ecc87898SStefano Zampini } else { 191ecc87898SStefano Zampini PetscCall(TSResizeRetrieveVec(ts, "ts:theta:sol_prev", &th->vec_sol_prev)); 192ecc87898SStefano Zampini PetscCall(PetscObjectReference((PetscObject)th->vec_sol_prev)); 193ecc87898SStefano Zampini PetscCall(TSResizeRetrieveVec(ts, "ts:theta:X0", &th->X0)); 19426b5f05dSStefano Zampini PetscCall(PetscObjectReference((PetscObject)th->X0)); 19526b5f05dSStefano Zampini } 19626b5f05dSStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 19726b5f05dSStefano Zampini } 19826b5f05dSStefano Zampini 199d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_Theta(TS ts) 200d71ae5a4SJacob Faibussowitsch { 201316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 2021566a47fSLisandro Dalcin PetscInt rejections = 0; 2034957b756SLisandro Dalcin PetscBool stageok, accept = PETSC_TRUE; 2041566a47fSLisandro Dalcin PetscReal next_time_step = ts->time_step; 205316643e7SJed Brown 206316643e7SJed Brown PetscFunctionBegin; 2071566a47fSLisandro Dalcin if (!ts->steprollback) { 2089566063dSJacob Faibussowitsch if (th->vec_sol_prev) PetscCall(VecCopy(th->X0, th->vec_sol_prev)); 2099566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, th->X0)); 2101566a47fSLisandro Dalcin } 2111566a47fSLisandro Dalcin 2121566a47fSLisandro Dalcin th->status = TS_STEP_INCOMPLETE; 21399260352SHong Zhang while (!ts->reason && th->status != TS_STEP_COMPLETE) { 2143e05ceb1SHong Zhang th->shift = 1 / (th->Theta * ts->time_step); 2151566a47fSLisandro Dalcin th->stage_time = ts->ptime + (th->endpoint ? (PetscReal)1 : th->Theta) * ts->time_step; 2169566063dSJacob Faibussowitsch PetscCall(VecCopy(th->X0, th->X)); 21748a46eb9SPierre Jolivet if (th->extrapolate && !ts->steprestart) PetscCall(VecAXPY(th->X, 1 / th->shift, th->Xdot)); 218eb284becSJed Brown if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */ 2199566063dSJacob Faibussowitsch if (!th->affine) PetscCall(VecDuplicate(ts->vec_sol, &th->affine)); 2209566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(th->Xdot)); 2219566063dSJacob Faibussowitsch PetscCall(TSComputeIFunction(ts, ts->ptime, th->X0, th->Xdot, th->affine, PETSC_FALSE)); 2229566063dSJacob Faibussowitsch PetscCall(VecScale(th->affine, (th->Theta - 1) / th->Theta)); 223eb284becSJed Brown } 2249566063dSJacob Faibussowitsch PetscCall(TSPreStage(ts, th->stage_time)); 22582d7ce88SStefano Zampini PetscCall(TSTheta_SNESSolve(ts, th->endpoint ? th->affine : NULL, th->X)); 2269566063dSJacob Faibussowitsch PetscCall(TSPostStage(ts, th->stage_time, 0, &th->X)); 2279566063dSJacob Faibussowitsch PetscCall(TSAdaptCheckStage(ts->adapt, ts, th->stage_time, th->X, &stageok)); 228fecfb714SLisandro Dalcin if (!stageok) goto reject_step; 229051f2191SLisandro Dalcin 230051f2191SLisandro Dalcin th->status = TS_STEP_PENDING; 2311566a47fSLisandro Dalcin if (th->endpoint) { 2329566063dSJacob Faibussowitsch PetscCall(VecCopy(th->X, ts->vec_sol)); 2331566a47fSLisandro Dalcin } else { 2349566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X)); 2359566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vec_sol, ts->time_step, th->Xdot)); 2361566a47fSLisandro Dalcin } 2379566063dSJacob Faibussowitsch PetscCall(TSAdaptChoose(ts->adapt, ts, ts->time_step, NULL, &next_time_step, &accept)); 2381566a47fSLisandro Dalcin th->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE; 2391566a47fSLisandro Dalcin if (!accept) { 2409566063dSJacob Faibussowitsch PetscCall(VecCopy(th->X0, ts->vec_sol)); 241be5899b3SLisandro Dalcin ts->time_step = next_time_step; 242be5899b3SLisandro Dalcin goto reject_step; 243051f2191SLisandro Dalcin } 2443b1890cdSShri Abhyankar 245715f1b00SHong Zhang if (ts->forward_solve || ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */ 2461a352fa8SHong Zhang th->ptime0 = ts->ptime; 2471a352fa8SHong Zhang th->time_step0 = ts->time_step; 24817145e75SHong Zhang } 2492b5a38e1SLisandro Dalcin ts->ptime += ts->time_step; 250cdbf8f93SLisandro Dalcin ts->time_step = next_time_step; 251051f2191SLisandro Dalcin break; 252051f2191SLisandro Dalcin 253051f2191SLisandro Dalcin reject_step: 2549371c9d4SSatish Balay ts->reject++; 2559371c9d4SSatish Balay accept = PETSC_FALSE; 2561566a47fSLisandro Dalcin if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) { 257051f2191SLisandro Dalcin ts->reason = TS_DIVERGED_STEP_REJECTED; 25863a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections)); 2593b1890cdSShri Abhyankar } 2603b1890cdSShri Abhyankar } 2613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 262316643e7SJed Brown } 263316643e7SJed Brown 264d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointStepBEuler_Private(TS ts) 265d71ae5a4SJacob Faibussowitsch { 266c9681e5dSHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 267cd4cee2dSHong Zhang TS quadts = ts->quadraturets; 268c9681e5dSHong Zhang Vec *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp; 269c9681e5dSHong Zhang Vec *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp; 270c9681e5dSHong Zhang PetscInt nadj; 2717207e0fdSHong Zhang Mat J, Jpre, quadJ = NULL, quadJp = NULL; 272c9681e5dSHong Zhang KSP ksp; 273c9681e5dSHong Zhang PetscScalar *xarr; 274077c4feaSHong Zhang TSEquationType eqtype; 275077c4feaSHong Zhang PetscBool isexplicitode = PETSC_FALSE; 2761a352fa8SHong Zhang PetscReal adjoint_time_step; 277c9681e5dSHong Zhang 278c9681e5dSHong Zhang PetscFunctionBegin; 2799566063dSJacob Faibussowitsch PetscCall(TSGetEquationType(ts, &eqtype)); 280077c4feaSHong Zhang if (eqtype == TS_EQ_ODE_EXPLICIT) { 281077c4feaSHong Zhang isexplicitode = PETSC_TRUE; 282077c4feaSHong Zhang VecsDeltaLam = ts->vecs_sensi; 283077c4feaSHong Zhang VecsDeltaLam2 = ts->vecs_sensi2; 284077c4feaSHong Zhang } 285c9681e5dSHong Zhang th->status = TS_STEP_INCOMPLETE; 2869566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(ts->snes, &ksp)); 2879566063dSJacob Faibussowitsch PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL)); 2887207e0fdSHong Zhang if (quadts) { 2899566063dSJacob Faibussowitsch PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL)); 2909566063dSJacob Faibussowitsch PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL)); 2917207e0fdSHong Zhang } 292c9681e5dSHong Zhang 2931a352fa8SHong Zhang th->stage_time = ts->ptime; 2941a352fa8SHong Zhang adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */ 295c9681e5dSHong Zhang 29633f72c5dSHong Zhang /* Build RHS for first-order adjoint lambda_{n+1}/h + r_u^T(n+1) */ 2971baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL)); 298cd4cee2dSHong Zhang 299c9681e5dSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 3009566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj])); 3019566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensiTemp[nadj], 1. / adjoint_time_step)); /* lambda_{n+1}/h */ 302cd4cee2dSHong Zhang if (quadJ) { 3039566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr)); 3049566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr)); 3059566063dSJacob Faibussowitsch PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col)); 3069566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdu_col)); 3079566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJ, &xarr)); 308c9681e5dSHong Zhang } 309c9681e5dSHong Zhang } 310c9681e5dSHong Zhang 311c9681e5dSHong Zhang /* Build LHS for first-order adjoint */ 312c87ba875SIvan Yashchuk th->shift = 1. / adjoint_time_step; 3139566063dSJacob Faibussowitsch PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre)); 3149566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ksp, J, Jpre)); 315c9681e5dSHong Zhang 316c9681e5dSHong Zhang /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */ 317c9681e5dSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 318c9681e5dSHong Zhang KSPConvergedReason kspreason; 3199566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj])); 3209566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(ksp, &kspreason)); 321c9681e5dSHong Zhang if (kspreason < 0) { 322c9681e5dSHong Zhang ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE; 32363a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n", ts->steps, nadj)); 324c9681e5dSHong Zhang } 325c9681e5dSHong Zhang } 326c9681e5dSHong Zhang 327c9681e5dSHong Zhang if (ts->vecs_sensi2) { /* U_{n+1} */ 328c9681e5dSHong Zhang /* Get w1 at t_{n+1} from TLM matrix */ 3299566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr)); 3309566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 331c9681e5dSHong Zhang /* lambda_s^T F_UU w_1 */ 3329566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu)); 333c9681e5dSHong Zhang /* lambda_s^T F_UP w_2 */ 3349566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup)); 335c9681e5dSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */ 3369566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj])); 3379566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensi2Temp[nadj], 1. / adjoint_time_step)); 3389566063dSJacob Faibussowitsch PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj])); 33948a46eb9SPierre Jolivet if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj])); 340c9681e5dSHong Zhang } 341c9681e5dSHong Zhang /* Solve stage equation LHS X = RHS for second-order adjoint */ 342c9681e5dSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 34305c9950eSHong Zhang KSPConvergedReason kspreason; 3449566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj])); 3459566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(ksp, &kspreason)); 34605c9950eSHong Zhang if (kspreason < 0) { 34705c9950eSHong Zhang ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE; 34863a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n", ts->steps, nadj)); 34905c9950eSHong Zhang } 350c9681e5dSHong Zhang } 351c9681e5dSHong Zhang } 352c9681e5dSHong Zhang 353c9681e5dSHong Zhang /* Update sensitivities, and evaluate integrals if there is any */ 354077c4feaSHong Zhang if (!isexplicitode) { 3553e05ceb1SHong Zhang th->shift = 0.0; 3569566063dSJacob Faibussowitsch PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre)); 3579566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ksp, J, Jpre)); 358c9681e5dSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 35933f72c5dSHong Zhang /* Add f_U \lambda_s to the original RHS */ 3609566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensiTemp[nadj], -1.)); 3619566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj], VecsSensiTemp[nadj])); 3629566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensiTemp[nadj], -adjoint_time_step)); 3639566063dSJacob Faibussowitsch PetscCall(VecCopy(VecsSensiTemp[nadj], ts->vecs_sensi[nadj])); 364c9681e5dSHong Zhang if (ts->vecs_sensi2) { 3659566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(J, VecsDeltaLam2[nadj], VecsSensi2Temp[nadj], VecsSensi2Temp[nadj])); 3669566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensi2Temp[nadj], -adjoint_time_step)); 3679566063dSJacob Faibussowitsch PetscCall(VecCopy(VecsSensi2Temp[nadj], ts->vecs_sensi2[nadj])); 368c9681e5dSHong Zhang } 369c9681e5dSHong Zhang } 370077c4feaSHong Zhang } 371c9681e5dSHong Zhang if (ts->vecs_sensip) { 3729566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->Xdot, -1. / adjoint_time_step, 1.0 / adjoint_time_step, 0, th->X0, ts->vec_sol)); 3739566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, 1. / adjoint_time_step, ts->Jacp, PETSC_FALSE)); /* get -f_p */ 3741baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp)); 375c9681e5dSHong Zhang if (ts->vecs_sensi2p) { 376c9681e5dSHong Zhang /* lambda_s^T F_PU w_1 */ 3779566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu)); 37833f72c5dSHong Zhang /* lambda_s^T F_PP w_2 */ 3799566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp)); 380c9681e5dSHong Zhang } 381cd4cee2dSHong Zhang 382c9681e5dSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 3839566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj])); 3849566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj])); 385cd4cee2dSHong Zhang if (quadJp) { 3869566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr)); 3879566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr)); 3889566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col)); 3899566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdp_col)); 3909566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJp, &xarr)); 39133f72c5dSHong Zhang } 392c9681e5dSHong Zhang if (ts->vecs_sensi2p) { 3939566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj])); 3949566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, VecsDeltaMu2[nadj])); 39548a46eb9SPierre Jolivet if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpu[nadj])); 39648a46eb9SPierre Jolivet if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step, ts->vecs_fpp[nadj])); 397c9681e5dSHong Zhang } 398c9681e5dSHong Zhang } 399c9681e5dSHong Zhang } 400c9681e5dSHong Zhang 401c9681e5dSHong Zhang if (ts->vecs_sensi2) { 4029566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_sensip_col)); 4039566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr)); 404c9681e5dSHong Zhang } 405c9681e5dSHong Zhang th->status = TS_STEP_COMPLETE; 4063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 407c9681e5dSHong Zhang } 408c9681e5dSHong Zhang 409d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointStep_Theta(TS ts) 410d71ae5a4SJacob Faibussowitsch { 4112ca6e920SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 412cd4cee2dSHong Zhang TS quadts = ts->quadraturets; 413b5e0532dSHong Zhang Vec *VecsDeltaLam = th->VecsDeltaLam, *VecsDeltaMu = th->VecsDeltaMu, *VecsSensiTemp = th->VecsSensiTemp; 414b5b4017aSHong Zhang Vec *VecsDeltaLam2 = th->VecsDeltaLam2, *VecsDeltaMu2 = th->VecsDeltaMu2, *VecsSensi2Temp = th->VecsSensi2Temp; 4152ca6e920SHong Zhang PetscInt nadj; 4167207e0fdSHong Zhang Mat J, Jpre, quadJ = NULL, quadJp = NULL; 4172ca6e920SHong Zhang KSP ksp; 418b5b4017aSHong Zhang PetscScalar *xarr; 4191a352fa8SHong Zhang PetscReal adjoint_time_step; 420da81f932SPierre Jolivet PetscReal adjoint_ptime; /* end time of the adjoint time step (ts->ptime is the start time, usually ts->ptime is larger than adjoint_ptime) */ 4212ca6e920SHong Zhang 4222ca6e920SHong Zhang PetscFunctionBegin; 423c9681e5dSHong Zhang if (th->Theta == 1.) { 4249566063dSJacob Faibussowitsch PetscCall(TSAdjointStepBEuler_Private(ts)); 4253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 426c9681e5dSHong Zhang } 4272ca6e920SHong Zhang th->status = TS_STEP_INCOMPLETE; 4289566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(ts->snes, &ksp)); 4299566063dSJacob Faibussowitsch PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL)); 4307207e0fdSHong Zhang if (quadts) { 4319566063dSJacob Faibussowitsch PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL)); 4329566063dSJacob Faibussowitsch PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL)); 4337207e0fdSHong Zhang } 434b5e0532dSHong Zhang /* If endpoint=1, th->ptime and th->X0 will be used; if endpoint=0, th->stage_time and th->X will be used. */ 4351a352fa8SHong Zhang th->stage_time = th->endpoint ? ts->ptime : (ts->ptime + (1. - th->Theta) * ts->time_step); 4361a352fa8SHong Zhang adjoint_ptime = ts->ptime + ts->time_step; 4371a352fa8SHong Zhang adjoint_time_step = -ts->time_step; /* always positive since time_step is negative */ 4382ca6e920SHong Zhang 43982ad9101SHong Zhang if (!th->endpoint) { 4405072d23cSHong Zhang /* recover th->X0 using vec_sol and the stage value th->X */ 4419566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->X0, 1.0 / (1.0 - th->Theta), th->Theta / (th->Theta - 1.0), 0, th->X, ts->vec_sol)); 44282ad9101SHong Zhang } 44382ad9101SHong Zhang 444b5b4017aSHong Zhang /* Build RHS for first-order adjoint */ 44533f72c5dSHong Zhang /* Cost function has an integral term */ 4467207e0fdSHong Zhang if (quadts) { 44705755b9cSHong Zhang if (th->endpoint) { 4489566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL)); 44905755b9cSHong Zhang } else { 4509566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL)); 45105755b9cSHong Zhang } 4527207e0fdSHong Zhang } 45333f72c5dSHong Zhang 454abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 4559566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vecs_sensi[nadj], VecsSensiTemp[nadj])); 4569566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensiTemp[nadj], 1. / (th->Theta * adjoint_time_step))); 457cd4cee2dSHong Zhang if (quadJ) { 4589566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr)); 4599566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr)); 4609566063dSJacob Faibussowitsch PetscCall(VecAXPY(VecsSensiTemp[nadj], 1., ts->vec_drdu_col)); 4619566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdu_col)); 4629566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJ, &xarr)); 46336eaed60SHong Zhang } 4642ca6e920SHong Zhang } 4653c54f92cSHong Zhang 466b5b4017aSHong Zhang /* Build LHS for first-order adjoint */ 4671a352fa8SHong Zhang th->shift = 1. / (th->Theta * adjoint_time_step); 4683c54f92cSHong Zhang if (th->endpoint) { 4699566063dSJacob Faibussowitsch PetscCall(TSComputeSNESJacobian(ts, ts->vec_sol, J, Jpre)); 4703c54f92cSHong Zhang } else { 4719566063dSJacob Faibussowitsch PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre)); 4723c54f92cSHong Zhang } 4739566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ksp, J, Jpre)); 4742ca6e920SHong Zhang 475b5b4017aSHong Zhang /* Solve stage equation LHS*lambda_s = RHS for first-order adjoint */ 476abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 4771d14d03bSHong Zhang KSPConvergedReason kspreason; 4789566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ksp, VecsSensiTemp[nadj], VecsDeltaLam[nadj])); 4799566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(ksp, &kspreason)); 4801d14d03bSHong Zhang if (kspreason < 0) { 4811d14d03bSHong Zhang ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE; 48263a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 1st-order adjoint solve\n", ts->steps, nadj)); 4831d14d03bSHong Zhang } 4842ca6e920SHong Zhang } 4853c54f92cSHong Zhang 4861d14d03bSHong Zhang /* Second-order adjoint */ 487b5b4017aSHong Zhang if (ts->vecs_sensi2) { /* U_{n+1} */ 4883c633725SBarry Smith PetscCheck(th->endpoint, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Operation not implemented in TS_Theta"); 489b5b4017aSHong Zhang /* Get w1 at t_{n+1} from TLM matrix */ 4909566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr)); 4919566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 492b5b4017aSHong Zhang /* lambda_s^T F_UU w_1 */ 4939566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionUU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu)); 4949566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_sensip_col)); 4959566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr)); 496b5b4017aSHong Zhang /* lambda_s^T F_UP w_2 */ 4979566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionUP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fup)); 498b5b4017aSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { /* compute the residual */ 4999566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vecs_sensi2[nadj], VecsSensi2Temp[nadj])); 5009566063dSJacob Faibussowitsch PetscCall(VecScale(VecsSensi2Temp[nadj], th->shift)); 5019566063dSJacob Faibussowitsch PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fuu[nadj])); 50248a46eb9SPierre Jolivet if (ts->vecs_fup) PetscCall(VecAXPY(VecsSensi2Temp[nadj], -1., ts->vecs_fup[nadj])); 503b5b4017aSHong Zhang } 504b5b4017aSHong Zhang /* Solve stage equation LHS X = RHS for second-order adjoint */ 505b5b4017aSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 5061d14d03bSHong Zhang KSPConvergedReason kspreason; 5079566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ksp, VecsSensi2Temp[nadj], VecsDeltaLam2[nadj])); 5089566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(ksp, &kspreason)); 5091d14d03bSHong Zhang if (kspreason < 0) { 5101d14d03bSHong Zhang ts->reason = TSADJOINT_DIVERGED_LINEAR_SOLVE; 51163a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th cost function, transposed linear solve fails, stopping 2nd-order adjoint solve\n", ts->steps, nadj)); 5121d14d03bSHong Zhang } 513b5b4017aSHong Zhang } 514b5b4017aSHong Zhang } 515b5b4017aSHong Zhang 51636eaed60SHong Zhang /* Update sensitivities, and evaluate integrals if there is any */ 5171d14d03bSHong Zhang if (th->endpoint) { /* two-stage Theta methods with th->Theta!=1, th->Theta==1 leads to BEuler */ 5181a352fa8SHong Zhang th->shift = 1. / ((th->Theta - 1.) * adjoint_time_step); 5191a352fa8SHong Zhang th->stage_time = adjoint_ptime; 5209566063dSJacob Faibussowitsch PetscCall(TSComputeSNESJacobian(ts, th->X0, J, Jpre)); 5219566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ksp, J, Jpre)); 52233f72c5dSHong Zhang /* R_U at t_n */ 5231baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobian(quadts, adjoint_ptime, th->X0, quadJ, NULL)); 524abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 5259566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], ts->vecs_sensi[nadj])); 526cd4cee2dSHong Zhang if (quadJ) { 5279566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr)); 5289566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr)); 5299566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi[nadj], -1., ts->vec_drdu_col)); 5309566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdu_col)); 5319566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJ, &xarr)); 532b5b4017aSHong Zhang } 5339566063dSJacob Faibussowitsch PetscCall(VecScale(ts->vecs_sensi[nadj], 1. / th->shift)); 534b5b4017aSHong Zhang } 5351d14d03bSHong Zhang 5361d14d03bSHong Zhang /* Second-order adjoint */ 5371d14d03bSHong Zhang if (ts->vecs_sensi2) { /* U_n */ 538b5b4017aSHong Zhang /* Get w1 at t_n from TLM matrix */ 5399566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr)); 5409566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 541b5b4017aSHong Zhang /* lambda_s^T F_UU w_1 */ 5429566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionUU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fuu)); 5439566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_sensip_col)); 5449566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr)); 545b5b4017aSHong Zhang /* lambda_s^T F_UU w_2 */ 5469566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionUP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fup)); 547b5b4017aSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 54833f72c5dSHong 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 */ 5499566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(J, VecsDeltaLam2[nadj], ts->vecs_sensi2[nadj])); 5509566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fuu[nadj])); 55148a46eb9SPierre Jolivet if (ts->vecs_fup) PetscCall(VecAXPY(ts->vecs_sensi2[nadj], 1., ts->vecs_fup[nadj])); 5529566063dSJacob Faibussowitsch PetscCall(VecScale(ts->vecs_sensi2[nadj], 1. / th->shift)); 553b5b4017aSHong Zhang } 554b5e0532dSHong Zhang } 5553fd52205SHong Zhang 556c586f2e8SHong Zhang th->stage_time = ts->ptime; /* recover the old value */ 557c586f2e8SHong Zhang 5583fd52205SHong Zhang if (ts->vecs_sensip) { /* sensitivities wrt parameters */ 559b5b4017aSHong Zhang /* U_{n+1} */ 56082ad9101SHong Zhang th->shift = 1.0 / (adjoint_time_step * th->Theta); 5619566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol)); 5629566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, -1. / (th->Theta * adjoint_time_step), ts->Jacp, PETSC_FALSE)); 5631baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp)); 564abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 5659566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj])); 5669566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu[nadj])); 5673b711c3fSHong Zhang if (quadJp) { 5689566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr)); 5699566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr)); 5709566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * th->Theta, ts->vec_drdp_col)); 5719566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdp_col)); 5729566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJp, &xarr)); 5733b711c3fSHong Zhang } 5743fd52205SHong Zhang } 57533f72c5dSHong Zhang if (ts->vecs_sensi2p) { /* second-order */ 57633f72c5dSHong Zhang /* Get w1 at t_{n+1} from TLM matrix */ 5779566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(ts->mat_sensip, 0, &xarr)); 5789566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 579b5b4017aSHong Zhang /* lambda_s^T F_PU w_1 */ 5809566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionPU(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu)); 5819566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_sensip_col)); 5829566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr)); 58333f72c5dSHong Zhang 584b5b4017aSHong Zhang /* lambda_s^T F_PP w_2 */ 5859566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionPP(ts, th->stage_time, ts->vec_sol, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp)); 586b5b4017aSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 58733f72c5dSHong 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) */ 5889566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj])); 5899566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, VecsDeltaMu2[nadj])); 59048a46eb9SPierre Jolivet if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpu[nadj])); 59148a46eb9SPierre Jolivet if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * th->Theta, ts->vecs_fpp[nadj])); 592b5b4017aSHong Zhang } 593b5b4017aSHong Zhang } 594b5b4017aSHong Zhang 595b5b4017aSHong Zhang /* U_s */ 5969566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(th->Xdot)); 5979566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, adjoint_ptime, th->X0, th->Xdot, 1. / ((th->Theta - 1.0) * adjoint_time_step), ts->Jacp, PETSC_FALSE)); 5981baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, adjoint_ptime, th->X0, quadJp)); 599abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 6009566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj])); 6019566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu[nadj])); 6023b711c3fSHong Zhang if (quadJp) { 6039566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr)); 6049566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr)); 6059566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step * (1.0 - th->Theta), ts->vec_drdp_col)); 6069566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdp_col)); 6079566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJp, &xarr)); 6083b711c3fSHong Zhang } 60933f72c5dSHong Zhang if (ts->vecs_sensi2p) { /* second-order */ 61033f72c5dSHong Zhang /* Get w1 at t_n from TLM matrix */ 6119566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(th->MatFwdSensip0, 0, &xarr)); 6129566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 613b5b4017aSHong Zhang /* lambda_s^T F_PU w_1 */ 6149566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionPU(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_sensip_col, ts->vecs_fpu)); 6159566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_sensip_col)); 6169566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(th->MatFwdSensip0, &xarr)); 617b5b4017aSHong Zhang /* lambda_s^T F_PP w_2 */ 6189566063dSJacob Faibussowitsch PetscCall(TSComputeIHessianProductFunctionPP(ts, adjoint_ptime, th->X0, VecsDeltaLam, ts->vec_dir, ts->vecs_fpp)); 619b5b4017aSHong Zhang for (nadj = 0; nadj < ts->numcost; nadj++) { 62033f72c5dSHong 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) */ 6219566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam2[nadj], VecsDeltaMu2[nadj])); 6229566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), VecsDeltaMu2[nadj])); 62348a46eb9SPierre Jolivet if (ts->vecs_fpu) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpu[nadj])); 62448a46eb9SPierre Jolivet if (ts->vecs_fpp) PetscCall(VecAXPY(ts->vecs_sensi2p[nadj], -adjoint_time_step * (1.0 - th->Theta), ts->vecs_fpp[nadj])); 62536eaed60SHong Zhang } 62636eaed60SHong Zhang } 6273fd52205SHong Zhang } 628b5e0532dSHong Zhang } 6293fd52205SHong Zhang } else { /* one-stage case */ 6303e05ceb1SHong Zhang th->shift = 0.0; 6319566063dSJacob Faibussowitsch PetscCall(TSComputeSNESJacobian(ts, th->X, J, Jpre)); /* get -f_y */ 6329566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ksp, J, Jpre)); 6331baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL)); 634abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 6359566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(J, VecsDeltaLam[nadj], VecsSensiTemp[nadj])); 6369566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi[nadj], -adjoint_time_step, VecsSensiTemp[nadj])); 637cd4cee2dSHong Zhang if (quadJ) { 6389566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJ, nadj, &xarr)); 6399566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdu_col, xarr)); 6409566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensi[nadj], adjoint_time_step, ts->vec_drdu_col)); 6419566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdu_col)); 6429566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJ, &xarr)); 64336eaed60SHong Zhang } 6442ca6e920SHong Zhang } 6453fd52205SHong Zhang if (ts->vecs_sensip) { 64682ad9101SHong Zhang th->shift = 1.0 / (adjoint_time_step * th->Theta); 6479566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X)); 6489566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 6491baa6e33SBarry Smith if (quadts) PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp)); 650abc2977eSBarry Smith for (nadj = 0; nadj < ts->numcost; nadj++) { 6519566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(ts->Jacp, VecsDeltaLam[nadj], VecsDeltaMu[nadj])); 6529566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], -adjoint_time_step, VecsDeltaMu[nadj])); 653cd4cee2dSHong Zhang if (quadJp) { 6549566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(quadJp, nadj, &xarr)); 6559566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_drdp_col, xarr)); 6569566063dSJacob Faibussowitsch PetscCall(VecAXPY(ts->vecs_sensip[nadj], adjoint_time_step, ts->vec_drdp_col)); 6579566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_drdp_col)); 6589566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(quadJp, &xarr)); 65936eaed60SHong Zhang } 66036eaed60SHong Zhang } 6613fd52205SHong Zhang } 6622ca6e920SHong Zhang } 6632ca6e920SHong Zhang 6642ca6e920SHong Zhang th->status = TS_STEP_COMPLETE; 6653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6662ca6e920SHong Zhang } 6672ca6e920SHong Zhang 668d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_Theta(TS ts, PetscReal t, Vec X) 669d71ae5a4SJacob Faibussowitsch { 670cd652676SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 671be5899b3SLisandro Dalcin PetscReal dt = t - ts->ptime; 672cd652676SJed Brown 673cd652676SJed Brown PetscFunctionBegin; 6749566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, th->X)); 675be5899b3SLisandro Dalcin if (th->endpoint) dt *= th->Theta; 6769566063dSJacob Faibussowitsch PetscCall(VecWAXPY(X, dt, th->Xdot, th->X)); 6773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 678cd652676SJed Brown } 679cd652676SJed Brown 680d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEvaluateWLTE_Theta(TS ts, NormType wnormtype, PetscInt *order, PetscReal *wlte) 681d71ae5a4SJacob Faibussowitsch { 6821566a47fSLisandro Dalcin TS_Theta *th = (TS_Theta *)ts->data; 6831566a47fSLisandro Dalcin Vec X = ts->vec_sol; /* X = solution */ 6841566a47fSLisandro Dalcin Vec Y = th->vec_lte_work; /* Y = X + LTE */ 6857453f775SEmil Constantinescu PetscReal wltea, wlter; 6861566a47fSLisandro Dalcin 6871566a47fSLisandro Dalcin PetscFunctionBegin; 6889371c9d4SSatish Balay if (!th->vec_sol_prev) { 6899371c9d4SSatish Balay *wlte = -1; 6903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6919371c9d4SSatish Balay } 6921566a47fSLisandro Dalcin /* Cannot compute LTE in first step or in restart after event */ 6939371c9d4SSatish Balay if (ts->steprestart) { 6949371c9d4SSatish Balay *wlte = -1; 6953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6969371c9d4SSatish Balay } 6971566a47fSLisandro Dalcin /* Compute LTE using backward differences with non-constant time step */ 698fecfb714SLisandro Dalcin { 699be5899b3SLisandro Dalcin PetscReal h = ts->time_step, h_prev = ts->ptime - ts->ptime_prev; 700be5899b3SLisandro Dalcin PetscReal a = 1 + h_prev / h; 7019371c9d4SSatish Balay PetscScalar scal[3]; 7029371c9d4SSatish Balay Vec vecs[3]; 7039371c9d4SSatish Balay scal[0] = +1 / a; 7049371c9d4SSatish Balay scal[1] = -1 / (a - 1); 7059371c9d4SSatish Balay scal[2] = +1 / (a * (a - 1)); 7069371c9d4SSatish Balay vecs[0] = X; 7079371c9d4SSatish Balay vecs[1] = th->X0; 7089371c9d4SSatish Balay vecs[2] = th->vec_sol_prev; 7099566063dSJacob Faibussowitsch PetscCall(VecCopy(X, Y)); 7109566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Y, 3, scal, vecs)); 7119566063dSJacob Faibussowitsch PetscCall(TSErrorWeightedNorm(ts, X, Y, wnormtype, wlte, &wltea, &wlter)); 7121566a47fSLisandro Dalcin } 7131566a47fSLisandro Dalcin if (order) *order = 2; 7143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7151566a47fSLisandro Dalcin } 7161566a47fSLisandro Dalcin 717d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSRollBack_Theta(TS ts) 718d71ae5a4SJacob Faibussowitsch { 7191566a47fSLisandro Dalcin TS_Theta *th = (TS_Theta *)ts->data; 7207207e0fdSHong Zhang TS quadts = ts->quadraturets; 7211566a47fSLisandro Dalcin 7221566a47fSLisandro Dalcin PetscFunctionBegin; 72348a46eb9SPierre Jolivet if (quadts && ts->costintegralfwd) PetscCall(VecCopy(th->VecCostIntegral0, quadts->vec_sol)); 724715f1b00SHong Zhang th->status = TS_STEP_INCOMPLETE; 7251baa6e33SBarry Smith if (ts->mat_sensip) PetscCall(MatCopy(th->MatFwdSensip0, ts->mat_sensip, SAME_NONZERO_PATTERN)); 72648a46eb9SPierre Jolivet if (quadts && quadts->mat_sensip) PetscCall(MatCopy(th->MatIntegralSensip0, quadts->mat_sensip, SAME_NONZERO_PATTERN)); 7273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 728715f1b00SHong Zhang } 729715f1b00SHong Zhang 730d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardStep_Theta(TS ts) 731d71ae5a4SJacob Faibussowitsch { 732715f1b00SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 733cd4cee2dSHong Zhang TS quadts = ts->quadraturets; 73413b1b0ffSHong Zhang Mat MatDeltaFwdSensip = th->MatDeltaFwdSensip; 735b5b4017aSHong Zhang Vec VecDeltaFwdSensipCol = th->VecDeltaFwdSensipCol; 7367207e0fdSHong Zhang PetscInt ntlm; 737715f1b00SHong Zhang KSP ksp; 7387207e0fdSHong Zhang Mat J, Jpre, quadJ = NULL, quadJp = NULL; 73913b1b0ffSHong Zhang PetscScalar *barr, *xarr; 7401a352fa8SHong Zhang PetscReal previous_shift; 741715f1b00SHong Zhang 742715f1b00SHong Zhang PetscFunctionBegin; 7431a352fa8SHong Zhang previous_shift = th->shift; 7449566063dSJacob Faibussowitsch PetscCall(MatCopy(ts->mat_sensip, th->MatFwdSensip0, SAME_NONZERO_PATTERN)); 74513b1b0ffSHong Zhang 74648a46eb9SPierre Jolivet if (quadts && quadts->mat_sensip) PetscCall(MatCopy(quadts->mat_sensip, th->MatIntegralSensip0, SAME_NONZERO_PATTERN)); 7479566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(ts->snes, &ksp)); 7489566063dSJacob Faibussowitsch PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL)); 7497207e0fdSHong Zhang if (quadts) { 7509566063dSJacob Faibussowitsch PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL)); 7519566063dSJacob Faibussowitsch PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL)); 7527207e0fdSHong Zhang } 753715f1b00SHong Zhang 754715f1b00SHong Zhang /* Build RHS */ 755715f1b00SHong Zhang if (th->endpoint) { /* 2-stage method*/ 7561a352fa8SHong Zhang th->shift = 1. / ((th->Theta - 1.) * th->time_step0); 7579566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobian(ts, th->ptime0, th->X0, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 7589566063dSJacob Faibussowitsch PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DEFAULT, &MatDeltaFwdSensip)); 7599566063dSJacob Faibussowitsch PetscCall(MatScale(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta)); 760715f1b00SHong Zhang 761022c081aSHong Zhang /* Add the f_p forcing terms */ 7620e11c21fSHong Zhang if (ts->Jacp) { 7639566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(th->Xdot)); 7649566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, th->ptime0, th->X0, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 7659566063dSJacob Faibussowitsch PetscCall(MatAXPY(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta, ts->Jacp, SUBSET_NONZERO_PATTERN)); 76682ad9101SHong Zhang th->shift = previous_shift; 7679566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol)); 7689566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 7699566063dSJacob Faibussowitsch PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN)); 7700e11c21fSHong Zhang } 771715f1b00SHong Zhang } else { /* 1-stage method */ 7723e05ceb1SHong Zhang th->shift = 0.0; 7739566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 7749566063dSJacob Faibussowitsch PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DEFAULT, &MatDeltaFwdSensip)); 7759566063dSJacob Faibussowitsch PetscCall(MatScale(MatDeltaFwdSensip, -1.)); 77613b1b0ffSHong Zhang 777022c081aSHong Zhang /* Add the f_p forcing terms */ 7780e11c21fSHong Zhang if (ts->Jacp) { 77982ad9101SHong Zhang th->shift = previous_shift; 7809566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X)); 7819566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 7829566063dSJacob Faibussowitsch PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN)); 783715f1b00SHong Zhang } 7840e11c21fSHong Zhang } 785715f1b00SHong Zhang 786715f1b00SHong Zhang /* Build LHS */ 7871a352fa8SHong Zhang th->shift = previous_shift; /* recover the previous shift used in TSStep_Theta() */ 788715f1b00SHong Zhang if (th->endpoint) { 7899566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobian(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 790715f1b00SHong Zhang } else { 7919566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 792715f1b00SHong Zhang } 7939566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ksp, J, Jpre)); 794715f1b00SHong Zhang 795715f1b00SHong Zhang /* 796715f1b00SHong Zhang Evaluate the first stage of integral gradients with the 2-stage method: 797c9ad9de0SHong Zhang drdu|t_n*S(t_n) + drdp|t_n 798715f1b00SHong Zhang This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1}) 799715f1b00SHong Zhang */ 800715f1b00SHong Zhang if (th->endpoint) { /* 2-stage method only */ 8017207e0fdSHong Zhang if (quadts && quadts->mat_sensip) { 8029566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobian(quadts, th->ptime0, th->X0, quadJ, NULL)); 8039566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobianP(quadts, th->ptime0, th->X0, quadJp)); 8049566063dSJacob Faibussowitsch PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp)); 8059566063dSJacob Faibussowitsch PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN)); 8069566063dSJacob Faibussowitsch PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * (1. - th->Theta), th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN)); 807715f1b00SHong Zhang } 808715f1b00SHong Zhang } 809715f1b00SHong Zhang 810715f1b00SHong Zhang /* Solve the tangent linear equation for forward sensitivities to parameters */ 811022c081aSHong Zhang for (ntlm = 0; ntlm < th->num_tlm; ntlm++) { 812b5b4017aSHong Zhang KSPConvergedReason kspreason; 8139566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(MatDeltaFwdSensip, ntlm, &barr)); 8149566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(VecDeltaFwdSensipCol, barr)); 815715f1b00SHong Zhang if (th->endpoint) { 8169566063dSJacob Faibussowitsch PetscCall(MatDenseGetColumn(ts->mat_sensip, ntlm, &xarr)); 8179566063dSJacob Faibussowitsch PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 8189566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, ts->vec_sensip_col)); 8199566063dSJacob Faibussowitsch PetscCall(VecResetArray(ts->vec_sensip_col)); 8209566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr)); 821715f1b00SHong Zhang } else { 8229566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, VecDeltaFwdSensipCol)); 823715f1b00SHong Zhang } 8249566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(ksp, &kspreason)); 825b5b4017aSHong Zhang if (kspreason < 0) { 826b5b4017aSHong Zhang ts->reason = TSFORWARD_DIVERGED_LINEAR_SOLVE; 82763a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th tangent linear solve, linear solve fails, stopping tangent linear solve\n", ts->steps, ntlm)); 828b5b4017aSHong Zhang } 8299566063dSJacob Faibussowitsch PetscCall(VecResetArray(VecDeltaFwdSensipCol)); 8309566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreColumn(MatDeltaFwdSensip, &barr)); 831715f1b00SHong Zhang } 832715f1b00SHong Zhang 83313b1b0ffSHong Zhang /* 83413b1b0ffSHong Zhang Evaluate the second stage of integral gradients with the 2-stage method: 835c9ad9de0SHong Zhang drdu|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1} 83613b1b0ffSHong Zhang */ 8377207e0fdSHong Zhang if (quadts && quadts->mat_sensip) { 83813b1b0ffSHong Zhang if (!th->endpoint) { 8399566063dSJacob Faibussowitsch PetscCall(MatAXPY(ts->mat_sensip, 1, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); /* stage sensitivity */ 8409566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL)); 8419566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp)); 8429566063dSJacob Faibussowitsch PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp)); 8439566063dSJacob Faibussowitsch PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN)); 8449566063dSJacob Faibussowitsch PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN)); 8459566063dSJacob Faibussowitsch PetscCall(MatAXPY(ts->mat_sensip, (1. - th->Theta) / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); 84613b1b0ffSHong Zhang } else { 8479566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL)); 8489566063dSJacob Faibussowitsch PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp)); 8499566063dSJacob Faibussowitsch PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DEFAULT, &th->MatIntegralSensipTemp)); 8509566063dSJacob Faibussowitsch PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN)); 8519566063dSJacob Faibussowitsch PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * th->Theta, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN)); 85213b1b0ffSHong Zhang } 85313b1b0ffSHong Zhang } else { 85448a46eb9SPierre Jolivet if (!th->endpoint) PetscCall(MatAXPY(ts->mat_sensip, 1. / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); 855715f1b00SHong Zhang } 8563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8571566a47fSLisandro Dalcin } 8581566a47fSLisandro Dalcin 859d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardGetStages_Theta(TS ts, PetscInt *ns, Mat *stagesensip[]) 860d71ae5a4SJacob Faibussowitsch { 8616affb6f8SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 8626affb6f8SHong Zhang 8636affb6f8SHong Zhang PetscFunctionBegin; 8647409eceaSHong Zhang if (ns) { 8657409eceaSHong Zhang if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */ 8667409eceaSHong Zhang else *ns = 2; /* endpoint form */ 8677409eceaSHong Zhang } 8685072d23cSHong Zhang if (stagesensip) { 869cc4f23bcSHong Zhang if (!th->endpoint && th->Theta != 1.0) { 8707409eceaSHong Zhang th->MatFwdStages[0] = th->MatDeltaFwdSensip; 871cc4f23bcSHong Zhang } else { 872cc4f23bcSHong Zhang th->MatFwdStages[0] = th->MatFwdSensip0; 873cc4f23bcSHong Zhang th->MatFwdStages[1] = ts->mat_sensip; /* stiffly accurate */ 874cc4f23bcSHong Zhang } 875cc4f23bcSHong Zhang *stagesensip = th->MatFwdStages; 8765072d23cSHong Zhang } 8773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8786affb6f8SHong Zhang } 8796affb6f8SHong Zhang 880316643e7SJed Brown /*------------------------------------------------------------*/ 881d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_Theta(TS ts) 882d71ae5a4SJacob Faibussowitsch { 883316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 884316643e7SJed Brown 885316643e7SJed Brown PetscFunctionBegin; 8869566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->X)); 8879566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->Xdot)); 8889566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->X0)); 8899566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->affine)); 8901566a47fSLisandro Dalcin 8919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->vec_sol_prev)); 8929566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->vec_lte_work)); 8931566a47fSLisandro Dalcin 8949566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->VecCostIntegral0)); 8953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 896277b19d0SLisandro Dalcin } 897277b19d0SLisandro Dalcin 898d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointReset_Theta(TS ts) 899d71ae5a4SJacob Faibussowitsch { 900ece46509SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 901ece46509SHong Zhang 902ece46509SHong Zhang PetscFunctionBegin; 9039566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam)); 9049566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu)); 9059566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam2)); 9069566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu2)); 9079566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensiTemp)); 9089566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensi2Temp)); 9093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 910ece46509SHong Zhang } 911ece46509SHong Zhang 912d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_Theta(TS ts) 913d71ae5a4SJacob Faibussowitsch { 914277b19d0SLisandro Dalcin PetscFunctionBegin; 9159566063dSJacob Faibussowitsch PetscCall(TSReset_Theta(ts)); 916b3a6b972SJed Brown if (ts->dm) { 9179566063dSJacob Faibussowitsch PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts)); 9189566063dSJacob Faibussowitsch PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts)); 919b3a6b972SJed Brown } 9209566063dSJacob Faibussowitsch PetscCall(PetscFree(ts->data)); 9219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", NULL)); 9229566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", NULL)); 9239566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", NULL)); 9249566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", NULL)); 9253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 926316643e7SJed Brown } 927316643e7SJed Brown 928316643e7SJed Brown /* 929316643e7SJed Brown This defines the nonlinear equation that is to be solved with SNES 9302b5a38e1SLisandro Dalcin G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0 9310fd10508SMatthew Knepley 9320fd10508SMatthew Knepley Note that U here is the stage argument. This means that U = U_{n+1} only if endpoint = true, 9330fd10508SMatthew Knepley otherwise U = theta U_{n+1} + (1 - theta) U0, which for the case of implicit midpoint is 9340fd10508SMatthew Knepley U = (U_{n+1} + U0)/2 935316643e7SJed Brown */ 936d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_Theta(SNES snes, Vec x, Vec y, TS ts) 937d71ae5a4SJacob Faibussowitsch { 938316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 9397445fe48SJed Brown Vec X0, Xdot; 9407445fe48SJed Brown DM dm, dmsave; 9413e05ceb1SHong Zhang PetscReal shift = th->shift; 942316643e7SJed Brown 943316643e7SJed Brown PetscFunctionBegin; 9449566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 9455a3a76d0SJed Brown /* When using the endpoint variant, this is actually 1/Theta * Xdot */ 9469566063dSJacob Faibussowitsch PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot)); 947494ce9fcSHong Zhang if (x != X0) { 9489566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x)); 949494ce9fcSHong Zhang } else { 9509566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(Xdot)); 951494ce9fcSHong Zhang } 9527445fe48SJed Brown /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */ 9537445fe48SJed Brown dmsave = ts->dm; 9547445fe48SJed Brown ts->dm = dm; 9559566063dSJacob Faibussowitsch PetscCall(TSComputeIFunction(ts, th->stage_time, x, Xdot, y, PETSC_FALSE)); 9567445fe48SJed Brown ts->dm = dmsave; 9579566063dSJacob Faibussowitsch PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot)); 9583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 959316643e7SJed Brown } 960316643e7SJed Brown 961d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes, Vec x, Mat A, Mat B, TS ts) 962d71ae5a4SJacob Faibussowitsch { 963316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 9647445fe48SJed Brown Vec Xdot; 9657445fe48SJed Brown DM dm, dmsave; 9663e05ceb1SHong Zhang PetscReal shift = th->shift; 967316643e7SJed Brown 968316643e7SJed Brown PetscFunctionBegin; 9699566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 970be5899b3SLisandro Dalcin /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */ 9719566063dSJacob Faibussowitsch PetscCall(TSThetaGetX0AndXdot(ts, dm, NULL, &Xdot)); 9727445fe48SJed Brown 9737445fe48SJed Brown dmsave = ts->dm; 9747445fe48SJed Brown ts->dm = dm; 9759566063dSJacob Faibussowitsch PetscCall(TSComputeIJacobian(ts, th->stage_time, x, Xdot, shift, A, B, PETSC_FALSE)); 9767445fe48SJed Brown ts->dm = dmsave; 9779566063dSJacob Faibussowitsch PetscCall(TSThetaRestoreX0AndXdot(ts, dm, NULL, &Xdot)); 9783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 979316643e7SJed Brown } 980316643e7SJed Brown 981d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardSetUp_Theta(TS ts) 982d71ae5a4SJacob Faibussowitsch { 983715f1b00SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 9847207e0fdSHong Zhang TS quadts = ts->quadraturets; 985715f1b00SHong Zhang 986715f1b00SHong Zhang PetscFunctionBegin; 987022c081aSHong Zhang /* combine sensitivities to parameters and sensitivities to initial values into one array */ 98813b1b0ffSHong Zhang th->num_tlm = ts->num_parameters; 9899566063dSJacob Faibussowitsch PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatDeltaFwdSensip)); 9907207e0fdSHong Zhang if (quadts && quadts->mat_sensip) { 9919566063dSJacob Faibussowitsch PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensipTemp)); 9929566063dSJacob Faibussowitsch PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensip0)); 993715f1b00SHong Zhang } 9946f92202bSHong Zhang /* backup sensitivity results for roll-backs */ 9959566063dSJacob Faibussowitsch PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatFwdSensip0)); 99613b1b0ffSHong Zhang 9979566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ts->vec_sol, &th->VecDeltaFwdSensipCol)); 9983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 999715f1b00SHong Zhang } 1000715f1b00SHong Zhang 1001d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSForwardReset_Theta(TS ts) 1002d71ae5a4SJacob Faibussowitsch { 10037adebddeSHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 10047207e0fdSHong Zhang TS quadts = ts->quadraturets; 10057adebddeSHong Zhang 10067adebddeSHong Zhang PetscFunctionBegin; 10077207e0fdSHong Zhang if (quadts && quadts->mat_sensip) { 10089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&th->MatIntegralSensipTemp)); 10099566063dSJacob Faibussowitsch PetscCall(MatDestroy(&th->MatIntegralSensip0)); 10107adebddeSHong Zhang } 10119566063dSJacob Faibussowitsch PetscCall(VecDestroy(&th->VecDeltaFwdSensipCol)); 10129566063dSJacob Faibussowitsch PetscCall(MatDestroy(&th->MatDeltaFwdSensip)); 10139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&th->MatFwdSensip0)); 10143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10157adebddeSHong Zhang } 10167adebddeSHong Zhang 1017d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_Theta(TS ts) 1018d71ae5a4SJacob Faibussowitsch { 1019316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 1020cd4cee2dSHong Zhang TS quadts = ts->quadraturets; 10212ffb9264SLisandro Dalcin PetscBool match; 1022316643e7SJed Brown 1023316643e7SJed Brown PetscFunctionBegin; 1024cd4cee2dSHong Zhang if (!th->VecCostIntegral0 && quadts && ts->costintegralfwd) { /* back up cost integral */ 10259566063dSJacob Faibussowitsch PetscCall(VecDuplicate(quadts->vec_sol, &th->VecCostIntegral0)); 1026b1cb36f3SHong Zhang } 102748a46eb9SPierre Jolivet if (!th->X) PetscCall(VecDuplicate(ts->vec_sol, &th->X)); 102848a46eb9SPierre Jolivet if (!th->Xdot) PetscCall(VecDuplicate(ts->vec_sol, &th->Xdot)); 102948a46eb9SPierre Jolivet if (!th->X0) PetscCall(VecDuplicate(ts->vec_sol, &th->X0)); 103048a46eb9SPierre Jolivet if (th->endpoint) PetscCall(VecDuplicate(ts->vec_sol, &th->affine)); 10313b1890cdSShri Abhyankar 10321566a47fSLisandro Dalcin th->order = (th->Theta == 0.5) ? 2 : 1; 103320d49056SMatthew G. Knepley th->shift = 1 / (th->Theta * ts->time_step); 10341566a47fSLisandro Dalcin 10359566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &ts->dm)); 10369566063dSJacob Faibussowitsch PetscCall(DMCoarsenHookAdd(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts)); 10379566063dSJacob Faibussowitsch PetscCall(DMSubDomainHookAdd(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts)); 10381566a47fSLisandro Dalcin 10399566063dSJacob Faibussowitsch PetscCall(TSGetAdapt(ts, &ts->adapt)); 10409566063dSJacob Faibussowitsch PetscCall(TSAdaptCandidatesClear(ts->adapt)); 10419566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &match)); 10422ffb9264SLisandro Dalcin if (!match) { 1043ecc87898SStefano Zampini if (!th->vec_sol_prev) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_sol_prev)); 1044ecc87898SStefano Zampini if (!th->vec_lte_work) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_lte_work)); 10453b1890cdSShri Abhyankar } 10469566063dSJacob Faibussowitsch PetscCall(TSGetSNES(ts, &ts->snes)); 1047cc4f23bcSHong Zhang 1048cc4f23bcSHong Zhang ts->stifflyaccurate = (!th->endpoint && th->Theta != 1.0) ? PETSC_FALSE : PETSC_TRUE; 10493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1050b4dd3bf9SBarry Smith } 10510c7376e5SHong Zhang 1052b4dd3bf9SBarry Smith /*------------------------------------------------------------*/ 1053b4dd3bf9SBarry Smith 1054d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSAdjointSetUp_Theta(TS ts) 1055d71ae5a4SJacob Faibussowitsch { 1056b4dd3bf9SBarry Smith TS_Theta *th = (TS_Theta *)ts->data; 1057b4dd3bf9SBarry Smith 1058b4dd3bf9SBarry Smith PetscFunctionBegin; 10599566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam)); 10609566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsSensiTemp)); 106148a46eb9SPierre Jolivet if (ts->vecs_sensip) PetscCall(VecDuplicateVecs(ts->vecs_sensip[0], ts->numcost, &th->VecsDeltaMu)); 1062b5b4017aSHong Zhang if (ts->vecs_sensi2) { 10639566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam2)); 10649566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vecs_sensi2[0], ts->numcost, &th->VecsSensi2Temp)); 106567633408SHong Zhang /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */ 106667633408SHong Zhang if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu; 106767633408SHong Zhang if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup; 1068b5b4017aSHong Zhang } 1069c9681e5dSHong Zhang if (ts->vecs_sensi2p) { 10709566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vecs_sensi2p[0], ts->numcost, &th->VecsDeltaMu2)); 107167633408SHong Zhang /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */ 107267633408SHong Zhang if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu; 107367633408SHong Zhang if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp; 1074b5b4017aSHong Zhang } 10753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1076316643e7SJed Brown } 1077316643e7SJed Brown 1078d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetFromOptions_Theta(TS ts, PetscOptionItems *PetscOptionsObject) 1079d71ae5a4SJacob Faibussowitsch { 1080316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 1081316643e7SJed Brown 1082316643e7SJed Brown PetscFunctionBegin; 1083d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Theta ODE solver options"); 1084316643e7SJed Brown { 10859566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-ts_theta_theta", "Location of stage (0<Theta<=1)", "TSThetaSetTheta", th->Theta, &th->Theta, NULL)); 10869566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-ts_theta_endpoint", "Use the endpoint instead of midpoint form of the Theta method", "TSThetaSetEndpoint", th->endpoint, &th->endpoint, NULL)); 10879566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-ts_theta_initial_guess_extrapolate", "Extrapolate stage initial guess from previous solution (sometimes unstable)", "TSThetaSetExtrapolate", th->extrapolate, &th->extrapolate, NULL)); 1088316643e7SJed Brown } 1089d0609cedSBarry Smith PetscOptionsHeadEnd(); 10903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1091316643e7SJed Brown } 1092316643e7SJed Brown 1093d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_Theta(TS ts, PetscViewer viewer) 1094d71ae5a4SJacob Faibussowitsch { 1095316643e7SJed Brown TS_Theta *th = (TS_Theta *)ts->data; 1096ace3abfcSBarry Smith PetscBool iascii; 1097316643e7SJed Brown 1098316643e7SJed Brown PetscFunctionBegin; 10999566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1100316643e7SJed Brown if (iascii) { 11019566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Theta=%g\n", (double)th->Theta)); 11029566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Extrapolation=%s\n", th->extrapolate ? "yes" : "no")); 1103316643e7SJed Brown } 11043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1105316643e7SJed Brown } 1106316643e7SJed Brown 1107d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetTheta_Theta(TS ts, PetscReal *theta) 1108d71ae5a4SJacob Faibussowitsch { 11090de4c49aSJed Brown TS_Theta *th = (TS_Theta *)ts->data; 11100de4c49aSJed Brown 11110de4c49aSJed Brown PetscFunctionBegin; 11120de4c49aSJed Brown *theta = th->Theta; 11133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11140de4c49aSJed Brown } 11150de4c49aSJed Brown 1116d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaSetTheta_Theta(TS ts, PetscReal theta) 1117d71ae5a4SJacob Faibussowitsch { 11180de4c49aSJed Brown TS_Theta *th = (TS_Theta *)ts->data; 11190de4c49aSJed Brown 11200de4c49aSJed Brown PetscFunctionBegin; 1121cad9d221SBarry Smith PetscCheck(theta > 0 && theta <= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Theta %g not in range (0,1]", (double)theta); 11220de4c49aSJed Brown th->Theta = theta; 11231566a47fSLisandro Dalcin th->order = (th->Theta == 0.5) ? 2 : 1; 11243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11250de4c49aSJed Brown } 1126eb284becSJed Brown 1127d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts, PetscBool *endpoint) 1128d71ae5a4SJacob Faibussowitsch { 112926f2ff8fSLisandro Dalcin TS_Theta *th = (TS_Theta *)ts->data; 113026f2ff8fSLisandro Dalcin 113126f2ff8fSLisandro Dalcin PetscFunctionBegin; 113226f2ff8fSLisandro Dalcin *endpoint = th->endpoint; 11333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 113426f2ff8fSLisandro Dalcin } 113526f2ff8fSLisandro Dalcin 1136d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts, PetscBool flg) 1137d71ae5a4SJacob Faibussowitsch { 1138eb284becSJed Brown TS_Theta *th = (TS_Theta *)ts->data; 1139eb284becSJed Brown 1140eb284becSJed Brown PetscFunctionBegin; 1141eb284becSJed Brown th->endpoint = flg; 11423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1143eb284becSJed Brown } 11440de4c49aSJed Brown 1145f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX) 1146d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSComputeLinearStability_Theta(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi) 1147d71ae5a4SJacob Faibussowitsch { 1148f9c1d6abSBarry Smith PetscComplex z = xr + xi * PETSC_i, f; 1149f9c1d6abSBarry Smith TS_Theta *th = (TS_Theta *)ts->data; 1150f9c1d6abSBarry Smith 1151f9c1d6abSBarry Smith PetscFunctionBegin; 1152*520136c7SJose E. Roman f = (1.0 + (1.0 - th->Theta) * z) / (1.0 - th->Theta * z); 1153f9c1d6abSBarry Smith *yr = PetscRealPartComplex(f); 1154f9c1d6abSBarry Smith *yi = PetscImaginaryPartComplex(f); 11553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1156f9c1d6abSBarry Smith } 1157f9c1d6abSBarry Smith #endif 1158f9c1d6abSBarry Smith 1159d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSGetStages_Theta(TS ts, PetscInt *ns, Vec *Y[]) 1160d71ae5a4SJacob Faibussowitsch { 116142682096SHong Zhang TS_Theta *th = (TS_Theta *)ts->data; 116242682096SHong Zhang 116342682096SHong Zhang PetscFunctionBegin; 11647409eceaSHong Zhang if (ns) { 11657409eceaSHong Zhang if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */ 11667409eceaSHong Zhang else *ns = 2; /* endpoint form */ 11677409eceaSHong Zhang } 11685072d23cSHong Zhang if (Y) { 1169cc4f23bcSHong Zhang if (!th->endpoint && th->Theta != 1.0) { 11707409eceaSHong Zhang th->Stages[0] = th->X; 1171cc4f23bcSHong Zhang } else { 1172cc4f23bcSHong Zhang th->Stages[0] = th->X0; 1173cc4f23bcSHong Zhang th->Stages[1] = ts->vec_sol; /* stiffly accurate */ 1174cc4f23bcSHong Zhang } 1175cc4f23bcSHong Zhang *Y = th->Stages; 11765072d23cSHong Zhang } 11773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 117842682096SHong Zhang } 1179f9c1d6abSBarry Smith 1180316643e7SJed Brown /* ------------------------------------------------------------ */ 1181316643e7SJed Brown /*MC 118296f5712cSJed Brown TSTHETA - DAE solver using the implicit Theta method 1183316643e7SJed Brown 1184316643e7SJed Brown Level: beginner 1185316643e7SJed Brown 1186bcf0153eSBarry Smith Options Database Keys: 1187c82ed962SBarry Smith + -ts_theta_theta <Theta> - Location of stage (0<Theta<=1) 1188c82ed962SBarry Smith . -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method 118903842d09SLisandro Dalcin - -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable) 11904eb428fdSBarry Smith 1191eb284becSJed Brown Notes: 119237fdd005SBarry Smith .vb 119337fdd005SBarry Smith -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER) 119437fdd005SBarry Smith -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule 119537fdd005SBarry Smith -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN) 119637fdd005SBarry Smith .ve 11974eb428fdSBarry Smith 11987409eceaSHong 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. 1199eb284becSJed Brown 12007409eceaSHong Zhang The midpoint variant is cast as a 1-stage implicit Runge-Kutta method. 1201eb284becSJed Brown 1202eb284becSJed Brown .vb 1203eb284becSJed Brown Theta | Theta 1204eb284becSJed Brown ------------- 1205eb284becSJed Brown | 1 1206eb284becSJed Brown .ve 1207eb284becSJed Brown 1208eb284becSJed Brown For the default Theta=0.5, this is also known as the implicit midpoint rule. 1209eb284becSJed Brown 1210eb284becSJed Brown When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit: 1211eb284becSJed Brown 1212eb284becSJed Brown .vb 1213eb284becSJed Brown 0 | 0 0 1214eb284becSJed Brown 1 | 1-Theta Theta 1215eb284becSJed Brown ------------------- 1216eb284becSJed Brown | 1-Theta Theta 1217eb284becSJed Brown .ve 1218eb284becSJed Brown 1219eb284becSJed Brown For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN). 1220eb284becSJed Brown 1221eb284becSJed Brown To apply a diagonally implicit RK method to DAE, the stage formula 1222eb284becSJed Brown 1223eb284becSJed Brown $ Y_i = X + h sum_j a_ij Y'_j 1224eb284becSJed Brown 12254eb428fdSBarry Smith is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i) 1226eb284becSJed Brown 12271cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSCN`, `TSBEULER`, `TSThetaSetTheta()`, `TSThetaSetEndpoint()` 1228316643e7SJed Brown M*/ 1229d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts) 1230d71ae5a4SJacob Faibussowitsch { 1231316643e7SJed Brown TS_Theta *th; 1232316643e7SJed Brown 1233316643e7SJed Brown PetscFunctionBegin; 1234277b19d0SLisandro Dalcin ts->ops->reset = TSReset_Theta; 1235ece46509SHong Zhang ts->ops->adjointreset = TSAdjointReset_Theta; 1236316643e7SJed Brown ts->ops->destroy = TSDestroy_Theta; 1237316643e7SJed Brown ts->ops->view = TSView_Theta; 1238316643e7SJed Brown ts->ops->setup = TSSetUp_Theta; 123942f2b339SBarry Smith ts->ops->adjointsetup = TSAdjointSetUp_Theta; 1240ece46509SHong Zhang ts->ops->adjointreset = TSAdjointReset_Theta; 1241316643e7SJed Brown ts->ops->step = TSStep_Theta; 1242cd652676SJed Brown ts->ops->interpolate = TSInterpolate_Theta; 12431566a47fSLisandro Dalcin ts->ops->evaluatewlte = TSEvaluateWLTE_Theta; 124424655328SShri ts->ops->rollback = TSRollBack_Theta; 124526b5f05dSStefano Zampini ts->ops->resizeregister = TSResizeRegister_Theta; 1246316643e7SJed Brown ts->ops->setfromoptions = TSSetFromOptions_Theta; 12470f5c6efeSJed Brown ts->ops->snesfunction = SNESTSFormFunction_Theta; 12480f5c6efeSJed Brown ts->ops->snesjacobian = SNESTSFormJacobian_Theta; 1249f9c1d6abSBarry Smith #if defined(PETSC_HAVE_COMPLEX) 1250f9c1d6abSBarry Smith ts->ops->linearstability = TSComputeLinearStability_Theta; 1251f9c1d6abSBarry Smith #endif 125242682096SHong Zhang ts->ops->getstages = TSGetStages_Theta; 125342f2b339SBarry Smith ts->ops->adjointstep = TSAdjointStep_Theta; 1254b1cb36f3SHong Zhang ts->ops->adjointintegral = TSAdjointCostIntegral_Theta; 1255b1cb36f3SHong Zhang ts->ops->forwardintegral = TSForwardCostIntegral_Theta; 12562ffb9264SLisandro Dalcin ts->default_adapt_type = TSADAPTNONE; 12576affb6f8SHong Zhang 1258715f1b00SHong Zhang ts->ops->forwardsetup = TSForwardSetUp_Theta; 12597adebddeSHong Zhang ts->ops->forwardreset = TSForwardReset_Theta; 1260715f1b00SHong Zhang ts->ops->forwardstep = TSForwardStep_Theta; 12616affb6f8SHong Zhang ts->ops->forwardgetstages = TSForwardGetStages_Theta; 1262316643e7SJed Brown 1263efd4aadfSBarry Smith ts->usessnes = PETSC_TRUE; 1264efd4aadfSBarry Smith 12654dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&th)); 1266316643e7SJed Brown ts->data = (void *)th; 1267316643e7SJed Brown 1268715f1b00SHong Zhang th->VecsDeltaLam = NULL; 1269715f1b00SHong Zhang th->VecsDeltaMu = NULL; 1270715f1b00SHong Zhang th->VecsSensiTemp = NULL; 1271b5b4017aSHong Zhang th->VecsSensi2Temp = NULL; 1272715f1b00SHong Zhang 12736f700aefSJed Brown th->extrapolate = PETSC_FALSE; 1274316643e7SJed Brown th->Theta = 0.5; 12751566a47fSLisandro Dalcin th->order = 2; 12769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", TSThetaGetTheta_Theta)); 12779566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", TSThetaSetTheta_Theta)); 12789566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", TSThetaGetEndpoint_Theta)); 12799566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", TSThetaSetEndpoint_Theta)); 12803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1281316643e7SJed Brown } 12820de4c49aSJed Brown 12830de4c49aSJed Brown /*@ 1284bcf0153eSBarry Smith TSThetaGetTheta - Get the abscissa of the stage in (0,1] for `TSTHETA` 12850de4c49aSJed Brown 12860de4c49aSJed Brown Not Collective 12870de4c49aSJed Brown 12880de4c49aSJed Brown Input Parameter: 12890de4c49aSJed Brown . ts - timestepping context 12900de4c49aSJed Brown 12910de4c49aSJed Brown Output Parameter: 12920de4c49aSJed Brown . theta - stage abscissa 12930de4c49aSJed Brown 1294bcf0153eSBarry Smith Level: advanced 1295bcf0153eSBarry Smith 12960de4c49aSJed Brown Note: 1297bcf0153eSBarry Smith Use of this function is normally only required to hack `TSTHETA` to use a modified integration scheme. 12980de4c49aSJed Brown 12991cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaSetTheta()`, `TSTHETA` 13000de4c49aSJed Brown @*/ 1301d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaGetTheta(TS ts, PetscReal *theta) 1302d71ae5a4SJacob Faibussowitsch { 13030de4c49aSJed Brown PetscFunctionBegin; 1304afb20b64SJed Brown PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 13054f572ea9SToby Isaac PetscAssertPointer(theta, 2); 1306cac4c232SBarry Smith PetscUseMethod(ts, "TSThetaGetTheta_C", (TS, PetscReal *), (ts, theta)); 13073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13080de4c49aSJed Brown } 13090de4c49aSJed Brown 13100de4c49aSJed Brown /*@ 1311bcf0153eSBarry Smith TSThetaSetTheta - Set the abscissa of the stage in (0,1] for `TSTHETA` 13120de4c49aSJed Brown 13130de4c49aSJed Brown Not Collective 13140de4c49aSJed Brown 1315d8d19677SJose E. Roman Input Parameters: 13160de4c49aSJed Brown + ts - timestepping context 13170de4c49aSJed Brown - theta - stage abscissa 13180de4c49aSJed Brown 1319bcf0153eSBarry Smith Options Database Key: 132067b8a455SSatish Balay . -ts_theta_theta <theta> - set theta 13210de4c49aSJed Brown 1322bcf0153eSBarry Smith Level: intermediate 13230de4c49aSJed Brown 13241cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaGetTheta()`, `TSTHETA`, `TSCN` 13250de4c49aSJed Brown @*/ 1326d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaSetTheta(TS ts, PetscReal theta) 1327d71ae5a4SJacob Faibussowitsch { 13280de4c49aSJed Brown PetscFunctionBegin; 1329afb20b64SJed Brown PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1330cac4c232SBarry Smith PetscTryMethod(ts, "TSThetaSetTheta_C", (TS, PetscReal), (ts, theta)); 13313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13320de4c49aSJed Brown } 1333f33bbcb6SJed Brown 133426f2ff8fSLisandro Dalcin /*@ 1335bcf0153eSBarry Smith TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA` 133626f2ff8fSLisandro Dalcin 133726f2ff8fSLisandro Dalcin Not Collective 133826f2ff8fSLisandro Dalcin 133926f2ff8fSLisandro Dalcin Input Parameter: 134026f2ff8fSLisandro Dalcin . ts - timestepping context 134126f2ff8fSLisandro Dalcin 134226f2ff8fSLisandro Dalcin Output Parameter: 1343bcf0153eSBarry Smith . endpoint - `PETSC_TRUE` when using the endpoint variant 134426f2ff8fSLisandro Dalcin 1345bcf0153eSBarry Smith Level: advanced 134626f2ff8fSLisandro Dalcin 13471cc06b55SBarry Smith .seealso: [](ch_ts), `TSThetaSetEndpoint()`, `TSTHETA`, `TSCN` 134826f2ff8fSLisandro Dalcin @*/ 1349d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaGetEndpoint(TS ts, PetscBool *endpoint) 1350d71ae5a4SJacob Faibussowitsch { 135126f2ff8fSLisandro Dalcin PetscFunctionBegin; 135226f2ff8fSLisandro Dalcin PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 13534f572ea9SToby Isaac PetscAssertPointer(endpoint, 2); 1354cac4c232SBarry Smith PetscUseMethod(ts, "TSThetaGetEndpoint_C", (TS, PetscBool *), (ts, endpoint)); 13553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 135626f2ff8fSLisandro Dalcin } 135726f2ff8fSLisandro Dalcin 1358eb284becSJed Brown /*@ 1359bcf0153eSBarry Smith TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA` 1360eb284becSJed Brown 1361eb284becSJed Brown Not Collective 1362eb284becSJed Brown 1363d8d19677SJose E. Roman Input Parameters: 1364eb284becSJed Brown + ts - timestepping context 1365bcf0153eSBarry Smith - flg - `PETSC_TRUE` to use the endpoint variant 1366eb284becSJed Brown 1367bcf0153eSBarry Smith Options Database Key: 136867b8a455SSatish Balay . -ts_theta_endpoint <flg> - use the endpoint variant 1369eb284becSJed Brown 1370bcf0153eSBarry Smith Level: intermediate 1371eb284becSJed Brown 13721cc06b55SBarry Smith .seealso: [](ch_ts), `TSTHETA`, `TSCN` 1373eb284becSJed Brown @*/ 1374d71ae5a4SJacob Faibussowitsch PetscErrorCode TSThetaSetEndpoint(TS ts, PetscBool flg) 1375d71ae5a4SJacob Faibussowitsch { 1376eb284becSJed Brown PetscFunctionBegin; 1377eb284becSJed Brown PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1378cac4c232SBarry Smith PetscTryMethod(ts, "TSThetaSetEndpoint_C", (TS, PetscBool), (ts, flg)); 13793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1380eb284becSJed Brown } 1381eb284becSJed Brown 1382f33bbcb6SJed Brown /* 1383f33bbcb6SJed Brown * TSBEULER and TSCN are straightforward specializations of TSTHETA. 1384f33bbcb6SJed Brown * The creation functions for these specializations are below. 1385f33bbcb6SJed Brown */ 1386f33bbcb6SJed Brown 1387d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_BEuler(TS ts) 1388d71ae5a4SJacob Faibussowitsch { 13891566a47fSLisandro Dalcin TS_Theta *th = (TS_Theta *)ts->data; 13901566a47fSLisandro Dalcin 13911566a47fSLisandro Dalcin PetscFunctionBegin; 139208401ef6SPierre Jolivet PetscCheck(th->Theta == 1.0, PetscObjectComm((PetscObject)ts), PETSC_ERR_OPT_OVERWRITE, "Can not change the default value (1) of theta when using backward Euler"); 139328b400f6SJacob 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"); 13949566063dSJacob Faibussowitsch PetscCall(TSSetUp_Theta(ts)); 13953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13961566a47fSLisandro Dalcin } 13971566a47fSLisandro Dalcin 1398d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_BEuler(TS ts, PetscViewer viewer) 1399d71ae5a4SJacob Faibussowitsch { 1400f33bbcb6SJed Brown PetscFunctionBegin; 14013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1402f33bbcb6SJed Brown } 1403f33bbcb6SJed Brown 1404f33bbcb6SJed Brown /*MC 1405f33bbcb6SJed Brown TSBEULER - ODE solver using the implicit backward Euler method 1406f33bbcb6SJed Brown 1407f33bbcb6SJed Brown Level: beginner 1408f33bbcb6SJed Brown 1409bcf0153eSBarry Smith Note: 141037fdd005SBarry Smith `TSBEULER` is equivalent to `TSTHETA` with Theta=1.0 or `-ts_type theta -ts_theta_theta 1.0` 14114eb428fdSBarry Smith 14121cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSEULER`, `TSCN`, `TSTHETA` 1413f33bbcb6SJed Brown M*/ 1414d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts) 1415d71ae5a4SJacob Faibussowitsch { 1416f33bbcb6SJed Brown PetscFunctionBegin; 14179566063dSJacob Faibussowitsch PetscCall(TSCreate_Theta(ts)); 14189566063dSJacob Faibussowitsch PetscCall(TSThetaSetTheta(ts, 1.0)); 14199566063dSJacob Faibussowitsch PetscCall(TSThetaSetEndpoint(ts, PETSC_FALSE)); 14200c7376e5SHong Zhang ts->ops->setup = TSSetUp_BEuler; 1421f33bbcb6SJed Brown ts->ops->view = TSView_BEuler; 14223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1423f33bbcb6SJed Brown } 1424f33bbcb6SJed Brown 1425d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_CN(TS ts) 1426d71ae5a4SJacob Faibussowitsch { 14271566a47fSLisandro Dalcin TS_Theta *th = (TS_Theta *)ts->data; 14281566a47fSLisandro Dalcin 14291566a47fSLisandro Dalcin PetscFunctionBegin; 143008401ef6SPierre Jolivet PetscCheck(th->Theta == 0.5, PetscObjectComm((PetscObject)ts), PETSC_ERR_OPT_OVERWRITE, "Can not change the default value (0.5) of theta when using Crank-Nicolson"); 14313c633725SBarry 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"); 14329566063dSJacob Faibussowitsch PetscCall(TSSetUp_Theta(ts)); 14333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14341566a47fSLisandro Dalcin } 14351566a47fSLisandro Dalcin 1436d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_CN(TS ts, PetscViewer viewer) 1437d71ae5a4SJacob Faibussowitsch { 1438f33bbcb6SJed Brown PetscFunctionBegin; 14393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1440f33bbcb6SJed Brown } 1441f33bbcb6SJed Brown 1442f33bbcb6SJed Brown /*MC 1443f33bbcb6SJed Brown TSCN - ODE solver using the implicit Crank-Nicolson method. 1444f33bbcb6SJed Brown 1445f33bbcb6SJed Brown Level: beginner 1446f33bbcb6SJed Brown 1447f33bbcb6SJed Brown Notes: 1448bcf0153eSBarry Smith `TSCN` is equivalent to `TSTHETA` with Theta=0.5 and the "endpoint" option set. I.e. 1449bcf0153eSBarry Smith .vb 1450bcf0153eSBarry Smith -ts_type theta 1451bcf0153eSBarry Smith -ts_theta_theta 0.5 1452bcf0153eSBarry Smith -ts_theta_endpoint 1453bcf0153eSBarry Smith .ve 14547cf5af47SJed Brown 14551cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSBEULER`, `TSTHETA`, `TSType`, 1456f33bbcb6SJed Brown M*/ 1457d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts) 1458d71ae5a4SJacob Faibussowitsch { 1459f33bbcb6SJed Brown PetscFunctionBegin; 14609566063dSJacob Faibussowitsch PetscCall(TSCreate_Theta(ts)); 14619566063dSJacob Faibussowitsch PetscCall(TSThetaSetTheta(ts, 0.5)); 14629566063dSJacob Faibussowitsch PetscCall(TSThetaSetEndpoint(ts, PETSC_TRUE)); 14630c7376e5SHong Zhang ts->ops->setup = TSSetUp_CN; 1464f33bbcb6SJed Brown ts->ops->view = TSView_CN; 14653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1466f33bbcb6SJed Brown } 1467