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 scal[0] = -1 / a; 711 scal[1] = +1 / (a - 1); 712 scal[2] = -1 / (a * (a - 1)); 713 vecs[0] = X; 714 vecs[1] = th->X0; 715 vecs[2] = th->vec_sol_prev; 716 PetscCall(VecCopy(X, Y)); 717 PetscCall(VecMAXPY(Y, 3, scal, vecs)); 718 PetscCall(TSErrorWeightedNorm(ts, X, Y, wnormtype, wlte, &wltea, &wlter)); 719 } 720 if (order) *order = 2; 721 PetscFunctionReturn(PETSC_SUCCESS); 722 } 723 724 static PetscErrorCode TSRollBack_Theta(TS ts) 725 { 726 TS_Theta *th = (TS_Theta *)ts->data; 727 TS quadts = ts->quadraturets; 728 729 PetscFunctionBegin; 730 if (quadts && ts->costintegralfwd) PetscCall(VecCopy(th->VecCostIntegral0, quadts->vec_sol)); 731 th->status = TS_STEP_INCOMPLETE; 732 if (ts->mat_sensip) PetscCall(MatCopy(th->MatFwdSensip0, ts->mat_sensip, SAME_NONZERO_PATTERN)); 733 if (quadts && quadts->mat_sensip) PetscCall(MatCopy(th->MatIntegralSensip0, quadts->mat_sensip, SAME_NONZERO_PATTERN)); 734 PetscFunctionReturn(PETSC_SUCCESS); 735 } 736 737 static PetscErrorCode TSForwardStep_Theta(TS ts) 738 { 739 TS_Theta *th = (TS_Theta *)ts->data; 740 TS quadts = ts->quadraturets; 741 Mat MatDeltaFwdSensip = th->MatDeltaFwdSensip; 742 Vec VecDeltaFwdSensipCol = th->VecDeltaFwdSensipCol; 743 PetscInt ntlm; 744 KSP ksp; 745 Mat J, Jpre, quadJ = NULL, quadJp = NULL; 746 PetscScalar *barr, *xarr; 747 PetscReal previous_shift; 748 749 PetscFunctionBegin; 750 previous_shift = th->shift; 751 PetscCall(MatCopy(ts->mat_sensip, th->MatFwdSensip0, SAME_NONZERO_PATTERN)); 752 753 if (quadts && quadts->mat_sensip) PetscCall(MatCopy(quadts->mat_sensip, th->MatIntegralSensip0, SAME_NONZERO_PATTERN)); 754 PetscCall(SNESGetKSP(ts->snes, &ksp)); 755 PetscCall(TSGetIJacobian(ts, &J, &Jpre, NULL, NULL)); 756 if (quadts) { 757 PetscCall(TSGetRHSJacobian(quadts, &quadJ, NULL, NULL, NULL)); 758 PetscCall(TSGetRHSJacobianP(quadts, &quadJp, NULL, NULL)); 759 } 760 761 /* Build RHS */ 762 if (th->endpoint) { /* 2-stage method*/ 763 th->shift = 1. / ((th->Theta - 1.) * th->time_step0); 764 PetscCall(TSComputeIJacobian(ts, th->ptime0, th->X0, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 765 PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DETERMINE, &MatDeltaFwdSensip)); 766 PetscCall(MatScale(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta)); 767 768 /* Add the f_p forcing terms */ 769 if (ts->Jacp) { 770 PetscCall(VecZeroEntries(th->Xdot)); 771 PetscCall(TSComputeIJacobianP(ts, th->ptime0, th->X0, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 772 PetscCall(MatAXPY(MatDeltaFwdSensip, (th->Theta - 1.) / th->Theta, ts->Jacp, SUBSET_NONZERO_PATTERN)); 773 th->shift = previous_shift; 774 PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, ts->vec_sol)); 775 PetscCall(TSComputeIJacobianP(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 776 PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN)); 777 } 778 } else { /* 1-stage method */ 779 th->shift = 0.0; 780 PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 781 PetscCall(MatMatMult(J, ts->mat_sensip, MAT_REUSE_MATRIX, PETSC_DETERMINE, &MatDeltaFwdSensip)); 782 PetscCall(MatScale(MatDeltaFwdSensip, -1.)); 783 784 /* Add the f_p forcing terms */ 785 if (ts->Jacp) { 786 th->shift = previous_shift; 787 PetscCall(VecAXPBYPCZ(th->Xdot, -th->shift, th->shift, 0, th->X0, th->X)); 788 PetscCall(TSComputeIJacobianP(ts, th->stage_time, th->X, th->Xdot, th->shift, ts->Jacp, PETSC_FALSE)); 789 PetscCall(MatAXPY(MatDeltaFwdSensip, -1., ts->Jacp, SUBSET_NONZERO_PATTERN)); 790 } 791 } 792 793 /* Build LHS */ 794 th->shift = previous_shift; /* recover the previous shift used in TSStep_Theta() */ 795 if (th->endpoint) { 796 PetscCall(TSComputeIJacobian(ts, th->stage_time, ts->vec_sol, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 797 } else { 798 PetscCall(TSComputeIJacobian(ts, th->stage_time, th->X, th->Xdot, th->shift, J, Jpre, PETSC_FALSE)); 799 } 800 PetscCall(KSPSetOperators(ksp, J, Jpre)); 801 802 /* 803 Evaluate the first stage of integral gradients with the 2-stage method: 804 drdu|t_n*S(t_n) + drdp|t_n 805 This is done before the linear solve because the sensitivity variable S(t_n) will be propagated to S(t_{n+1}) 806 */ 807 if (th->endpoint) { /* 2-stage method only */ 808 if (quadts && quadts->mat_sensip) { 809 PetscCall(TSComputeRHSJacobian(quadts, th->ptime0, th->X0, quadJ, NULL)); 810 PetscCall(TSComputeRHSJacobianP(quadts, th->ptime0, th->X0, quadJp)); 811 PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DETERMINE, &th->MatIntegralSensipTemp)); 812 PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN)); 813 PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * (1. - th->Theta), th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN)); 814 } 815 } 816 817 /* Solve the tangent linear equation for forward sensitivities to parameters */ 818 for (ntlm = 0; ntlm < th->num_tlm; ntlm++) { 819 KSPConvergedReason kspreason; 820 PetscCall(MatDenseGetColumn(MatDeltaFwdSensip, ntlm, &barr)); 821 PetscCall(VecPlaceArray(VecDeltaFwdSensipCol, barr)); 822 if (th->endpoint) { 823 PetscCall(MatDenseGetColumn(ts->mat_sensip, ntlm, &xarr)); 824 PetscCall(VecPlaceArray(ts->vec_sensip_col, xarr)); 825 PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, ts->vec_sensip_col)); 826 PetscCall(VecResetArray(ts->vec_sensip_col)); 827 PetscCall(MatDenseRestoreColumn(ts->mat_sensip, &xarr)); 828 } else { 829 PetscCall(KSPSolve(ksp, VecDeltaFwdSensipCol, VecDeltaFwdSensipCol)); 830 } 831 PetscCall(KSPGetConvergedReason(ksp, &kspreason)); 832 if (kspreason < 0) { 833 ts->reason = TSFORWARD_DIVERGED_LINEAR_SOLVE; 834 PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", %" PetscInt_FMT "th tangent linear solve, linear solve fails, stopping tangent linear solve\n", ts->steps, ntlm)); 835 } 836 PetscCall(VecResetArray(VecDeltaFwdSensipCol)); 837 PetscCall(MatDenseRestoreColumn(MatDeltaFwdSensip, &barr)); 838 } 839 840 /* 841 Evaluate the second stage of integral gradients with the 2-stage method: 842 drdu|t_{n+1}*S(t_{n+1}) + drdp|t_{n+1} 843 */ 844 if (quadts && quadts->mat_sensip) { 845 if (!th->endpoint) { 846 PetscCall(MatAXPY(ts->mat_sensip, 1, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); /* stage sensitivity */ 847 PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, th->X, quadJ, NULL)); 848 PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, th->X, quadJp)); 849 PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DETERMINE, &th->MatIntegralSensipTemp)); 850 PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN)); 851 PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN)); 852 PetscCall(MatAXPY(ts->mat_sensip, (1. - th->Theta) / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); 853 } else { 854 PetscCall(TSComputeRHSJacobian(quadts, th->stage_time, ts->vec_sol, quadJ, NULL)); 855 PetscCall(TSComputeRHSJacobianP(quadts, th->stage_time, ts->vec_sol, quadJp)); 856 PetscCall(MatTransposeMatMult(ts->mat_sensip, quadJ, MAT_REUSE_MATRIX, PETSC_DETERMINE, &th->MatIntegralSensipTemp)); 857 PetscCall(MatAXPY(th->MatIntegralSensipTemp, 1, quadJp, SAME_NONZERO_PATTERN)); 858 PetscCall(MatAXPY(quadts->mat_sensip, th->time_step0 * th->Theta, th->MatIntegralSensipTemp, SAME_NONZERO_PATTERN)); 859 } 860 } else { 861 if (!th->endpoint) PetscCall(MatAXPY(ts->mat_sensip, 1. / th->Theta, MatDeltaFwdSensip, SAME_NONZERO_PATTERN)); 862 } 863 PetscFunctionReturn(PETSC_SUCCESS); 864 } 865 866 static PetscErrorCode TSForwardGetStages_Theta(TS ts, PetscInt *ns, Mat *stagesensip[]) 867 { 868 TS_Theta *th = (TS_Theta *)ts->data; 869 870 PetscFunctionBegin; 871 if (ns) { 872 if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */ 873 else *ns = 2; /* endpoint form */ 874 } 875 if (stagesensip) { 876 if (!th->endpoint && th->Theta != 1.0) { 877 th->MatFwdStages[0] = th->MatDeltaFwdSensip; 878 } else { 879 th->MatFwdStages[0] = th->MatFwdSensip0; 880 th->MatFwdStages[1] = ts->mat_sensip; /* stiffly accurate */ 881 } 882 *stagesensip = th->MatFwdStages; 883 } 884 PetscFunctionReturn(PETSC_SUCCESS); 885 } 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 /*------------------------------------------------------------*/ 1060 1061 static PetscErrorCode TSAdjointSetUp_Theta(TS ts) 1062 { 1063 TS_Theta *th = (TS_Theta *)ts->data; 1064 1065 PetscFunctionBegin; 1066 PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam)); 1067 PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsSensiTemp)); 1068 if (ts->vecs_sensip) PetscCall(VecDuplicateVecs(ts->vecs_sensip[0], ts->numcost, &th->VecsDeltaMu)); 1069 if (ts->vecs_sensi2) { 1070 PetscCall(VecDuplicateVecs(ts->vecs_sensi[0], ts->numcost, &th->VecsDeltaLam2)); 1071 PetscCall(VecDuplicateVecs(ts->vecs_sensi2[0], ts->numcost, &th->VecsSensi2Temp)); 1072 /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */ 1073 if (!ts->ihessianproduct_fuu) ts->vecs_fuu = ts->vecs_guu; 1074 if (!ts->ihessianproduct_fup) ts->vecs_fup = ts->vecs_gup; 1075 } 1076 if (ts->vecs_sensi2p) { 1077 PetscCall(VecDuplicateVecs(ts->vecs_sensi2p[0], ts->numcost, &th->VecsDeltaMu2)); 1078 /* hack ts to make implicit TS solver work when users provide only explicit versions of callbacks (RHSFunction,RHSJacobian,RHSHessian etc.) */ 1079 if (!ts->ihessianproduct_fpu) ts->vecs_fpu = ts->vecs_gpu; 1080 if (!ts->ihessianproduct_fpp) ts->vecs_fpp = ts->vecs_gpp; 1081 } 1082 PetscFunctionReturn(PETSC_SUCCESS); 1083 } 1084 1085 static PetscErrorCode TSSetFromOptions_Theta(TS ts, PetscOptionItems PetscOptionsObject) 1086 { 1087 TS_Theta *th = (TS_Theta *)ts->data; 1088 1089 PetscFunctionBegin; 1090 PetscOptionsHeadBegin(PetscOptionsObject, "Theta ODE solver options"); 1091 { 1092 PetscCall(PetscOptionsReal("-ts_theta_theta", "Location of stage (0<Theta<=1)", "TSThetaSetTheta", th->Theta, &th->Theta, NULL)); 1093 PetscCall(PetscOptionsBool("-ts_theta_endpoint", "Use the endpoint instead of midpoint form of the Theta method", "TSThetaSetEndpoint", th->endpoint, &th->endpoint, NULL)); 1094 PetscCall(PetscOptionsBool("-ts_theta_initial_guess_extrapolate", "Extrapolate stage initial guess from previous solution (sometimes unstable)", "TSThetaSetExtrapolate", th->extrapolate, &th->extrapolate, NULL)); 1095 } 1096 PetscOptionsHeadEnd(); 1097 PetscFunctionReturn(PETSC_SUCCESS); 1098 } 1099 1100 static PetscErrorCode TSView_Theta(TS ts, PetscViewer viewer) 1101 { 1102 TS_Theta *th = (TS_Theta *)ts->data; 1103 PetscBool isascii; 1104 1105 PetscFunctionBegin; 1106 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 1107 if (isascii) { 1108 PetscCall(PetscViewerASCIIPrintf(viewer, " Theta=%g\n", (double)th->Theta)); 1109 PetscCall(PetscViewerASCIIPrintf(viewer, " Extrapolation=%s\n", th->extrapolate ? "yes" : "no")); 1110 } 1111 PetscFunctionReturn(PETSC_SUCCESS); 1112 } 1113 1114 static PetscErrorCode TSThetaGetTheta_Theta(TS ts, PetscReal *theta) 1115 { 1116 TS_Theta *th = (TS_Theta *)ts->data; 1117 1118 PetscFunctionBegin; 1119 *theta = th->Theta; 1120 PetscFunctionReturn(PETSC_SUCCESS); 1121 } 1122 1123 static PetscErrorCode TSThetaSetTheta_Theta(TS ts, PetscReal theta) 1124 { 1125 TS_Theta *th = (TS_Theta *)ts->data; 1126 1127 PetscFunctionBegin; 1128 PetscCheck(theta > 0 && theta <= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Theta %g not in range (0,1]", (double)theta); 1129 th->Theta = theta; 1130 th->order = (th->Theta == 0.5) ? 2 : 1; 1131 PetscFunctionReturn(PETSC_SUCCESS); 1132 } 1133 1134 static PetscErrorCode TSThetaGetEndpoint_Theta(TS ts, PetscBool *endpoint) 1135 { 1136 TS_Theta *th = (TS_Theta *)ts->data; 1137 1138 PetscFunctionBegin; 1139 *endpoint = th->endpoint; 1140 PetscFunctionReturn(PETSC_SUCCESS); 1141 } 1142 1143 static PetscErrorCode TSThetaSetEndpoint_Theta(TS ts, PetscBool flg) 1144 { 1145 TS_Theta *th = (TS_Theta *)ts->data; 1146 1147 PetscFunctionBegin; 1148 th->endpoint = flg; 1149 PetscFunctionReturn(PETSC_SUCCESS); 1150 } 1151 1152 #if defined(PETSC_HAVE_COMPLEX) 1153 static PetscErrorCode TSComputeLinearStability_Theta(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi) 1154 { 1155 PetscComplex z = xr + xi * PETSC_i, f; 1156 TS_Theta *th = (TS_Theta *)ts->data; 1157 1158 PetscFunctionBegin; 1159 f = (1.0 + (1.0 - th->Theta) * z) / (1.0 - th->Theta * z); 1160 *yr = PetscRealPartComplex(f); 1161 *yi = PetscImaginaryPartComplex(f); 1162 PetscFunctionReturn(PETSC_SUCCESS); 1163 } 1164 #endif 1165 1166 static PetscErrorCode TSGetStages_Theta(TS ts, PetscInt *ns, Vec *Y[]) 1167 { 1168 TS_Theta *th = (TS_Theta *)ts->data; 1169 1170 PetscFunctionBegin; 1171 if (ns) { 1172 if (!th->endpoint && th->Theta != 1.0) *ns = 1; /* midpoint form */ 1173 else *ns = 2; /* endpoint form */ 1174 } 1175 if (Y) { 1176 if (!th->endpoint && th->Theta != 1.0) { 1177 th->Stages[0] = th->X; 1178 } else { 1179 th->Stages[0] = th->X0; 1180 th->Stages[1] = ts->vec_sol; /* stiffly accurate */ 1181 } 1182 *Y = th->Stages; 1183 } 1184 PetscFunctionReturn(PETSC_SUCCESS); 1185 } 1186 1187 /* ------------------------------------------------------------ */ 1188 /*MC 1189 TSTHETA - DAE solver using the implicit Theta method 1190 1191 Level: beginner 1192 1193 Options Database Keys: 1194 + -ts_theta_theta <Theta> - Location of stage (0<Theta<=1) 1195 . -ts_theta_endpoint <flag> - Use the endpoint (like Crank-Nicholson) instead of midpoint form of the Theta method 1196 - -ts_theta_initial_guess_extrapolate <flg> - Extrapolate stage initial guess from previous solution (sometimes unstable) 1197 1198 Notes: 1199 .vb 1200 -ts_type theta -ts_theta_theta 1.0 corresponds to backward Euler (TSBEULER) 1201 -ts_type theta -ts_theta_theta 0.5 corresponds to the implicit midpoint rule 1202 -ts_type theta -ts_theta_theta 0.5 -ts_theta_endpoint corresponds to Crank-Nicholson (TSCN) 1203 .ve 1204 1205 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. 1206 1207 The midpoint variant is cast as a 1-stage implicit Runge-Kutta method. 1208 1209 .vb 1210 Theta | Theta 1211 ------------- 1212 | 1 1213 .ve 1214 1215 For the default Theta=0.5, this is also known as the implicit midpoint rule. 1216 1217 When the endpoint variant is chosen, the method becomes a 2-stage method with first stage explicit: 1218 1219 .vb 1220 0 | 0 0 1221 1 | 1-Theta Theta 1222 ------------------- 1223 | 1-Theta Theta 1224 .ve 1225 1226 For the default Theta=0.5, this is the trapezoid rule (also known as Crank-Nicolson, see TSCN). 1227 1228 To apply a diagonally implicit RK method to DAE, the stage formula 1229 .vb 1230 Y_i = X + h sum_j a_ij Y'_j 1231 .ve 1232 is interpreted as a formula for Y'_i in terms of Y_i and known values (Y'_j, j<i) 1233 1234 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSCN`, `TSBEULER`, `TSThetaSetTheta()`, `TSThetaSetEndpoint()` 1235 M*/ 1236 PETSC_EXTERN PetscErrorCode TSCreate_Theta(TS ts) 1237 { 1238 TS_Theta *th; 1239 1240 PetscFunctionBegin; 1241 ts->ops->reset = TSReset_Theta; 1242 ts->ops->adjointreset = TSAdjointReset_Theta; 1243 ts->ops->destroy = TSDestroy_Theta; 1244 ts->ops->view = TSView_Theta; 1245 ts->ops->setup = TSSetUp_Theta; 1246 ts->ops->adjointsetup = TSAdjointSetUp_Theta; 1247 ts->ops->adjointreset = TSAdjointReset_Theta; 1248 ts->ops->step = TSStep_Theta; 1249 ts->ops->interpolate = TSInterpolate_Theta; 1250 ts->ops->evaluatewlte = TSEvaluateWLTE_Theta; 1251 ts->ops->rollback = TSRollBack_Theta; 1252 ts->ops->resizeregister = TSResizeRegister_Theta; 1253 ts->ops->setfromoptions = TSSetFromOptions_Theta; 1254 ts->ops->snesfunction = SNESTSFormFunction_Theta; 1255 ts->ops->snesjacobian = SNESTSFormJacobian_Theta; 1256 #if defined(PETSC_HAVE_COMPLEX) 1257 ts->ops->linearstability = TSComputeLinearStability_Theta; 1258 #endif 1259 ts->ops->getstages = TSGetStages_Theta; 1260 ts->ops->adjointstep = TSAdjointStep_Theta; 1261 ts->ops->adjointintegral = TSAdjointCostIntegral_Theta; 1262 ts->ops->forwardintegral = TSForwardCostIntegral_Theta; 1263 ts->default_adapt_type = TSADAPTNONE; 1264 1265 ts->ops->forwardsetup = TSForwardSetUp_Theta; 1266 ts->ops->forwardreset = TSForwardReset_Theta; 1267 ts->ops->forwardstep = TSForwardStep_Theta; 1268 ts->ops->forwardgetstages = TSForwardGetStages_Theta; 1269 1270 ts->usessnes = PETSC_TRUE; 1271 1272 PetscCall(PetscNew(&th)); 1273 ts->data = (void *)th; 1274 1275 th->VecsDeltaLam = NULL; 1276 th->VecsDeltaMu = NULL; 1277 th->VecsSensiTemp = NULL; 1278 th->VecsSensi2Temp = NULL; 1279 1280 th->extrapolate = PETSC_FALSE; 1281 th->Theta = 0.5; 1282 th->order = 2; 1283 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetTheta_C", TSThetaGetTheta_Theta)); 1284 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetTheta_C", TSThetaSetTheta_Theta)); 1285 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaGetEndpoint_C", TSThetaGetEndpoint_Theta)); 1286 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSThetaSetEndpoint_C", TSThetaSetEndpoint_Theta)); 1287 PetscFunctionReturn(PETSC_SUCCESS); 1288 } 1289 1290 /*@ 1291 TSThetaGetTheta - Get the abscissa of the stage in (0,1] for `TSTHETA` 1292 1293 Not Collective 1294 1295 Input Parameter: 1296 . ts - timestepping context 1297 1298 Output Parameter: 1299 . theta - stage abscissa 1300 1301 Level: advanced 1302 1303 Note: 1304 Use of this function is normally only required to hack `TSTHETA` to use a modified integration scheme. 1305 1306 .seealso: [](ch_ts), `TSThetaSetTheta()`, `TSTHETA` 1307 @*/ 1308 PetscErrorCode TSThetaGetTheta(TS ts, PetscReal *theta) 1309 { 1310 PetscFunctionBegin; 1311 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1312 PetscAssertPointer(theta, 2); 1313 PetscUseMethod(ts, "TSThetaGetTheta_C", (TS, PetscReal *), (ts, theta)); 1314 PetscFunctionReturn(PETSC_SUCCESS); 1315 } 1316 1317 /*@ 1318 TSThetaSetTheta - Set the abscissa of the stage in (0,1] for `TSTHETA` 1319 1320 Not Collective 1321 1322 Input Parameters: 1323 + ts - timestepping context 1324 - theta - stage abscissa 1325 1326 Options Database Key: 1327 . -ts_theta_theta <theta> - set theta 1328 1329 Level: intermediate 1330 1331 .seealso: [](ch_ts), `TSThetaGetTheta()`, `TSTHETA`, `TSCN` 1332 @*/ 1333 PetscErrorCode TSThetaSetTheta(TS ts, PetscReal theta) 1334 { 1335 PetscFunctionBegin; 1336 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1337 PetscTryMethod(ts, "TSThetaSetTheta_C", (TS, PetscReal), (ts, theta)); 1338 PetscFunctionReturn(PETSC_SUCCESS); 1339 } 1340 1341 /*@ 1342 TSThetaGetEndpoint - Gets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA` 1343 1344 Not Collective 1345 1346 Input Parameter: 1347 . ts - timestepping context 1348 1349 Output Parameter: 1350 . endpoint - `PETSC_TRUE` when using the endpoint variant 1351 1352 Level: advanced 1353 1354 .seealso: [](ch_ts), `TSThetaSetEndpoint()`, `TSTHETA`, `TSCN` 1355 @*/ 1356 PetscErrorCode TSThetaGetEndpoint(TS ts, PetscBool *endpoint) 1357 { 1358 PetscFunctionBegin; 1359 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1360 PetscAssertPointer(endpoint, 2); 1361 PetscUseMethod(ts, "TSThetaGetEndpoint_C", (TS, PetscBool *), (ts, endpoint)); 1362 PetscFunctionReturn(PETSC_SUCCESS); 1363 } 1364 1365 /*@ 1366 TSThetaSetEndpoint - Sets whether to use the endpoint variant of the method (e.g. trapezoid/Crank-Nicolson instead of midpoint rule) for `TSTHETA` 1367 1368 Not Collective 1369 1370 Input Parameters: 1371 + ts - timestepping context 1372 - flg - `PETSC_TRUE` to use the endpoint variant 1373 1374 Options Database Key: 1375 . -ts_theta_endpoint <flg> - use the endpoint variant 1376 1377 Level: intermediate 1378 1379 .seealso: [](ch_ts), `TSTHETA`, `TSCN` 1380 @*/ 1381 PetscErrorCode TSThetaSetEndpoint(TS ts, PetscBool flg) 1382 { 1383 PetscFunctionBegin; 1384 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1385 PetscTryMethod(ts, "TSThetaSetEndpoint_C", (TS, PetscBool), (ts, flg)); 1386 PetscFunctionReturn(PETSC_SUCCESS); 1387 } 1388 1389 /* 1390 * TSBEULER and TSCN are straightforward specializations of TSTHETA. 1391 * The creation functions for these specializations are below. 1392 */ 1393 1394 static PetscErrorCode TSSetUp_BEuler(TS ts) 1395 { 1396 TS_Theta *th = (TS_Theta *)ts->data; 1397 1398 PetscFunctionBegin; 1399 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"); 1400 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"); 1401 PetscCall(TSSetUp_Theta(ts)); 1402 PetscFunctionReturn(PETSC_SUCCESS); 1403 } 1404 1405 static PetscErrorCode TSView_BEuler(TS ts, PetscViewer viewer) 1406 { 1407 PetscFunctionBegin; 1408 PetscFunctionReturn(PETSC_SUCCESS); 1409 } 1410 1411 /*MC 1412 TSBEULER - ODE solver using the implicit backward Euler method 1413 1414 Level: beginner 1415 1416 Note: 1417 `TSBEULER` is equivalent to `TSTHETA` with Theta=1.0 or `-ts_type theta -ts_theta_theta 1.0` 1418 1419 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSEULER`, `TSCN`, `TSTHETA` 1420 M*/ 1421 PETSC_EXTERN PetscErrorCode TSCreate_BEuler(TS ts) 1422 { 1423 PetscFunctionBegin; 1424 PetscCall(TSCreate_Theta(ts)); 1425 PetscCall(TSThetaSetTheta(ts, 1.0)); 1426 PetscCall(TSThetaSetEndpoint(ts, PETSC_FALSE)); 1427 ts->ops->setup = TSSetUp_BEuler; 1428 ts->ops->view = TSView_BEuler; 1429 PetscFunctionReturn(PETSC_SUCCESS); 1430 } 1431 1432 static PetscErrorCode TSSetUp_CN(TS ts) 1433 { 1434 TS_Theta *th = (TS_Theta *)ts->data; 1435 1436 PetscFunctionBegin; 1437 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"); 1438 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"); 1439 PetscCall(TSSetUp_Theta(ts)); 1440 PetscFunctionReturn(PETSC_SUCCESS); 1441 } 1442 1443 static PetscErrorCode TSView_CN(TS ts, PetscViewer viewer) 1444 { 1445 PetscFunctionBegin; 1446 PetscFunctionReturn(PETSC_SUCCESS); 1447 } 1448 1449 /*MC 1450 TSCN - ODE solver using the implicit Crank-Nicolson method. 1451 1452 Level: beginner 1453 1454 Notes: 1455 `TSCN` is equivalent to `TSTHETA` with Theta=0.5 and the "endpoint" option set. I.e. 1456 .vb 1457 -ts_type theta 1458 -ts_theta_theta 0.5 1459 -ts_theta_endpoint 1460 .ve 1461 1462 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSBEULER`, `TSTHETA`, `TSType`, 1463 M*/ 1464 PETSC_EXTERN PetscErrorCode TSCreate_CN(TS ts) 1465 { 1466 PetscFunctionBegin; 1467 PetscCall(TSCreate_Theta(ts)); 1468 PetscCall(TSThetaSetTheta(ts, 0.5)); 1469 PetscCall(TSThetaSetEndpoint(ts, PETSC_TRUE)); 1470 ts->ops->setup = TSSetUp_CN; 1471 ts->ops->view = TSView_CN; 1472 PetscFunctionReturn(PETSC_SUCCESS); 1473 } 1474