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