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, PetscCtx 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, PetscCtx 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, PetscCtx ctx) 97 { 98 PetscFunctionBegin; 99 PetscFunctionReturn(PETSC_SUCCESS); 100 } 101 102 static PetscErrorCode DMSubDomainRestrictHook_TSTheta(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, PetscCtx 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 static PetscErrorCode TSReset_Theta(TS ts) 889 { 890 TS_Theta *th = (TS_Theta *)ts->data; 891 892 PetscFunctionBegin; 893 PetscCall(VecDestroy(&th->X)); 894 PetscCall(VecDestroy(&th->Xdot)); 895 PetscCall(VecDestroy(&th->X0)); 896 PetscCall(VecDestroy(&th->affine)); 897 898 PetscCall(VecDestroy(&th->vec_sol_prev)); 899 PetscCall(VecDestroy(&th->vec_lte_work)); 900 901 PetscCall(VecDestroy(&th->VecCostIntegral0)); 902 PetscFunctionReturn(PETSC_SUCCESS); 903 } 904 905 static PetscErrorCode TSAdjointReset_Theta(TS ts) 906 { 907 TS_Theta *th = (TS_Theta *)ts->data; 908 909 PetscFunctionBegin; 910 PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam)); 911 PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu)); 912 PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaLam2)); 913 PetscCall(VecDestroyVecs(ts->numcost, &th->VecsDeltaMu2)); 914 PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensiTemp)); 915 PetscCall(VecDestroyVecs(ts->numcost, &th->VecsSensi2Temp)); 916 PetscFunctionReturn(PETSC_SUCCESS); 917 } 918 919 static PetscErrorCode TSDestroy_Theta(TS ts) 920 { 921 PetscFunctionBegin; 922 PetscCall(TSReset_Theta(ts)); 923 if (ts->dm) { 924 PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts)); 925 PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts)); 926 } 927 PetscCall(PetscFree(ts->data)); 928 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", NULL)); 929 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", NULL)); 930 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", NULL)); 931 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", NULL)); 932 PetscFunctionReturn(PETSC_SUCCESS); 933 } 934 935 /* 936 This defines the nonlinear equation that is to be solved with SNES 937 G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0 938 939 Note that U here is the stage argument. This means that U = U_{n+1} only if endpoint = true, 940 otherwise U = theta U_{n+1} + (1 - theta) U0, which for the case of implicit midpoint is 941 U = (U_{n+1} + U0)/2 942 */ 943 static PetscErrorCode SNESTSFormFunction_Theta(SNES snes, Vec x, Vec y, TS ts) 944 { 945 TS_Theta *th = (TS_Theta *)ts->data; 946 Vec X0, Xdot; 947 DM dm, dmsave; 948 PetscReal shift = th->shift; 949 950 PetscFunctionBegin; 951 PetscCall(SNESGetDM(snes, &dm)); 952 /* When using the endpoint variant, this is actually 1/Theta * Xdot */ 953 PetscCall(TSThetaGetX0AndXdot(ts, dm, &X0, &Xdot)); 954 if (x != X0) { 955 PetscCall(VecAXPBYPCZ(Xdot, -shift, shift, 0, X0, x)); 956 } else { 957 PetscCall(VecZeroEntries(Xdot)); 958 } 959 /* DM monkey-business allows user code to call TSGetDM() inside of functions evaluated on levels of FAS */ 960 dmsave = ts->dm; 961 ts->dm = dm; 962 PetscCall(TSComputeIFunction(ts, th->stage_time, x, Xdot, y, PETSC_FALSE)); 963 ts->dm = dmsave; 964 PetscCall(TSThetaRestoreX0AndXdot(ts, dm, &X0, &Xdot)); 965 PetscFunctionReturn(PETSC_SUCCESS); 966 } 967 968 static PetscErrorCode SNESTSFormJacobian_Theta(SNES snes, Vec x, Mat A, Mat B, TS ts) 969 { 970 TS_Theta *th = (TS_Theta *)ts->data; 971 Vec Xdot; 972 DM dm, dmsave; 973 PetscReal shift = th->shift; 974 975 PetscFunctionBegin; 976 PetscCall(SNESGetDM(snes, &dm)); 977 /* Xdot has already been computed in SNESTSFormFunction_Theta (SNES guarantees this) */ 978 PetscCall(TSThetaGetX0AndXdot(ts, dm, NULL, &Xdot)); 979 980 dmsave = ts->dm; 981 ts->dm = dm; 982 PetscCall(TSComputeIJacobian(ts, th->stage_time, x, Xdot, shift, A, B, PETSC_FALSE)); 983 ts->dm = dmsave; 984 PetscCall(TSThetaRestoreX0AndXdot(ts, dm, NULL, &Xdot)); 985 PetscFunctionReturn(PETSC_SUCCESS); 986 } 987 988 static PetscErrorCode TSForwardSetUp_Theta(TS ts) 989 { 990 TS_Theta *th = (TS_Theta *)ts->data; 991 TS quadts = ts->quadraturets; 992 993 PetscFunctionBegin; 994 /* combine sensitivities to parameters and sensitivities to initial values into one array */ 995 th->num_tlm = ts->num_parameters; 996 PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatDeltaFwdSensip)); 997 if (quadts && quadts->mat_sensip) { 998 PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensipTemp)); 999 PetscCall(MatDuplicate(quadts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatIntegralSensip0)); 1000 } 1001 /* backup sensitivity results for roll-backs */ 1002 PetscCall(MatDuplicate(ts->mat_sensip, MAT_DO_NOT_COPY_VALUES, &th->MatFwdSensip0)); 1003 1004 PetscCall(VecDuplicate(ts->vec_sol, &th->VecDeltaFwdSensipCol)); 1005 PetscFunctionReturn(PETSC_SUCCESS); 1006 } 1007 1008 static PetscErrorCode TSForwardReset_Theta(TS ts) 1009 { 1010 TS_Theta *th = (TS_Theta *)ts->data; 1011 TS quadts = ts->quadraturets; 1012 1013 PetscFunctionBegin; 1014 if (quadts && quadts->mat_sensip) { 1015 PetscCall(MatDestroy(&th->MatIntegralSensipTemp)); 1016 PetscCall(MatDestroy(&th->MatIntegralSensip0)); 1017 } 1018 PetscCall(VecDestroy(&th->VecDeltaFwdSensipCol)); 1019 PetscCall(MatDestroy(&th->MatDeltaFwdSensip)); 1020 PetscCall(MatDestroy(&th->MatFwdSensip0)); 1021 PetscFunctionReturn(PETSC_SUCCESS); 1022 } 1023 1024 static PetscErrorCode TSSetUp_Theta(TS ts) 1025 { 1026 TS_Theta *th = (TS_Theta *)ts->data; 1027 TS quadts = ts->quadraturets; 1028 PetscBool match; 1029 1030 PetscFunctionBegin; 1031 if (!th->VecCostIntegral0 && quadts && ts->costintegralfwd) { /* back up cost integral */ 1032 PetscCall(VecDuplicate(quadts->vec_sol, &th->VecCostIntegral0)); 1033 } 1034 if (!th->X) PetscCall(VecDuplicate(ts->vec_sol, &th->X)); 1035 if (!th->Xdot) PetscCall(VecDuplicate(ts->vec_sol, &th->Xdot)); 1036 if (!th->X0) PetscCall(VecDuplicate(ts->vec_sol, &th->X0)); 1037 if (th->endpoint) PetscCall(VecDuplicate(ts->vec_sol, &th->affine)); 1038 1039 th->order = (th->Theta == 0.5) ? 2 : 1; 1040 th->shift = 1 / (th->Theta * ts->time_step); 1041 1042 PetscCall(TSGetDM(ts, &ts->dm)); 1043 PetscCall(DMCoarsenHookAdd(ts->dm, DMCoarsenHook_TSTheta, DMRestrictHook_TSTheta, ts)); 1044 PetscCall(DMSubDomainHookAdd(ts->dm, DMSubDomainHook_TSTheta, DMSubDomainRestrictHook_TSTheta, ts)); 1045 1046 PetscCall(TSGetAdapt(ts, &ts->adapt)); 1047 PetscCall(TSAdaptCandidatesClear(ts->adapt)); 1048 PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &match)); 1049 if (!match) { 1050 if (!th->vec_sol_prev) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_sol_prev)); 1051 if (!th->vec_lte_work) PetscCall(VecDuplicate(ts->vec_sol, &th->vec_lte_work)); 1052 } 1053 PetscCall(TSGetSNES(ts, &ts->snes)); 1054 1055 ts->stifflyaccurate = (!th->endpoint && th->Theta != 1.0) ? PETSC_FALSE : PETSC_TRUE; 1056 PetscFunctionReturn(PETSC_SUCCESS); 1057 } 1058 1059 static PetscErrorCode TSAdjointSetUp_Theta(TS ts) 1060 { 1061 TS_Theta *th = (TS_Theta *)ts->data; 1062 1063 PetscFunctionBegin; 1064 PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam)); 1065 PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsSensiTemp)); 1066 if (ts->vecs_sensip) PetscCall(VecDuplicateVecs(ts->vecs_sensip[0], ts->numcost, &th->VecsDeltaMu)); 1067 if (ts->vecs_sensi2) { 1068 PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam2)); 1069 PetscCall(VecDuplicateVecs(ts->vecs_sensi2[0], ts->numcost, &th->VecsSensi2Temp)); 1070 /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */ 1071 if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu; 1072 if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup; 1073 } 1074 if (ts->vecs_sensi2p) { 1075 PetscCall(VecDuplicateVecs(ts->vecs_sensi2p[0], ts->numcost, &th->VecsDeltaMu2)); 1076 /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */ 1077 if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu; 1078 if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp; 1079 } 1080 PetscFunctionReturn(PETSC_SUCCESS); 1081 } 1082 1083 static PetscErrorCode TSSetFromOptions_Theta(TS ts, PetscOptionItems PetscOptionsObject) 1084 { 1085 TS_Theta *th = (TS_Theta *)ts->data; 1086 1087 PetscFunctionBegin; 1088 PetscOptionsHeadBegin(PetscOptionsObject, "Theta ODE solver options"); 1089 { 1090 PetscCall(PetscOptionsReal("-ts_theta_theta", "Location of stage (0<Theta<=1)", "TSThetaSetTheta", th->Theta, &th->Theta, NULL)); 1091 PetscCall(PetscOptionsBool("-ts_theta_endpoint", "Use the endpoint instead of midpoint form of the Theta method", "TSThetaSetEndpoint", th->endpoint, &th->endpoint, NULL)); 1092 PetscCall(PetscOptionsBool("-ts_theta_initial_guess_extrapolate", "Extrapolate stage initial guess from previous solution (sometimes unstable)", "TSThetaSetExtrapolate", th->extrapolate, &th->extrapolate, NULL)); 1093 } 1094 PetscOptionsHeadEnd(); 1095 PetscFunctionReturn(PETSC_SUCCESS); 1096 } 1097 1098 static PetscErrorCode TSView_Theta(TS ts, PetscViewer viewer) 1099 { 1100 TS_Theta *th = (TS_Theta *)ts->data; 1101 PetscBool isascii; 1102 1103 PetscFunctionBegin; 1104 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 1105 if (isascii) { 1106 PetscCall(PetscViewerASCIIPrintf(viewer, " Theta=%g\n", (double)th->Theta)); 1107 PetscCall(PetscViewerASCIIPrintf(viewer, " Extrapolation=%s\n", th->extrapolate ? "yes" : "no")); 1108 } 1109 PetscFunctionReturn(PETSC_SUCCESS); 1110 } 1111 1112 static PetscErrorCode TSThetaGetTheta_Theta(TS ts, PetscReal *theta) 1113 { 1114 TS_Theta *th = (TS_Theta *)ts->data; 1115 1116 PetscFunctionBegin; 1117 *theta = th->Theta; 1118 PetscFunctionReturn(PETSC_SUCCESS); 1119 } 1120 1121 static PetscErrorCode TSThetaSetTheta_Theta(TS ts, PetscReal theta) 1122 { 1123 TS_Theta *th = (TS_Theta *)ts->data; 1124 1125 PetscFunctionBegin; 1126 PetscCheck(theta > 0 && theta <= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Theta %g not in range (0,1]", (double)theta); 1127 th->Theta = theta; 1128 th->order = (th->Theta == 0.5) ? 2 : 1; 1129 PetscFunctionReturn(PETSC_SUCCESS); 1130 } 1131 1132 static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts, PetscBool *endpoint) 1133 { 1134 TS_Theta *th = (TS_Theta *)ts->data; 1135 1136 PetscFunctionBegin; 1137 *endpoint = th->endpoint; 1138 PetscFunctionReturn(PETSC_SUCCESS); 1139 } 1140 1141 static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts, PetscBool flg) 1142 { 1143 TS_Theta *th = (TS_Theta *)ts->data; 1144 1145 PetscFunctionBegin; 1146 th->endpoint = flg; 1147 PetscFunctionReturn(PETSC_SUCCESS); 1148 } 1149 1150 #if defined(PETSC_HAVE_COMPLEX) 1151 static PetscErrorCode TSComputeLinearStability_Theta(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi) 1152 { 1153 PetscComplex z = xr + xi * PETSC_i, f; 1154 TS_Theta *th = (TS_Theta *)ts->data; 1155 1156 PetscFunctionBegin; 1157 f = (1.0 + (1.0 - th->Theta) * z) / (1.0 - th->Theta * z); 1158 *yr = PetscRealPartComplex(f); 1159 *yi = PetscImaginaryPartComplex(f); 1160 PetscFunctionReturn(PETSC_SUCCESS); 1161 } 1162 #endif 1163 1164 static PetscErrorCode TSGetStages_Theta(TS ts, PetscInt *ns, Vec *Y[]) 1165 { 1166 TS_Theta *th = (TS_Theta *)ts->data; 1167 1168 PetscFunctionBegin; 1169 if (ns) { 1170 if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */ 1171 else *ns = 2; /* endpoint form */ 1172 } 1173 if (Y) { 1174 if (!th->endpoint && th->Theta != 1.0) { 1175 th->Stages[0] = th->X; 1176 } else { 1177 th->Stages[0] = th->X0; 1178 th->Stages[1] = ts->vec_sol; /* stiffly accurate */ 1179 } 1180 *Y = th->Stages; 1181 } 1182 PetscFunctionReturn(PETSC_SUCCESS); 1183 } 1184 1185 /*MC 1186 TSTHETA - DAE solver using the implicit Theta method 1187 1188 Level: beginner 1189 1190 Options Database Keys: 1191 + -ts_theta_theta <Theta> - Location of stage (0<Theta<=1) 1192 . -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method 1193 - -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable) 1194 1195 Notes: 1196 .vb 1197 -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER) 1198 -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule 1199 -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN) 1200 .ve 1201 1202 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. 1203 1204 The midpoint variant is cast as a 1-stage implicit Runge-Kutta method. 1205 1206 .vb 1207 Theta | Theta 1208 ------------- 1209 | 1 1210 .ve 1211 1212 For the default Theta=0.5, this is also known as the implicit midpoint rule. 1213 1214 When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit: 1215 1216 .vb 1217 0 | 0 0 1218 1 | 1-Theta Theta 1219 ------------------- 1220 | 1-Theta Theta 1221 .ve 1222 1223 For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN). 1224 1225 To apply a diagonally implicit RK method to DAE, the stage formula 1226 .vb 1227 Y_i = X + h sum_j a_ij Y'_j 1228 .ve 1229 is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i) 1230 1231 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSCN`, `TSBEULER`, `TSThetaSetTheta()`, `TSThetaSetEndpoint()` 1232 M*/ 1233 PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts) 1234 { 1235 TS_Theta *th; 1236 1237 PetscFunctionBegin; 1238 ts->ops->reset = TSReset_Theta; 1239 ts->ops->adjointreset = TSAdjointReset_Theta; 1240 ts->ops->destroy = TSDestroy_Theta; 1241 ts->ops->view = TSView_Theta; 1242 ts->ops->setup = TSSetUp_Theta; 1243 ts->ops->adjointsetup = TSAdjointSetUp_Theta; 1244 ts->ops->adjointreset = TSAdjointReset_Theta; 1245 ts->ops->step = TSStep_Theta; 1246 ts->ops->interpolate = TSInterpolate_Theta; 1247 ts->ops->evaluatewlte = TSEvaluateWLTE_Theta; 1248 ts->ops->rollback = TSRollBack_Theta; 1249 ts->ops->resizeregister = TSResizeRegister_Theta; 1250 ts->ops->setfromoptions = TSSetFromOptions_Theta; 1251 ts->ops->snesfunction = SNESTSFormFunction_Theta; 1252 ts->ops->snesjacobian = SNESTSFormJacobian_Theta; 1253 #if defined(PETSC_HAVE_COMPLEX) 1254 ts->ops->linearstability = TSComputeLinearStability_Theta; 1255 #endif 1256 ts->ops->getstages = TSGetStages_Theta; 1257 ts->ops->adjointstep = TSAdjointStep_Theta; 1258 ts->ops->adjointintegral = TSAdjointCostIntegral_Theta; 1259 ts->ops->forwardintegral = TSForwardCostIntegral_Theta; 1260 ts->default_adapt_type = TSADAPTNONE; 1261 1262 ts->ops->forwardsetup = TSForwardSetUp_Theta; 1263 ts->ops->forwardreset = TSForwardReset_Theta; 1264 ts->ops->forwardstep = TSForwardStep_Theta; 1265 ts->ops->forwardgetstages = TSForwardGetStages_Theta; 1266 1267 ts->usessnes = PETSC_TRUE; 1268 1269 PetscCall(PetscNew(&th)); 1270 ts->data = (void *)th; 1271 1272 th->VecsDeltaLam = NULL; 1273 th->VecsDeltaMu = NULL; 1274 th->VecsSensiTemp = NULL; 1275 th->VecsSensi2Temp = NULL; 1276 1277 th->extrapolate = PETSC_FALSE; 1278 th->Theta = 0.5; 1279 th->order = 2; 1280 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", TSThetaGetTheta_Theta)); 1281 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", TSThetaSetTheta_Theta)); 1282 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", TSThetaGetEndpoint_Theta)); 1283 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", TSThetaSetEndpoint_Theta)); 1284 PetscFunctionReturn(PETSC_SUCCESS); 1285 } 1286 1287 /*@ 1288 TSThetaGetTheta - Get the abscissa of the stage in (0,1] for `TSTHETA` 1289 1290 Not Collective 1291 1292 Input Parameter: 1293 . ts - timestepping context 1294 1295 Output Parameter: 1296 . theta - stage abscissa 1297 1298 Level: advanced 1299 1300 Note: 1301 Use of this function is normally only required to hack `TSTHETA` to use a modified integration scheme. 1302 1303 .seealso: [](ch_ts), `TSThetaSetTheta()`, `TSTHETA` 1304 @*/ 1305 PetscErrorCode TSThetaGetTheta(TS ts, PetscReal *theta) 1306 { 1307 PetscFunctionBegin; 1308 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1309 PetscAssertPointer(theta, 2); 1310 PetscUseMethod(ts, "TSThetaGetTheta_C", (TS, PetscReal *), (ts, theta)); 1311 PetscFunctionReturn(PETSC_SUCCESS); 1312 } 1313 1314 /*@ 1315 TSThetaSetTheta - Set the abscissa of the stage in (0,1] for `TSTHETA` 1316 1317 Not Collective 1318 1319 Input Parameters: 1320 + ts - timestepping context 1321 - theta - stage abscissa 1322 1323 Options Database Key: 1324 . -ts_theta_theta <theta> - set theta 1325 1326 Level: intermediate 1327 1328 .seealso: [](ch_ts), `TSThetaGetTheta()`, `TSTHETA`, `TSCN` 1329 @*/ 1330 PetscErrorCode TSThetaSetTheta(TS ts, PetscReal theta) 1331 { 1332 PetscFunctionBegin; 1333 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1334 PetscTryMethod(ts, "TSThetaSetTheta_C", (TS, PetscReal), (ts, theta)); 1335 PetscFunctionReturn(PETSC_SUCCESS); 1336 } 1337 1338 /*@ 1339 TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA` 1340 1341 Not Collective 1342 1343 Input Parameter: 1344 . ts - timestepping context 1345 1346 Output Parameter: 1347 . endpoint - `PETSC_TRUE` when using the endpoint variant 1348 1349 Level: advanced 1350 1351 .seealso: [](ch_ts), `TSThetaSetEndpoint()`, `TSTHETA`, `TSCN` 1352 @*/ 1353 PetscErrorCode TSThetaGetEndpoint(TS ts, PetscBool *endpoint) 1354 { 1355 PetscFunctionBegin; 1356 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1357 PetscAssertPointer(endpoint, 2); 1358 PetscUseMethod(ts, "TSThetaGetEndpoint_C", (TS, PetscBool *), (ts, endpoint)); 1359 PetscFunctionReturn(PETSC_SUCCESS); 1360 } 1361 1362 /*@ 1363 TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA` 1364 1365 Not Collective 1366 1367 Input Parameters: 1368 + ts - timestepping context 1369 - flg - `PETSC_TRUE` to use the endpoint variant 1370 1371 Options Database Key: 1372 . -ts_theta_endpoint <flg> - use the endpoint variant 1373 1374 Level: intermediate 1375 1376 .seealso: [](ch_ts), `TSTHETA`, `TSCN` 1377 @*/ 1378 PetscErrorCode TSThetaSetEndpoint(TS ts, PetscBool flg) 1379 { 1380 PetscFunctionBegin; 1381 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1382 PetscTryMethod(ts, "TSThetaSetEndpoint_C", (TS, PetscBool), (ts, flg)); 1383 PetscFunctionReturn(PETSC_SUCCESS); 1384 } 1385 1386 /* 1387 * TSBEULER and TSCN are straightforward specializations of TSTHETA. 1388 * The creation functions for these specializations are below. 1389 */ 1390 1391 static PetscErrorCode TSSetUp_BEuler(TS ts) 1392 { 1393 TS_Theta *th = (TS_Theta *)ts->data; 1394 1395 PetscFunctionBegin; 1396 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"); 1397 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"); 1398 PetscCall(TSSetUp_Theta(ts)); 1399 PetscFunctionReturn(PETSC_SUCCESS); 1400 } 1401 1402 static PetscErrorCode TSView_BEuler(TS ts, PetscViewer viewer) 1403 { 1404 PetscFunctionBegin; 1405 PetscFunctionReturn(PETSC_SUCCESS); 1406 } 1407 1408 /*MC 1409 TSBEULER - ODE solver using the implicit backward Euler method 1410 1411 Level: beginner 1412 1413 Note: 1414 `TSBEULER` is equivalent to `TSTHETA` with Theta=1.0 or `-ts_type theta -ts_theta_theta 1.0` 1415 1416 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSEULER`, `TSCN`, `TSTHETA` 1417 M*/ 1418 PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts) 1419 { 1420 PetscFunctionBegin; 1421 PetscCall(TSCreate_Theta(ts)); 1422 PetscCall(TSThetaSetTheta(ts, 1.0)); 1423 PetscCall(TSThetaSetEndpoint(ts, PETSC_FALSE)); 1424 ts->ops->setup = TSSetUp_BEuler; 1425 ts->ops->view = TSView_BEuler; 1426 PetscFunctionReturn(PETSC_SUCCESS); 1427 } 1428 1429 static PetscErrorCode TSSetUp_CN(TS ts) 1430 { 1431 TS_Theta *th = (TS_Theta *)ts->data; 1432 1433 PetscFunctionBegin; 1434 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"); 1435 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"); 1436 PetscCall(TSSetUp_Theta(ts)); 1437 PetscFunctionReturn(PETSC_SUCCESS); 1438 } 1439 1440 static PetscErrorCode TSView_CN(TS ts, PetscViewer viewer) 1441 { 1442 PetscFunctionBegin; 1443 PetscFunctionReturn(PETSC_SUCCESS); 1444 } 1445 1446 /*MC 1447 TSCN - ODE solver using the implicit Crank-Nicolson method. 1448 1449 Level: beginner 1450 1451 Notes: 1452 `TSCN` is equivalent to `TSTHETA` with Theta=0.5 and the "endpoint" option set. I.e. 1453 .vb 1454 -ts_type theta 1455 -ts_theta_theta 0.5 1456 -ts_theta_endpoint 1457 .ve 1458 1459 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSBEULER`, `TSTHETA`, `TSType`, 1460 M*/ 1461 PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts) 1462 { 1463 PetscFunctionBegin; 1464 PetscCall(TSCreate_Theta(ts)); 1465 PetscCall(TSThetaSetTheta(ts, 0.5)); 1466 PetscCall(TSThetaSetEndpoint(ts, PETSC_TRUE)); 1467 ts->ops->setup = TSSetUp_CN; 1468 ts->ops->view = TSView_CN; 1469 PetscFunctionReturn(PETSC_SUCCESS); 1470 } 1471