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