1 #include <petsc/private/tsimpl.h> /*I <petscts.h> I*/ 2 #include <petscdraw.h> 3 4 PetscLogEvent TS_AdjointStep, TS_ForwardStep, TS_JacobianPEval; 5 6 /* #define TSADJOINT_STAGE */ 7 8 /* ------------------------ Sensitivity Context ---------------------------*/ 9 10 /*@C 11 TSSetRHSJacobianP - Sets the function that computes the Jacobian of G w.r.t. the parameters P where U_t = G(U,P,t), as well as the location to store the matrix. 12 13 Logically Collective 14 15 Input Parameters: 16 + ts - `TS` context obtained from `TSCreate()` 17 . Amat - JacobianP matrix 18 . func - function 19 - ctx - [optional] user-defined function context 20 21 Level: intermediate 22 23 Note: 24 `Amat` has the same number of rows and the same row parallel layout as `u`, `Amat` has the same number of columns and parallel layout as `p` 25 26 .seealso: [](ch_ts), `TS`, `TSRHSJacobianPFn`, `TSGetRHSJacobianP()` 27 @*/ 28 PetscErrorCode TSSetRHSJacobianP(TS ts, Mat Amat, TSRHSJacobianPFn *func, void *ctx) 29 { 30 PetscFunctionBegin; 31 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 32 PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2); 33 34 ts->rhsjacobianp = func; 35 ts->rhsjacobianpctx = ctx; 36 if (Amat) { 37 PetscCall(PetscObjectReference((PetscObject)Amat)); 38 PetscCall(MatDestroy(&ts->Jacprhs)); 39 ts->Jacprhs = Amat; 40 } 41 PetscFunctionReturn(PETSC_SUCCESS); 42 } 43 44 /*@C 45 TSGetRHSJacobianP - Gets the function that computes the Jacobian of G w.r.t. the parameters P where U_t = G(U,P,t), as well as the location to store the matrix. 46 47 Logically Collective 48 49 Input Parameter: 50 . ts - `TS` context obtained from `TSCreate()` 51 52 Output Parameters: 53 + Amat - JacobianP matrix 54 . func - function 55 - ctx - [optional] user-defined function context 56 57 Level: intermediate 58 59 Note: 60 `Amat` has the same number of rows and the same row parallel layout as `u`, `Amat` has the same number of columns and parallel layout as `p` 61 62 .seealso: [](ch_ts), `TSSetRHSJacobianP()`, `TS`, `TSRHSJacobianPFn` 63 @*/ 64 PetscErrorCode TSGetRHSJacobianP(TS ts, Mat *Amat, TSRHSJacobianPFn **func, void **ctx) 65 { 66 PetscFunctionBegin; 67 if (func) *func = ts->rhsjacobianp; 68 if (ctx) *ctx = ts->rhsjacobianpctx; 69 if (Amat) *Amat = ts->Jacprhs; 70 PetscFunctionReturn(PETSC_SUCCESS); 71 } 72 73 /*@C 74 TSComputeRHSJacobianP - Runs the user-defined JacobianP function. 75 76 Collective 77 78 Input Parameters: 79 + ts - The `TS` context obtained from `TSCreate()` 80 . t - the time 81 - U - the solution at which to compute the Jacobian 82 83 Output Parameter: 84 . Amat - the computed Jacobian 85 86 Level: developer 87 88 .seealso: [](ch_ts), `TSSetRHSJacobianP()`, `TS` 89 @*/ 90 PetscErrorCode TSComputeRHSJacobianP(TS ts, PetscReal t, Vec U, Mat Amat) 91 { 92 PetscFunctionBegin; 93 if (!Amat) PetscFunctionReturn(PETSC_SUCCESS); 94 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 95 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 96 97 if (ts->rhsjacobianp) PetscCallBack("TS callback JacobianP for sensitivity analysis", (*ts->rhsjacobianp)(ts, t, U, Amat, ts->rhsjacobianpctx)); 98 else { 99 PetscBool assembled; 100 PetscCall(MatZeroEntries(Amat)); 101 PetscCall(MatAssembled(Amat, &assembled)); 102 if (!assembled) { 103 PetscCall(MatAssemblyBegin(Amat, MAT_FINAL_ASSEMBLY)); 104 PetscCall(MatAssemblyEnd(Amat, MAT_FINAL_ASSEMBLY)); 105 } 106 } 107 PetscFunctionReturn(PETSC_SUCCESS); 108 } 109 110 /*@C 111 TSSetIJacobianP - Sets the function that computes the Jacobian of F w.r.t. the parameters P where F(Udot,U,t) = G(U,P,t), as well as the location to store the matrix. 112 113 Logically Collective 114 115 Input Parameters: 116 + ts - `TS` context obtained from `TSCreate()` 117 . Amat - JacobianP matrix 118 . func - function 119 - ctx - [optional] user-defined function context 120 121 Calling sequence of `func`: 122 + ts - the `TS` context 123 . t - current timestep 124 . U - input vector (current ODE solution) 125 . Udot - time derivative of state vector 126 . shift - shift to apply, see note below 127 . A - output matrix 128 - ctx - [optional] user-defined function context 129 130 Level: intermediate 131 132 Note: 133 Amat has the same number of rows and the same row parallel layout as u, Amat has the same number of columns and parallel layout as p 134 135 .seealso: [](ch_ts), `TSSetRHSJacobianP()`, `TS` 136 @*/ 137 PetscErrorCode TSSetIJacobianP(TS ts, Mat Amat, PetscErrorCode (*func)(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat A, void *ctx), void *ctx) 138 { 139 PetscFunctionBegin; 140 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 141 PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2); 142 143 ts->ijacobianp = func; 144 ts->ijacobianpctx = ctx; 145 if (Amat) { 146 PetscCall(PetscObjectReference((PetscObject)Amat)); 147 PetscCall(MatDestroy(&ts->Jacp)); 148 ts->Jacp = Amat; 149 } 150 PetscFunctionReturn(PETSC_SUCCESS); 151 } 152 153 /*@ 154 TSComputeIJacobianP - Runs the user-defined IJacobianP function. 155 156 Collective 157 158 Input Parameters: 159 + ts - the `TS` context 160 . t - current timestep 161 . U - state vector 162 . Udot - time derivative of state vector 163 . shift - shift to apply, see note below 164 - imex - flag indicates if the method is IMEX so that the RHSJacobianP should be kept separate 165 166 Output Parameter: 167 . Amat - Jacobian matrix 168 169 Level: developer 170 171 .seealso: [](ch_ts), `TS`, `TSSetIJacobianP()` 172 @*/ 173 PetscErrorCode TSComputeIJacobianP(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat Amat, PetscBool imex) 174 { 175 PetscFunctionBegin; 176 if (!Amat) PetscFunctionReturn(PETSC_SUCCESS); 177 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 178 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 179 PetscValidHeaderSpecific(Udot, VEC_CLASSID, 4); 180 181 PetscCall(PetscLogEventBegin(TS_JacobianPEval, ts, U, Amat, 0)); 182 if (ts->ijacobianp) PetscCallBack("TS callback JacobianP for sensitivity analysis", (*ts->ijacobianp)(ts, t, U, Udot, shift, Amat, ts->ijacobianpctx)); 183 if (imex) { 184 if (!ts->ijacobianp) { /* system was written as Udot = G(t,U) */ 185 PetscBool assembled; 186 PetscCall(MatZeroEntries(Amat)); 187 PetscCall(MatAssembled(Amat, &assembled)); 188 if (!assembled) { 189 PetscCall(MatAssemblyBegin(Amat, MAT_FINAL_ASSEMBLY)); 190 PetscCall(MatAssemblyEnd(Amat, MAT_FINAL_ASSEMBLY)); 191 } 192 } 193 } else { 194 if (ts->rhsjacobianp) PetscCall(TSComputeRHSJacobianP(ts, t, U, ts->Jacprhs)); 195 if (ts->Jacprhs == Amat) { /* No IJacobian, so we only have the RHS matrix */ 196 PetscCall(MatScale(Amat, -1)); 197 } else if (ts->Jacprhs) { /* Both IJacobian and RHSJacobian */ 198 MatStructure axpy = DIFFERENT_NONZERO_PATTERN; 199 if (!ts->ijacobianp) { /* No IJacobianp provided, but we have a separate RHS matrix */ 200 PetscCall(MatZeroEntries(Amat)); 201 } 202 PetscCall(MatAXPY(Amat, -1, ts->Jacprhs, axpy)); 203 } 204 } 205 PetscCall(PetscLogEventEnd(TS_JacobianPEval, ts, U, Amat, 0)); 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 /*@C 210 TSSetCostIntegrand - Sets the routine for evaluating the integral term in one or more cost functions 211 212 Logically Collective 213 214 Input Parameters: 215 + ts - the `TS` context obtained from `TSCreate()` 216 . numcost - number of gradients to be computed, this is the number of cost functions 217 . costintegral - vector that stores the integral values 218 . rf - routine for evaluating the integrand function 219 . drduf - function that computes the gradients of the r with respect to u 220 . drdpf - function that computes the gradients of the r with respect to p, can be `NULL` if parametric sensitivity is not desired (`mu` = `NULL`) 221 . fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run 222 - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`) 223 224 Calling sequence of `rf`: 225 + ts - the integrator 226 . t - the time 227 . U - the solution 228 . F - the computed value of the function 229 - ctx - the user context 230 231 Calling sequence of `drduf`: 232 + ts - the integrator 233 . t - the time 234 . U - the solution 235 . dRdU - the computed gradients of the r with respect to u 236 - ctx - the user context 237 238 Calling sequence of `drdpf`: 239 + ts - the integrator 240 . t - the time 241 . U - the solution 242 . dRdP - the computed gradients of the r with respect to p 243 - ctx - the user context 244 245 Level: deprecated 246 247 Notes: 248 For optimization there is usually a single cost function (numcost = 1). For sensitivities there may be multiple cost functions 249 250 Use `TSCreateQuadratureTS()` and `TSForwardSetSensitivities()` instead 251 252 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobianP()`, `TSGetCostGradients()`, `TSSetCostGradients()`, 253 `TSCreateQuadratureTS()`, `TSForwardSetSensitivities()` 254 @*/ 255 PetscErrorCode TSSetCostIntegrand(TS ts, PetscInt numcost, Vec costintegral, PetscErrorCode (*rf)(TS ts, PetscReal t, Vec U, Vec F, void *ctx), PetscErrorCode (*drduf)(TS ts, PetscReal t, Vec U, Vec *dRdU, void *ctx), PetscErrorCode (*drdpf)(TS ts, PetscReal t, Vec U, Vec *dRdP, void *ctx), PetscBool fwd, void *ctx) 256 { 257 PetscFunctionBegin; 258 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 259 if (costintegral) PetscValidHeaderSpecific(costintegral, VEC_CLASSID, 3); 260 PetscCheck(!ts->numcost || ts->numcost == numcost, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostGradients() or TSForwardSetIntegralGradients()"); 261 if (!ts->numcost) ts->numcost = numcost; 262 263 if (costintegral) { 264 PetscCall(PetscObjectReference((PetscObject)costintegral)); 265 PetscCall(VecDestroy(&ts->vec_costintegral)); 266 ts->vec_costintegral = costintegral; 267 } else { 268 if (!ts->vec_costintegral) { /* Create a seq vec if user does not provide one */ 269 PetscCall(VecCreateSeq(PETSC_COMM_SELF, numcost, &ts->vec_costintegral)); 270 } else { 271 PetscCall(VecSet(ts->vec_costintegral, 0.0)); 272 } 273 } 274 if (!ts->vec_costintegrand) { 275 PetscCall(VecDuplicate(ts->vec_costintegral, &ts->vec_costintegrand)); 276 } else { 277 PetscCall(VecSet(ts->vec_costintegrand, 0.0)); 278 } 279 ts->costintegralfwd = fwd; /* Evaluate the cost integral in forward run if fwd is true */ 280 ts->costintegrand = rf; 281 ts->costintegrandctx = ctx; 282 ts->drdufunction = drduf; 283 ts->drdpfunction = drdpf; 284 PetscFunctionReturn(PETSC_SUCCESS); 285 } 286 287 /*@ 288 TSGetCostIntegral - Returns the values of the integral term in the cost functions. 289 It is valid to call the routine after a backward run. 290 291 Not Collective 292 293 Input Parameter: 294 . ts - the `TS` context obtained from `TSCreate()` 295 296 Output Parameter: 297 . v - the vector containing the integrals for each cost function 298 299 Level: intermediate 300 301 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSSetCostIntegrand()` 302 @*/ 303 PetscErrorCode TSGetCostIntegral(TS ts, Vec *v) 304 { 305 TS quadts; 306 307 PetscFunctionBegin; 308 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 309 PetscAssertPointer(v, 2); 310 PetscCall(TSGetQuadratureTS(ts, NULL, &quadts)); 311 *v = quadts->vec_sol; 312 PetscFunctionReturn(PETSC_SUCCESS); 313 } 314 315 /*@ 316 TSComputeCostIntegrand - Evaluates the integral function in the cost functions. 317 318 Input Parameters: 319 + ts - the `TS` context 320 . t - current time 321 - U - state vector, i.e. current solution 322 323 Output Parameter: 324 . Q - vector of size numcost to hold the outputs 325 326 Level: deprecated 327 328 Note: 329 Most users should not need to explicitly call this routine, as it 330 is used internally within the sensitivity analysis context. 331 332 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSSetCostIntegrand()` 333 @*/ 334 PetscErrorCode TSComputeCostIntegrand(TS ts, PetscReal t, Vec U, Vec Q) 335 { 336 PetscFunctionBegin; 337 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 338 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 339 PetscValidHeaderSpecific(Q, VEC_CLASSID, 4); 340 341 PetscCall(PetscLogEventBegin(TS_FunctionEval, ts, U, Q, 0)); 342 if (ts->costintegrand) PetscCallBack("TS callback integrand in the cost function", (*ts->costintegrand)(ts, t, U, Q, ts->costintegrandctx)); 343 else PetscCall(VecZeroEntries(Q)); 344 PetscCall(PetscLogEventEnd(TS_FunctionEval, ts, U, Q, 0)); 345 PetscFunctionReturn(PETSC_SUCCESS); 346 } 347 348 // PetscClangLinter pragma disable: -fdoc-* 349 /*@ 350 TSComputeDRDUFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobian()` 351 352 Level: deprecated 353 354 @*/ 355 PetscErrorCode TSComputeDRDUFunction(TS ts, PetscReal t, Vec U, Vec *DRDU) 356 { 357 PetscFunctionBegin; 358 if (!DRDU) PetscFunctionReturn(PETSC_SUCCESS); 359 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 360 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 361 362 PetscCallBack("TS callback DRDU for sensitivity analysis", (*ts->drdufunction)(ts, t, U, DRDU, ts->costintegrandctx)); 363 PetscFunctionReturn(PETSC_SUCCESS); 364 } 365 366 // PetscClangLinter pragma disable: -fdoc-* 367 /*@ 368 TSComputeDRDPFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobianP()` 369 370 Level: deprecated 371 372 @*/ 373 PetscErrorCode TSComputeDRDPFunction(TS ts, PetscReal t, Vec U, Vec *DRDP) 374 { 375 PetscFunctionBegin; 376 if (!DRDP) PetscFunctionReturn(PETSC_SUCCESS); 377 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 378 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 379 380 PetscCallBack("TS callback DRDP for sensitivity analysis", (*ts->drdpfunction)(ts, t, U, DRDP, ts->costintegrandctx)); 381 PetscFunctionReturn(PETSC_SUCCESS); 382 } 383 384 // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation 385 // PetscClangLinter pragma disable: -fdoc-section-header-unknown 386 /*@C 387 TSSetIHessianProduct - Sets the function that computes the vector-Hessian-vector product. The Hessian is the second-order derivative of F (IFunction) w.r.t. the state variable. 388 389 Logically Collective 390 391 Input Parameters: 392 + ts - `TS` context obtained from `TSCreate()` 393 . ihp1 - an array of vectors storing the result of vector-Hessian-vector product for F_UU 394 . hessianproductfunc1 - vector-Hessian-vector product function for F_UU 395 . ihp2 - an array of vectors storing the result of vector-Hessian-vector product for F_UP 396 . hessianproductfunc2 - vector-Hessian-vector product function for F_UP 397 . ihp3 - an array of vectors storing the result of vector-Hessian-vector product for F_PU 398 . hessianproductfunc3 - vector-Hessian-vector product function for F_PU 399 . ihp4 - an array of vectors storing the result of vector-Hessian-vector product for F_PP 400 - hessianproductfunc4 - vector-Hessian-vector product function for F_PP 401 402 Calling sequence of `ihessianproductfunc1`: 403 + ts - the `TS` context 404 + t - current timestep 405 . U - input vector (current ODE solution) 406 . Vl - an array of input vectors to be left-multiplied with the Hessian 407 . Vr - input vector to be right-multiplied with the Hessian 408 . VHV - an array of output vectors for vector-Hessian-vector product 409 - ctx - [optional] user-defined function context 410 411 Level: intermediate 412 413 Notes: 414 All other functions have the same calling sequence as `rhhessianproductfunc1`, so their 415 descriptions are omitted for brevity. 416 417 The first Hessian function and the working array are required. 418 As an example to implement the callback functions, the second callback function calculates the vector-Hessian-vector product 419 $ Vl_n^T*F_UP*Vr 420 where the vector Vl_n (n-th element in the array Vl) and Vr are of size N and M respectively, and the Hessian F_UP is of size N x N x M. 421 Each entry of F_UP corresponds to the derivative 422 $ F_UP[i][j][k] = \frac{\partial^2 F[i]}{\partial U[j] \partial P[k]}. 423 The result of the vector-Hessian-vector product for Vl_n needs to be stored in vector VHV_n with the j-th entry being 424 $ VHV_n[j] = \sum_i \sum_k {Vl_n[i] * F_UP[i][j][k] * Vr[k]} 425 If the cost function is a scalar, there will be only one vector in Vl and VHV. 426 427 .seealso: [](ch_ts), `TS` 428 @*/ 429 PetscErrorCode TSSetIHessianProduct(TS ts, Vec *ihp1, PetscErrorCode (*ihessianproductfunc1)(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV, void *ctx), Vec *ihp2, PetscErrorCode (*ihessianproductfunc2)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *ihp3, PetscErrorCode (*ihessianproductfunc3)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *ihp4, PetscErrorCode (*ihessianproductfunc4)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), void *ctx) 430 { 431 PetscFunctionBegin; 432 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 433 PetscAssertPointer(ihp1, 2); 434 435 ts->ihessianproductctx = ctx; 436 if (ihp1) ts->vecs_fuu = ihp1; 437 if (ihp2) ts->vecs_fup = ihp2; 438 if (ihp3) ts->vecs_fpu = ihp3; 439 if (ihp4) ts->vecs_fpp = ihp4; 440 ts->ihessianproduct_fuu = ihessianproductfunc1; 441 ts->ihessianproduct_fup = ihessianproductfunc2; 442 ts->ihessianproduct_fpu = ihessianproductfunc3; 443 ts->ihessianproduct_fpp = ihessianproductfunc4; 444 PetscFunctionReturn(PETSC_SUCCESS); 445 } 446 447 /*@ 448 TSComputeIHessianProductFunctionUU - Runs the user-defined vector-Hessian-vector product function for Fuu. 449 450 Collective 451 452 Input Parameters: 453 + ts - The `TS` context obtained from `TSCreate()` 454 . t - the time 455 . U - the solution at which to compute the Hessian product 456 . Vl - the array of input vectors to be multiplied with the Hessian from the left 457 - Vr - the input vector to be multiplied with the Hessian from the right 458 459 Output Parameter: 460 . VHV - the array of output vectors that store the Hessian product 461 462 Level: developer 463 464 Note: 465 `TSComputeIHessianProductFunctionUU()` is typically used for sensitivity implementation, 466 so most users would not generally call this routine themselves. 467 468 .seealso: [](ch_ts), `TSSetIHessianProduct()` 469 @*/ 470 PetscErrorCode TSComputeIHessianProductFunctionUU(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 471 { 472 PetscFunctionBegin; 473 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 474 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 475 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 476 477 if (ts->ihessianproduct_fuu) PetscCallBack("TS callback IHessianProduct 1 for sensitivity analysis", (*ts->ihessianproduct_fuu)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx)); 478 479 /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */ 480 if (ts->rhshessianproduct_guu) { 481 PetscInt nadj; 482 PetscCall(TSComputeRHSHessianProductFunctionUU(ts, t, U, Vl, Vr, VHV)); 483 for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1)); 484 } 485 PetscFunctionReturn(PETSC_SUCCESS); 486 } 487 488 /*@ 489 TSComputeIHessianProductFunctionUP - Runs the user-defined vector-Hessian-vector product function for Fup. 490 491 Collective 492 493 Input Parameters: 494 + ts - The `TS` context obtained from `TSCreate()` 495 . t - the time 496 . U - the solution at which to compute the Hessian product 497 . Vl - the array of input vectors to be multiplied with the Hessian from the left 498 - Vr - the input vector to be multiplied with the Hessian from the right 499 500 Output Parameter: 501 . VHV - the array of output vectors that store the Hessian product 502 503 Level: developer 504 505 Note: 506 `TSComputeIHessianProductFunctionUP()` is typically used for sensitivity implementation, 507 so most users would not generally call this routine themselves. 508 509 .seealso: [](ch_ts), `TSSetIHessianProduct()` 510 @*/ 511 PetscErrorCode TSComputeIHessianProductFunctionUP(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 512 { 513 PetscFunctionBegin; 514 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 515 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 516 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 517 518 if (ts->ihessianproduct_fup) PetscCallBack("TS callback IHessianProduct 2 for sensitivity analysis", (*ts->ihessianproduct_fup)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx)); 519 520 /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */ 521 if (ts->rhshessianproduct_gup) { 522 PetscInt nadj; 523 PetscCall(TSComputeRHSHessianProductFunctionUP(ts, t, U, Vl, Vr, VHV)); 524 for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1)); 525 } 526 PetscFunctionReturn(PETSC_SUCCESS); 527 } 528 529 /*@ 530 TSComputeIHessianProductFunctionPU - Runs the user-defined vector-Hessian-vector product function for Fpu. 531 532 Collective 533 534 Input Parameters: 535 + ts - The `TS` context obtained from `TSCreate()` 536 . t - the time 537 . U - the solution at which to compute the Hessian product 538 . Vl - the array of input vectors to be multiplied with the Hessian from the left 539 - Vr - the input vector to be multiplied with the Hessian from the right 540 541 Output Parameter: 542 . VHV - the array of output vectors that store the Hessian product 543 544 Level: developer 545 546 Note: 547 `TSComputeIHessianProductFunctionPU()` is typically used for sensitivity implementation, 548 so most users would not generally call this routine themselves. 549 550 .seealso: [](ch_ts), `TSSetIHessianProduct()` 551 @*/ 552 PetscErrorCode TSComputeIHessianProductFunctionPU(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 553 { 554 PetscFunctionBegin; 555 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 556 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 557 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 558 559 if (ts->ihessianproduct_fpu) PetscCallBack("TS callback IHessianProduct 3 for sensitivity analysis", (*ts->ihessianproduct_fpu)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx)); 560 561 /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */ 562 if (ts->rhshessianproduct_gpu) { 563 PetscInt nadj; 564 PetscCall(TSComputeRHSHessianProductFunctionPU(ts, t, U, Vl, Vr, VHV)); 565 for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1)); 566 } 567 PetscFunctionReturn(PETSC_SUCCESS); 568 } 569 570 /*@C 571 TSComputeIHessianProductFunctionPP - Runs the user-defined vector-Hessian-vector product function for Fpp. 572 573 Collective 574 575 Input Parameters: 576 + ts - The `TS` context obtained from `TSCreate()` 577 . t - the time 578 . U - the solution at which to compute the Hessian product 579 . Vl - the array of input vectors to be multiplied with the Hessian from the left 580 - Vr - the input vector to be multiplied with the Hessian from the right 581 582 Output Parameter: 583 . VHV - the array of output vectors that store the Hessian product 584 585 Level: developer 586 587 Note: 588 `TSComputeIHessianProductFunctionPP()` is typically used for sensitivity implementation, 589 so most users would not generally call this routine themselves. 590 591 .seealso: [](ch_ts), `TSSetIHessianProduct()` 592 @*/ 593 PetscErrorCode TSComputeIHessianProductFunctionPP(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 594 { 595 PetscFunctionBegin; 596 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 597 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 598 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 599 600 if (ts->ihessianproduct_fpp) PetscCallBack("TS callback IHessianProduct 3 for sensitivity analysis", (*ts->ihessianproduct_fpp)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx)); 601 602 /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */ 603 if (ts->rhshessianproduct_gpp) { 604 PetscInt nadj; 605 PetscCall(TSComputeRHSHessianProductFunctionPP(ts, t, U, Vl, Vr, VHV)); 606 for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1)); 607 } 608 PetscFunctionReturn(PETSC_SUCCESS); 609 } 610 611 // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation 612 // PetscClangLinter pragma disable: -fdoc-section-header-unknown 613 /*@C 614 TSSetRHSHessianProduct - Sets the function that computes the vector-Hessian-vector 615 product. The Hessian is the second-order derivative of G (RHSFunction) w.r.t. the state 616 variable. 617 618 Logically Collective 619 620 Input Parameters: 621 + ts - `TS` context obtained from `TSCreate()` 622 . rhshp1 - an array of vectors storing the result of vector-Hessian-vector product for G_UU 623 . hessianproductfunc1 - vector-Hessian-vector product function for G_UU 624 . rhshp2 - an array of vectors storing the result of vector-Hessian-vector product for G_UP 625 . hessianproductfunc2 - vector-Hessian-vector product function for G_UP 626 . rhshp3 - an array of vectors storing the result of vector-Hessian-vector product for G_PU 627 . hessianproductfunc3 - vector-Hessian-vector product function for G_PU 628 . rhshp4 - an array of vectors storing the result of vector-Hessian-vector product for G_PP 629 . hessianproductfunc4 - vector-Hessian-vector product function for G_PP 630 - ctx - [optional] user-defined function context 631 632 Calling sequence of `rhshessianproductfunc1`: 633 + ts - the `TS` context 634 . t - current timestep 635 . U - input vector (current ODE solution) 636 . Vl - an array of input vectors to be left-multiplied with the Hessian 637 . Vr - input vector to be right-multiplied with the Hessian 638 . VHV - an array of output vectors for vector-Hessian-vector product 639 - ctx - [optional] user-defined function context 640 641 Level: intermediate 642 643 Notes: 644 All other functions have the same calling sequence as `rhhessianproductfunc1`, so their 645 descriptions are omitted for brevity. 646 647 The first Hessian function and the working array are required. 648 649 As an example to implement the callback functions, the second callback function calculates the vector-Hessian-vector product 650 $ Vl_n^T*G_UP*Vr 651 where the vector Vl_n (n-th element in the array Vl) and Vr are of size N and M respectively, and the Hessian G_UP is of size N x N x M. 652 Each entry of G_UP corresponds to the derivative 653 $ G_UP[i][j][k] = \frac{\partial^2 G[i]}{\partial U[j] \partial P[k]}. 654 The result of the vector-Hessian-vector product for Vl_n needs to be stored in vector VHV_n with j-th entry being 655 $ VHV_n[j] = \sum_i \sum_k {Vl_n[i] * G_UP[i][j][k] * Vr[k]} 656 If the cost function is a scalar, there will be only one vector in Vl and VHV. 657 658 .seealso: `TS`, `TSAdjoint` 659 @*/ 660 PetscErrorCode TSSetRHSHessianProduct(TS ts, Vec *rhshp1, PetscErrorCode (*rhshessianproductfunc1)(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV, void *ctx), Vec *rhshp2, PetscErrorCode (*rhshessianproductfunc2)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *rhshp3, PetscErrorCode (*rhshessianproductfunc3)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *rhshp4, PetscErrorCode (*rhshessianproductfunc4)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), void *ctx) 661 { 662 PetscFunctionBegin; 663 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 664 PetscAssertPointer(rhshp1, 2); 665 666 ts->rhshessianproductctx = ctx; 667 if (rhshp1) ts->vecs_guu = rhshp1; 668 if (rhshp2) ts->vecs_gup = rhshp2; 669 if (rhshp3) ts->vecs_gpu = rhshp3; 670 if (rhshp4) ts->vecs_gpp = rhshp4; 671 ts->rhshessianproduct_guu = rhshessianproductfunc1; 672 ts->rhshessianproduct_gup = rhshessianproductfunc2; 673 ts->rhshessianproduct_gpu = rhshessianproductfunc3; 674 ts->rhshessianproduct_gpp = rhshessianproductfunc4; 675 PetscFunctionReturn(PETSC_SUCCESS); 676 } 677 678 /*@ 679 TSComputeRHSHessianProductFunctionUU - Runs the user-defined vector-Hessian-vector product function for Guu. 680 681 Collective 682 683 Input Parameters: 684 + ts - The `TS` context obtained from `TSCreate()` 685 . t - the time 686 . U - the solution at which to compute the Hessian product 687 . Vl - the array of input vectors to be multiplied with the Hessian from the left 688 - Vr - the input vector to be multiplied with the Hessian from the right 689 690 Output Parameter: 691 . VHV - the array of output vectors that store the Hessian product 692 693 Level: developer 694 695 Note: 696 `TSComputeRHSHessianProductFunctionUU()` is typically used for sensitivity implementation, 697 so most users would not generally call this routine themselves. 698 699 .seealso: [](ch_ts), `TS`, `TSSetRHSHessianProduct()` 700 @*/ 701 PetscErrorCode TSComputeRHSHessianProductFunctionUU(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 702 { 703 PetscFunctionBegin; 704 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 705 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 706 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 707 708 PetscCallBack("TS callback RHSHessianProduct 1 for sensitivity analysis", (*ts->rhshessianproduct_guu)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx)); 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711 712 /*@ 713 TSComputeRHSHessianProductFunctionUP - Runs the user-defined vector-Hessian-vector product function for Gup. 714 715 Collective 716 717 Input Parameters: 718 + ts - The `TS` context obtained from `TSCreate()` 719 . t - the time 720 . U - the solution at which to compute the Hessian product 721 . Vl - the array of input vectors to be multiplied with the Hessian from the left 722 - Vr - the input vector to be multiplied with the Hessian from the right 723 724 Output Parameter: 725 . VHV - the array of output vectors that store the Hessian product 726 727 Level: developer 728 729 Note: 730 `TSComputeRHSHessianProductFunctionUP()` is typically used for sensitivity implementation, 731 so most users would not generally call this routine themselves. 732 733 .seealso: [](ch_ts), `TS`, `TSSetRHSHessianProduct()` 734 @*/ 735 PetscErrorCode TSComputeRHSHessianProductFunctionUP(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 736 { 737 PetscFunctionBegin; 738 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 739 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 740 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 741 742 PetscCallBack("TS callback RHSHessianProduct 2 for sensitivity analysis", (*ts->rhshessianproduct_gup)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx)); 743 PetscFunctionReturn(PETSC_SUCCESS); 744 } 745 746 /*@ 747 TSComputeRHSHessianProductFunctionPU - Runs the user-defined vector-Hessian-vector product function for Gpu. 748 749 Collective 750 751 Input Parameters: 752 + ts - The `TS` context obtained from `TSCreate()` 753 . t - the time 754 . U - the solution at which to compute the Hessian product 755 . Vl - the array of input vectors to be multiplied with the Hessian from the left 756 - Vr - the input vector to be multiplied with the Hessian from the right 757 758 Output Parameter: 759 . VHV - the array of output vectors that store the Hessian product 760 761 Level: developer 762 763 Note: 764 `TSComputeRHSHessianProductFunctionPU()` is typically used for sensitivity implementation, 765 so most users would not generally call this routine themselves. 766 767 .seealso: [](ch_ts), `TSSetRHSHessianProduct()` 768 @*/ 769 PetscErrorCode TSComputeRHSHessianProductFunctionPU(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 770 { 771 PetscFunctionBegin; 772 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 773 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 774 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 775 776 PetscCallBack("TS callback RHSHessianProduct 3 for sensitivity analysis", (*ts->rhshessianproduct_gpu)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx)); 777 PetscFunctionReturn(PETSC_SUCCESS); 778 } 779 780 /*@ 781 TSComputeRHSHessianProductFunctionPP - Runs the user-defined vector-Hessian-vector product function for Gpp. 782 783 Collective 784 785 Input Parameters: 786 + ts - The `TS` context obtained from `TSCreate()` 787 . t - the time 788 . U - the solution at which to compute the Hessian product 789 . Vl - the array of input vectors to be multiplied with the Hessian from the left 790 - Vr - the input vector to be multiplied with the Hessian from the right 791 792 Output Parameter: 793 . VHV - the array of output vectors that store the Hessian product 794 795 Level: developer 796 797 Note: 798 `TSComputeRHSHessianProductFunctionPP()` is typically used for sensitivity implementation, 799 so most users would not generally call this routine themselves. 800 801 .seealso: [](ch_ts), `TSSetRHSHessianProduct()` 802 @*/ 803 PetscErrorCode TSComputeRHSHessianProductFunctionPP(TS ts, PetscReal t, Vec U, Vec Vl[], Vec Vr, Vec VHV[]) 804 { 805 PetscFunctionBegin; 806 if (!VHV) PetscFunctionReturn(PETSC_SUCCESS); 807 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 808 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 809 810 PetscCallBack("TS callback RHSHessianProduct 3 for sensitivity analysis", (*ts->rhshessianproduct_gpp)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx)); 811 PetscFunctionReturn(PETSC_SUCCESS); 812 } 813 814 /* --------------------------- Adjoint sensitivity ---------------------------*/ 815 816 /*@ 817 TSSetCostGradients - Sets the initial value of the gradients of the cost function w.r.t. initial values and w.r.t. the problem parameters 818 for use by the `TS` adjoint routines. 819 820 Logically Collective 821 822 Input Parameters: 823 + ts - the `TS` context obtained from `TSCreate()` 824 . numcost - number of gradients to be computed, this is the number of cost functions 825 . lambda - gradients with respect to the initial condition variables, the dimension and parallel layout of these vectors is the same as the ODE solution vector 826 - mu - gradients with respect to the parameters, the number of entries in these vectors is the same as the number of parameters 827 828 Level: beginner 829 830 Notes: 831 the entries in these vectors must be correctly initialized with the values lambda_i = df/dy|finaltime mu_i = df/dp|finaltime 832 833 After `TSAdjointSolve()` is called the lambda and the mu contain the computed sensitivities 834 835 .seealso: `TS`, `TSAdjointSolve()`, `TSGetCostGradients()` 836 @*/ 837 PetscErrorCode TSSetCostGradients(TS ts, PetscInt numcost, Vec *lambda, Vec *mu) 838 { 839 PetscFunctionBegin; 840 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 841 PetscAssertPointer(lambda, 3); 842 ts->vecs_sensi = lambda; 843 ts->vecs_sensip = mu; 844 PetscCheck(!ts->numcost || ts->numcost == numcost, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand"); 845 ts->numcost = numcost; 846 PetscFunctionReturn(PETSC_SUCCESS); 847 } 848 849 /*@ 850 TSGetCostGradients - Returns the gradients from the `TSAdjointSolve()` 851 852 Not Collective, but the vectors returned are parallel if `TS` is parallel 853 854 Input Parameter: 855 . ts - the `TS` context obtained from `TSCreate()` 856 857 Output Parameters: 858 + numcost - size of returned arrays 859 . lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables 860 - mu - vectors containing the gradients of the cost functions with respect to the problem parameters 861 862 Level: intermediate 863 864 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSSetCostGradients()` 865 @*/ 866 PetscErrorCode TSGetCostGradients(TS ts, PetscInt *numcost, Vec **lambda, Vec **mu) 867 { 868 PetscFunctionBegin; 869 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 870 if (numcost) *numcost = ts->numcost; 871 if (lambda) *lambda = ts->vecs_sensi; 872 if (mu) *mu = ts->vecs_sensip; 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 /*@ 877 TSSetCostHessianProducts - Sets the initial value of the Hessian-vector products of the cost function w.r.t. initial values and w.r.t. the problem parameters 878 for use by the `TS` adjoint routines. 879 880 Logically Collective 881 882 Input Parameters: 883 + ts - the `TS` context obtained from `TSCreate()` 884 . numcost - number of cost functions 885 . lambda2 - Hessian-vector product with respect to the initial condition variables, the dimension and parallel layout of these vectors is the same as the ODE solution vector 886 . mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters 887 - dir - the direction vector that are multiplied with the Hessian of the cost functions 888 889 Level: beginner 890 891 Notes: 892 Hessian of the cost function is completely different from Hessian of the ODE/DAE system 893 894 For second-order adjoint, one needs to call this function and then `TSAdjointSetForward()` before `TSSolve()`. 895 896 After `TSAdjointSolve()` is called, the lambda2 and the mu2 will contain the computed second-order adjoint sensitivities, and can be used to produce Hessian-vector product (not the full Hessian matrix). Users must provide a direction vector; it is usually generated by an optimization solver. 897 898 Passing `NULL` for `lambda2` disables the second-order calculation. 899 900 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSAdjointSetForward()` 901 @*/ 902 PetscErrorCode TSSetCostHessianProducts(TS ts, PetscInt numcost, Vec *lambda2, Vec *mu2, Vec dir) 903 { 904 PetscFunctionBegin; 905 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 906 PetscCheck(!ts->numcost || ts->numcost == numcost, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand"); 907 ts->numcost = numcost; 908 ts->vecs_sensi2 = lambda2; 909 ts->vecs_sensi2p = mu2; 910 ts->vec_dir = dir; 911 PetscFunctionReturn(PETSC_SUCCESS); 912 } 913 914 /*@ 915 TSGetCostHessianProducts - Returns the gradients from the `TSAdjointSolve()` 916 917 Not Collective, but vectors returned are parallel if `TS` is parallel 918 919 Input Parameter: 920 . ts - the `TS` context obtained from `TSCreate()` 921 922 Output Parameters: 923 + numcost - number of cost functions 924 . lambda2 - Hessian-vector product with respect to the initial condition variables, the dimension and parallel layout of these vectors is the same as the ODE solution vector 925 . mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters 926 - dir - the direction vector that are multiplied with the Hessian of the cost functions 927 928 Level: intermediate 929 930 .seealso: [](ch_ts), `TSAdjointSolve()`, `TSSetCostHessianProducts()` 931 @*/ 932 PetscErrorCode TSGetCostHessianProducts(TS ts, PetscInt *numcost, Vec **lambda2, Vec **mu2, Vec *dir) 933 { 934 PetscFunctionBegin; 935 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 936 if (numcost) *numcost = ts->numcost; 937 if (lambda2) *lambda2 = ts->vecs_sensi2; 938 if (mu2) *mu2 = ts->vecs_sensi2p; 939 if (dir) *dir = ts->vec_dir; 940 PetscFunctionReturn(PETSC_SUCCESS); 941 } 942 943 /*@ 944 TSAdjointSetForward - Trigger the tangent linear solver and initialize the forward sensitivities 945 946 Logically Collective 947 948 Input Parameters: 949 + ts - the `TS` context obtained from `TSCreate()` 950 - didp - the derivative of initial values w.r.t. parameters 951 952 Level: intermediate 953 954 Notes: 955 When computing sensitivities w.r.t. initial condition, set didp to `NULL` so that the solver will take it as an identity matrix mathematically. 956 `TSAdjoint` does not reset the tangent linear solver automatically, `TSAdjointResetForward()` should be called to reset the tangent linear solver. 957 958 .seealso: [](ch_ts), `TSAdjointSolve()`, `TSSetCostHessianProducts()`, `TSAdjointResetForward()` 959 @*/ 960 PetscErrorCode TSAdjointSetForward(TS ts, Mat didp) 961 { 962 Mat A; 963 Vec sp; 964 PetscScalar *xarr; 965 PetscInt lsize; 966 967 PetscFunctionBegin; 968 ts->forward_solve = PETSC_TRUE; /* turn on tangent linear mode */ 969 PetscCheck(ts->vecs_sensi2, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetCostHessianProducts() first"); 970 PetscCheck(ts->vec_dir, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Directional vector is missing. Call TSSetCostHessianProducts() to set it."); 971 /* create a single-column dense matrix */ 972 PetscCall(VecGetLocalSize(ts->vec_sol, &lsize)); 973 PetscCall(MatCreateDense(PetscObjectComm((PetscObject)ts), lsize, PETSC_DECIDE, PETSC_DECIDE, 1, NULL, &A)); 974 975 PetscCall(VecDuplicate(ts->vec_sol, &sp)); 976 PetscCall(MatDenseGetColumn(A, 0, &xarr)); 977 PetscCall(VecPlaceArray(sp, xarr)); 978 if (ts->vecs_sensi2p) { /* tangent linear variable initialized as 2*dIdP*dir */ 979 if (didp) { 980 PetscCall(MatMult(didp, ts->vec_dir, sp)); 981 PetscCall(VecScale(sp, 2.)); 982 } else { 983 PetscCall(VecZeroEntries(sp)); 984 } 985 } else { /* tangent linear variable initialized as dir */ 986 PetscCall(VecCopy(ts->vec_dir, sp)); 987 } 988 PetscCall(VecResetArray(sp)); 989 PetscCall(MatDenseRestoreColumn(A, &xarr)); 990 PetscCall(VecDestroy(&sp)); 991 992 PetscCall(TSForwardSetInitialSensitivities(ts, A)); /* if didp is NULL, identity matrix is assumed */ 993 994 PetscCall(MatDestroy(&A)); 995 PetscFunctionReturn(PETSC_SUCCESS); 996 } 997 998 /*@ 999 TSAdjointResetForward - Reset the tangent linear solver and destroy the tangent linear context 1000 1001 Logically Collective 1002 1003 Input Parameter: 1004 . ts - the `TS` context obtained from `TSCreate()` 1005 1006 Level: intermediate 1007 1008 .seealso: [](ch_ts), `TSAdjointSetForward()` 1009 @*/ 1010 PetscErrorCode TSAdjointResetForward(TS ts) 1011 { 1012 PetscFunctionBegin; 1013 ts->forward_solve = PETSC_FALSE; /* turn off tangent linear mode */ 1014 PetscCall(TSForwardReset(ts)); 1015 PetscFunctionReturn(PETSC_SUCCESS); 1016 } 1017 1018 /*@ 1019 TSAdjointSetUp - Sets up the internal data structures for the later use 1020 of an adjoint solver 1021 1022 Collective 1023 1024 Input Parameter: 1025 . ts - the `TS` context obtained from `TSCreate()` 1026 1027 Level: advanced 1028 1029 .seealso: [](ch_ts), `TSCreate()`, `TSAdjointStep()`, `TSSetCostGradients()` 1030 @*/ 1031 PetscErrorCode TSAdjointSetUp(TS ts) 1032 { 1033 TSTrajectory tj; 1034 PetscBool match; 1035 1036 PetscFunctionBegin; 1037 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1038 if (ts->adjointsetupcalled) PetscFunctionReturn(PETSC_SUCCESS); 1039 PetscCheck(ts->vecs_sensi, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetCostGradients() first"); 1040 PetscCheck(!ts->vecs_sensip || ts->Jacp || ts->Jacprhs, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetRHSJacobianP() or TSSetIJacobianP() first"); 1041 PetscCall(TSGetTrajectory(ts, &tj)); 1042 PetscCall(PetscObjectTypeCompare((PetscObject)tj, TSTRAJECTORYBASIC, &match)); 1043 if (match) { 1044 PetscBool solution_only; 1045 PetscCall(TSTrajectoryGetSolutionOnly(tj, &solution_only)); 1046 PetscCheck(!solution_only, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "TSAdjoint cannot use the solution-only mode when choosing the Basic TSTrajectory type. Turn it off with -ts_trajectory_solution_only 0"); 1047 } 1048 PetscCall(TSTrajectorySetUseHistory(tj, PETSC_FALSE)); /* not use TSHistory */ 1049 1050 if (ts->quadraturets) { /* if there is integral in the cost function */ 1051 PetscCall(VecDuplicate(ts->vecs_sensi[0], &ts->vec_drdu_col)); 1052 if (ts->vecs_sensip) PetscCall(VecDuplicate(ts->vecs_sensip[0], &ts->vec_drdp_col)); 1053 } 1054 1055 PetscTryTypeMethod(ts, adjointsetup); 1056 ts->adjointsetupcalled = PETSC_TRUE; 1057 PetscFunctionReturn(PETSC_SUCCESS); 1058 } 1059 1060 /*@ 1061 TSAdjointReset - Resets a `TS` adjoint context and removes any allocated `Vec`s and `Mat`s. 1062 1063 Collective 1064 1065 Input Parameter: 1066 . ts - the `TS` context obtained from `TSCreate()` 1067 1068 Level: beginner 1069 1070 .seealso: [](ch_ts), `TSCreate()`, `TSAdjointSetUp()`, `TSADestroy()` 1071 @*/ 1072 PetscErrorCode TSAdjointReset(TS ts) 1073 { 1074 PetscFunctionBegin; 1075 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1076 PetscTryTypeMethod(ts, adjointreset); 1077 if (ts->quadraturets) { /* if there is integral in the cost function */ 1078 PetscCall(VecDestroy(&ts->vec_drdu_col)); 1079 if (ts->vecs_sensip) PetscCall(VecDestroy(&ts->vec_drdp_col)); 1080 } 1081 ts->vecs_sensi = NULL; 1082 ts->vecs_sensip = NULL; 1083 ts->vecs_sensi2 = NULL; 1084 ts->vecs_sensi2p = NULL; 1085 ts->vec_dir = NULL; 1086 ts->adjointsetupcalled = PETSC_FALSE; 1087 PetscFunctionReturn(PETSC_SUCCESS); 1088 } 1089 1090 /*@ 1091 TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time 1092 1093 Logically Collective 1094 1095 Input Parameters: 1096 + ts - the `TS` context obtained from `TSCreate()` 1097 - steps - number of steps to use 1098 1099 Level: intermediate 1100 1101 Notes: 1102 Normally one does not call this and `TSAdjointSolve()` integrates back to the original timestep. One can call this 1103 so as to integrate back to less than the original timestep 1104 1105 .seealso: [](ch_ts), `TSAdjointSolve()`, `TS`, `TSSetExactFinalTime()` 1106 @*/ 1107 PetscErrorCode TSAdjointSetSteps(TS ts, PetscInt steps) 1108 { 1109 PetscFunctionBegin; 1110 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1111 PetscValidLogicalCollectiveInt(ts, steps, 2); 1112 PetscCheck(steps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Cannot step back a negative number of steps"); 1113 PetscCheck(steps <= ts->steps, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Cannot step back more than the total number of forward steps"); 1114 ts->adjoint_max_steps = steps; 1115 PetscFunctionReturn(PETSC_SUCCESS); 1116 } 1117 1118 // PetscClangLinter pragma disable: -fdoc-* 1119 /*@C 1120 TSAdjointSetRHSJacobian - Deprecated, use `TSSetRHSJacobianP()` 1121 1122 Level: deprecated 1123 @*/ 1124 PetscErrorCode TSAdjointSetRHSJacobian(TS ts, Mat Amat, PetscErrorCode (*func)(TS, PetscReal, Vec, Mat, void *), void *ctx) 1125 { 1126 PetscFunctionBegin; 1127 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1128 PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2); 1129 1130 ts->rhsjacobianp = func; 1131 ts->rhsjacobianpctx = ctx; 1132 if (Amat) { 1133 PetscCall(PetscObjectReference((PetscObject)Amat)); 1134 PetscCall(MatDestroy(&ts->Jacp)); 1135 ts->Jacp = Amat; 1136 } 1137 PetscFunctionReturn(PETSC_SUCCESS); 1138 } 1139 1140 // PetscClangLinter pragma disable: -fdoc-* 1141 /*@C 1142 TSAdjointComputeRHSJacobian - Deprecated, use `TSComputeRHSJacobianP()` 1143 1144 Level: deprecated 1145 @*/ 1146 PetscErrorCode TSAdjointComputeRHSJacobian(TS ts, PetscReal t, Vec U, Mat Amat) 1147 { 1148 PetscFunctionBegin; 1149 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1150 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 1151 PetscValidHeaderSpecific(Amat, MAT_CLASSID, 4); 1152 1153 PetscCallBack("TS callback JacobianP for sensitivity analysis", (*ts->rhsjacobianp)(ts, t, U, Amat, ts->rhsjacobianpctx)); 1154 PetscFunctionReturn(PETSC_SUCCESS); 1155 } 1156 1157 // PetscClangLinter pragma disable: -fdoc-* 1158 /*@ 1159 TSAdjointComputeDRDYFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobian()` 1160 1161 Level: deprecated 1162 @*/ 1163 PetscErrorCode TSAdjointComputeDRDYFunction(TS ts, PetscReal t, Vec U, Vec *DRDU) 1164 { 1165 PetscFunctionBegin; 1166 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1167 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 1168 1169 PetscCallBack("TS callback DRDY for sensitivity analysis", (*ts->drdufunction)(ts, t, U, DRDU, ts->costintegrandctx)); 1170 PetscFunctionReturn(PETSC_SUCCESS); 1171 } 1172 1173 // PetscClangLinter pragma disable: -fdoc-* 1174 /*@ 1175 TSAdjointComputeDRDPFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobianP()` 1176 1177 Level: deprecated 1178 @*/ 1179 PetscErrorCode TSAdjointComputeDRDPFunction(TS ts, PetscReal t, Vec U, Vec *DRDP) 1180 { 1181 PetscFunctionBegin; 1182 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1183 PetscValidHeaderSpecific(U, VEC_CLASSID, 3); 1184 1185 PetscCallBack("TS callback DRDP for sensitivity analysis", (*ts->drdpfunction)(ts, t, U, DRDP, ts->costintegrandctx)); 1186 PetscFunctionReturn(PETSC_SUCCESS); 1187 } 1188 1189 // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation 1190 /*@C 1191 TSAdjointMonitorSensi - monitors the first lambda sensitivity 1192 1193 Level: intermediate 1194 1195 .seealso: [](ch_ts), `TSAdjointMonitorSet()` 1196 @*/ 1197 static PetscErrorCode TSAdjointMonitorSensi(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscInt numcost, Vec *lambda, Vec *mu, PetscViewerAndFormat *vf) 1198 { 1199 PetscViewer viewer = vf->viewer; 1200 1201 PetscFunctionBegin; 1202 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8); 1203 PetscCall(PetscViewerPushFormat(viewer, vf->format)); 1204 PetscCall(VecView(lambda[0], viewer)); 1205 PetscCall(PetscViewerPopFormat(viewer)); 1206 PetscFunctionReturn(PETSC_SUCCESS); 1207 } 1208 1209 /*@C 1210 TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 1211 1212 Collective 1213 1214 Input Parameters: 1215 + ts - `TS` object you wish to monitor 1216 . name - the monitor type one is seeking 1217 . help - message indicating what monitoring is done 1218 . manual - manual page for the monitor 1219 . monitor - the monitor function, its context must be a `PetscViewerAndFormat` 1220 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `TS` or `PetscViewer` objects 1221 1222 Level: developer 1223 1224 .seealso: [](ch_ts), `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 1225 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 1226 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 1227 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 1228 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 1229 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 1230 `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscViewerAndFormat` 1231 @*/ 1232 PetscErrorCode TSAdjointMonitorSetFromOptions(TS ts, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(TS, PetscInt, PetscReal, Vec, PetscInt, Vec *, Vec *, PetscViewerAndFormat *), PetscErrorCode (*monitorsetup)(TS, PetscViewerAndFormat *)) 1233 { 1234 PetscViewer viewer; 1235 PetscViewerFormat format; 1236 PetscBool flg; 1237 1238 PetscFunctionBegin; 1239 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)ts), ((PetscObject)ts)->options, ((PetscObject)ts)->prefix, name, &viewer, &format, &flg)); 1240 if (flg) { 1241 PetscViewerAndFormat *vf; 1242 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 1243 PetscCall(PetscViewerDestroy(&viewer)); 1244 if (monitorsetup) PetscCall((*monitorsetup)(ts, vf)); 1245 PetscCall(TSAdjointMonitorSet(ts, (PetscErrorCode (*)(TS, PetscInt, PetscReal, Vec, PetscInt, Vec *, Vec *, void *))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy)); 1246 } 1247 PetscFunctionReturn(PETSC_SUCCESS); 1248 } 1249 1250 /*@C 1251 TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every 1252 timestep to display the iteration's progress. 1253 1254 Logically Collective 1255 1256 Input Parameters: 1257 + ts - the `TS` context obtained from `TSCreate()` 1258 . adjointmonitor - monitoring routine 1259 . adjointmctx - [optional] user-defined context for private data for the monitor routine 1260 (use `NULL` if no context is desired) 1261 - adjointmdestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for its calling sequence 1262 1263 Calling sequence of `adjointmonitor`: 1264 + ts - the `TS` context 1265 . steps - iteration number (after the final time step the monitor routine is called with 1266 a step of -1, this is at the final time which may have been interpolated to) 1267 . time - current time 1268 . u - current iterate 1269 . numcost - number of cost functionos 1270 . lambda - sensitivities to initial conditions 1271 . mu - sensitivities to parameters 1272 - adjointmctx - [optional] adjoint monitoring context 1273 1274 Level: intermediate 1275 1276 Note: 1277 This routine adds an additional monitor to the list of monitors that 1278 already has been loaded. 1279 1280 Fortran Notes: 1281 Only a single monitor function can be set for each `TS` object 1282 1283 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSAdjointMonitorCancel()`, `PetscCtxDestroyFn` 1284 @*/ 1285 PetscErrorCode TSAdjointMonitorSet(TS ts, PetscErrorCode (*adjointmonitor)(TS ts, PetscInt steps, PetscReal time, Vec u, PetscInt numcost, Vec *lambda, Vec *mu, void *adjointmctx), void *adjointmctx, PetscCtxDestroyFn *adjointmdestroy) 1286 { 1287 PetscInt i; 1288 PetscBool identical; 1289 1290 PetscFunctionBegin; 1291 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1292 for (i = 0; i < ts->numbermonitors; i++) { 1293 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor, adjointmctx, adjointmdestroy, (PetscErrorCode (*)(void))ts->adjointmonitor[i], ts->adjointmonitorcontext[i], ts->adjointmonitordestroy[i], &identical)); 1294 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 1295 } 1296 PetscCheck(ts->numberadjointmonitors < MAXTSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many adjoint monitors set"); 1297 ts->adjointmonitor[ts->numberadjointmonitors] = adjointmonitor; 1298 ts->adjointmonitordestroy[ts->numberadjointmonitors] = adjointmdestroy; 1299 ts->adjointmonitorcontext[ts->numberadjointmonitors++] = adjointmctx; 1300 PetscFunctionReturn(PETSC_SUCCESS); 1301 } 1302 1303 /*@C 1304 TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object. 1305 1306 Logically Collective 1307 1308 Input Parameter: 1309 . ts - the `TS` context obtained from `TSCreate()` 1310 1311 Notes: 1312 There is no way to remove a single, specific monitor. 1313 1314 Level: intermediate 1315 1316 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSAdjointMonitorSet()` 1317 @*/ 1318 PetscErrorCode TSAdjointMonitorCancel(TS ts) 1319 { 1320 PetscInt i; 1321 1322 PetscFunctionBegin; 1323 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1324 for (i = 0; i < ts->numberadjointmonitors; i++) { 1325 if (ts->adjointmonitordestroy[i]) PetscCall((*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i])); 1326 } 1327 ts->numberadjointmonitors = 0; 1328 PetscFunctionReturn(PETSC_SUCCESS); 1329 } 1330 1331 /*@C 1332 TSAdjointMonitorDefault - the default monitor of adjoint computations 1333 1334 Input Parameters: 1335 + ts - the `TS` context 1336 . step - iteration number (after the final time step the monitor routine is called with a 1337 step of -1, this is at the final time which may have been interpolated to) 1338 . time - current time 1339 . v - current iterate 1340 . numcost - number of cost functionos 1341 . lambda - sensitivities to initial conditions 1342 . mu - sensitivities to parameters 1343 - vf - the viewer and format 1344 1345 Level: intermediate 1346 1347 .seealso: [](ch_ts), `TS`, `TSAdjointSolve()`, `TSAdjointMonitorSet()` 1348 @*/ 1349 PetscErrorCode TSAdjointMonitorDefault(TS ts, PetscInt step, PetscReal time, Vec v, PetscInt numcost, Vec *lambda, Vec *mu, PetscViewerAndFormat *vf) 1350 { 1351 PetscViewer viewer = vf->viewer; 1352 1353 PetscFunctionBegin; 1354 (void)v; 1355 (void)numcost; 1356 (void)lambda; 1357 (void)mu; 1358 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8); 1359 PetscCall(PetscViewerPushFormat(viewer, vf->format)); 1360 PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel)); 1361 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " TS dt %g time %g%s", step, (double)ts->time_step, (double)time, ts->steprollback ? " (r)\n" : "\n")); 1362 PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel)); 1363 PetscCall(PetscViewerPopFormat(viewer)); 1364 PetscFunctionReturn(PETSC_SUCCESS); 1365 } 1366 1367 /*@C 1368 TSAdjointMonitorDrawSensi - Monitors progress of the adjoint `TS` solvers by calling 1369 `VecView()` for the sensitivities to initial states at each timestep 1370 1371 Collective 1372 1373 Input Parameters: 1374 + ts - the `TS` context 1375 . step - current time-step 1376 . ptime - current time 1377 . u - current state 1378 . numcost - number of cost functions 1379 . lambda - sensitivities to initial conditions 1380 . mu - sensitivities to parameters 1381 - dummy - either a viewer or `NULL` 1382 1383 Level: intermediate 1384 1385 .seealso: [](ch_ts), `TSAdjointSolve()`, `TSAdjointMonitorSet()`, `TSAdjointMonitorDefault()`, `VecView()` 1386 @*/ 1387 PetscErrorCode TSAdjointMonitorDrawSensi(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscInt numcost, Vec *lambda, Vec *mu, void *dummy) 1388 { 1389 TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy; 1390 PetscDraw draw; 1391 PetscReal xl, yl, xr, yr, h; 1392 char time[32]; 1393 1394 PetscFunctionBegin; 1395 if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(PETSC_SUCCESS); 1396 1397 PetscCall(VecView(lambda[0], ictx->viewer)); 1398 PetscCall(PetscViewerDrawGetDraw(ictx->viewer, 0, &draw)); 1399 PetscCall(PetscSNPrintf(time, 32, "Timestep %" PetscInt_FMT " Time %g", step, (double)ptime)); 1400 PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr)); 1401 h = yl + .95 * (yr - yl); 1402 PetscCall(PetscDrawStringCentered(draw, .5 * (xl + xr), h, PETSC_DRAW_BLACK, time)); 1403 PetscCall(PetscDrawFlush(draw)); 1404 PetscFunctionReturn(PETSC_SUCCESS); 1405 } 1406 1407 /*@C 1408 TSAdjointSetFromOptions - Sets various `TS` adjoint parameters from options database. 1409 1410 Collective 1411 1412 Input Parameters: 1413 + ts - the `TS` context 1414 - PetscOptionsObject - the options context 1415 1416 Options Database Keys: 1417 + -ts_adjoint_solve <yes,no> - After solving the ODE/DAE solve the adjoint problem (requires `-ts_save_trajectory`) 1418 . -ts_adjoint_monitor - print information at each adjoint time step 1419 - -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically 1420 1421 Level: developer 1422 1423 Note: 1424 This is not normally called directly by users 1425 1426 .seealso: [](ch_ts), `TSSetSaveTrajectory()`, `TSTrajectorySetUp()` 1427 @*/ 1428 PetscErrorCode TSAdjointSetFromOptions(TS ts, PetscOptionItems PetscOptionsObject) 1429 { 1430 PetscBool tflg, opt; 1431 1432 PetscFunctionBegin; 1433 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1434 PetscOptionsHeadBegin(PetscOptionsObject, "TS Adjoint options"); 1435 tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE; 1436 PetscCall(PetscOptionsBool("-ts_adjoint_solve", "Solve the adjoint problem immediately after solving the forward problem", "", tflg, &tflg, &opt)); 1437 if (opt) { 1438 PetscCall(TSSetSaveTrajectory(ts)); 1439 ts->adjoint_solve = tflg; 1440 } 1441 PetscCall(TSAdjointMonitorSetFromOptions(ts, "-ts_adjoint_monitor", "Monitor adjoint timestep size", "TSAdjointMonitorDefault", TSAdjointMonitorDefault, NULL)); 1442 PetscCall(TSAdjointMonitorSetFromOptions(ts, "-ts_adjoint_monitor_sensi", "Monitor sensitivity in the adjoint computation", "TSAdjointMonitorSensi", TSAdjointMonitorSensi, NULL)); 1443 opt = PETSC_FALSE; 1444 PetscCall(PetscOptionsName("-ts_adjoint_monitor_draw_sensi", "Monitor adjoint sensitivities (lambda only) graphically", "TSAdjointMonitorDrawSensi", &opt)); 1445 if (opt) { 1446 TSMonitorDrawCtx ctx; 1447 PetscInt howoften = 1; 1448 1449 PetscCall(PetscOptionsInt("-ts_adjoint_monitor_draw_sensi", "Monitor adjoint sensitivities (lambda only) graphically", "TSAdjointMonitorDrawSensi", howoften, &howoften, NULL)); 1450 PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx)); 1451 PetscCall(TSAdjointMonitorSet(ts, TSAdjointMonitorDrawSensi, ctx, (PetscCtxDestroyFn *)TSMonitorDrawCtxDestroy)); 1452 } 1453 PetscFunctionReturn(PETSC_SUCCESS); 1454 } 1455 1456 /*@ 1457 TSAdjointStep - Steps one time step backward in the adjoint run 1458 1459 Collective 1460 1461 Input Parameter: 1462 . ts - the `TS` context obtained from `TSCreate()` 1463 1464 Level: intermediate 1465 1466 .seealso: [](ch_ts), `TSAdjointSetUp()`, `TSAdjointSolve()` 1467 @*/ 1468 PetscErrorCode TSAdjointStep(TS ts) 1469 { 1470 DM dm; 1471 1472 PetscFunctionBegin; 1473 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1474 PetscCall(TSGetDM(ts, &dm)); 1475 PetscCall(TSAdjointSetUp(ts)); 1476 ts->steps--; /* must decrease the step index before the adjoint step is taken. */ 1477 1478 ts->reason = TS_CONVERGED_ITERATING; 1479 ts->ptime_prev = ts->ptime; 1480 PetscCall(PetscLogEventBegin(TS_AdjointStep, ts, 0, 0, 0)); 1481 PetscUseTypeMethod(ts, adjointstep); 1482 PetscCall(PetscLogEventEnd(TS_AdjointStep, ts, 0, 0, 0)); 1483 ts->adjoint_steps++; 1484 1485 if (ts->reason < 0) { 1486 PetscCheck(!ts->errorifstepfailed, PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSAdjointStep has failed due to %s", TSConvergedReasons[ts->reason]); 1487 } else if (!ts->reason) { 1488 if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS; 1489 } 1490 PetscFunctionReturn(PETSC_SUCCESS); 1491 } 1492 1493 /*@ 1494 TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE 1495 1496 Collective 1497 ` 1498 1499 Input Parameter: 1500 . ts - the `TS` context obtained from `TSCreate()` 1501 1502 Options Database Key: 1503 . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values 1504 1505 Level: intermediate 1506 1507 Notes: 1508 This must be called after a call to `TSSolve()` that solves the forward problem 1509 1510 By default this will integrate back to the initial time, one can use `TSAdjointSetSteps()` to step back to a later time 1511 1512 .seealso: [](ch_ts), `TSCreate()`, `TSSetCostGradients()`, `TSSetSolution()`, `TSAdjointStep()` 1513 @*/ 1514 PetscErrorCode TSAdjointSolve(TS ts) 1515 { 1516 static PetscBool cite = PETSC_FALSE; 1517 #if defined(TSADJOINT_STAGE) 1518 PetscLogStage adjoint_stage; 1519 #endif 1520 1521 PetscFunctionBegin; 1522 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1523 PetscCall(PetscCitationsRegister("@article{Zhang2022tsadjoint,\n" 1524 " title = {{PETSc TSAdjoint: A Discrete Adjoint ODE Solver for First-Order and Second-Order Sensitivity Analysis}},\n" 1525 " author = {Zhang, Hong and Constantinescu, Emil M. and Smith, Barry F.},\n" 1526 " journal = {SIAM Journal on Scientific Computing},\n" 1527 " volume = {44},\n" 1528 " number = {1},\n" 1529 " pages = {C1-C24},\n" 1530 " doi = {10.1137/21M140078X},\n" 1531 " year = {2022}\n}\n", 1532 &cite)); 1533 #if defined(TSADJOINT_STAGE) 1534 PetscCall(PetscLogStageRegister("TSAdjoint", &adjoint_stage)); 1535 PetscCall(PetscLogStagePush(adjoint_stage)); 1536 #endif 1537 PetscCall(TSAdjointSetUp(ts)); 1538 1539 /* reset time step and iteration counters */ 1540 ts->adjoint_steps = 0; 1541 ts->ksp_its = 0; 1542 ts->snes_its = 0; 1543 ts->num_snes_failures = 0; 1544 ts->reject = 0; 1545 ts->reason = TS_CONVERGED_ITERATING; 1546 1547 if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps; 1548 if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS; 1549 1550 while (!ts->reason) { 1551 PetscCall(TSTrajectoryGet(ts->trajectory, ts, ts->steps, &ts->ptime)); 1552 PetscCall(TSAdjointMonitor(ts, ts->steps, ts->ptime, ts->vec_sol, ts->numcost, ts->vecs_sensi, ts->vecs_sensip)); 1553 PetscCall(TSAdjointEventHandler(ts)); 1554 PetscCall(TSAdjointStep(ts)); 1555 if ((ts->vec_costintegral || ts->quadraturets) && !ts->costintegralfwd) PetscCall(TSAdjointCostIntegral(ts)); 1556 } 1557 if (!ts->steps) { 1558 PetscCall(TSTrajectoryGet(ts->trajectory, ts, ts->steps, &ts->ptime)); 1559 PetscCall(TSAdjointMonitor(ts, ts->steps, ts->ptime, ts->vec_sol, ts->numcost, ts->vecs_sensi, ts->vecs_sensip)); 1560 } 1561 ts->solvetime = ts->ptime; 1562 PetscCall(TSTrajectoryViewFromOptions(ts->trajectory, NULL, "-ts_trajectory_view")); 1563 PetscCall(VecViewFromOptions(ts->vecs_sensi[0], (PetscObject)ts, "-ts_adjoint_view_solution")); 1564 ts->adjoint_max_steps = 0; 1565 #if defined(TSADJOINT_STAGE) 1566 PetscCall(PetscLogStagePop()); 1567 #endif 1568 PetscFunctionReturn(PETSC_SUCCESS); 1569 } 1570 1571 /*@C 1572 TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using `TSAdjointMonitorSet()` 1573 1574 Collective 1575 1576 Input Parameters: 1577 + ts - time stepping context obtained from `TSCreate()` 1578 . step - step number that has just completed 1579 . ptime - model time of the state 1580 . u - state at the current model time 1581 . numcost - number of cost functions (dimension of lambda or mu) 1582 . lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables 1583 - mu - vectors containing the gradients of the cost functions with respect to the problem parameters 1584 1585 Level: developer 1586 1587 Note: 1588 `TSAdjointMonitor()` is typically used automatically within the time stepping implementations. 1589 Users would almost never call this routine directly. 1590 1591 .seealso: `TSAdjointMonitorSet()`, `TSAdjointSolve()` 1592 @*/ 1593 PetscErrorCode TSAdjointMonitor(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscInt numcost, Vec *lambda, Vec *mu) 1594 { 1595 PetscInt i, n = ts->numberadjointmonitors; 1596 1597 PetscFunctionBegin; 1598 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1599 PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 1600 PetscCall(VecLockReadPush(u)); 1601 for (i = 0; i < n; i++) PetscCall((*ts->adjointmonitor[i])(ts, step, ptime, u, numcost, lambda, mu, ts->adjointmonitorcontext[i])); 1602 PetscCall(VecLockReadPop(u)); 1603 PetscFunctionReturn(PETSC_SUCCESS); 1604 } 1605 1606 /*@ 1607 TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run. 1608 1609 Collective 1610 1611 Input Parameter: 1612 . ts - time stepping context 1613 1614 Level: advanced 1615 1616 Notes: 1617 This function cannot be called until `TSAdjointStep()` has been completed. 1618 1619 .seealso: [](ch_ts), `TSAdjointSolve()`, `TSAdjointStep()` 1620 @*/ 1621 PetscErrorCode TSAdjointCostIntegral(TS ts) 1622 { 1623 PetscFunctionBegin; 1624 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1625 PetscUseTypeMethod(ts, adjointintegral); 1626 PetscFunctionReturn(PETSC_SUCCESS); 1627 } 1628 1629 /* ------------------ Forward (tangent linear) sensitivity ------------------*/ 1630 1631 /*@ 1632 TSForwardSetUp - Sets up the internal data structures for the later use 1633 of forward sensitivity analysis 1634 1635 Collective 1636 1637 Input Parameter: 1638 . ts - the `TS` context obtained from `TSCreate()` 1639 1640 Level: advanced 1641 1642 .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSDestroy()`, `TSSetUp()` 1643 @*/ 1644 PetscErrorCode TSForwardSetUp(TS ts) 1645 { 1646 PetscFunctionBegin; 1647 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1648 if (ts->forwardsetupcalled) PetscFunctionReturn(PETSC_SUCCESS); 1649 PetscTryTypeMethod(ts, forwardsetup); 1650 PetscCall(VecDuplicate(ts->vec_sol, &ts->vec_sensip_col)); 1651 ts->forwardsetupcalled = PETSC_TRUE; 1652 PetscFunctionReturn(PETSC_SUCCESS); 1653 } 1654 1655 /*@ 1656 TSForwardReset - Reset the internal data structures used by forward sensitivity analysis 1657 1658 Collective 1659 1660 Input Parameter: 1661 . ts - the `TS` context obtained from `TSCreate()` 1662 1663 Level: advanced 1664 1665 .seealso: [](ch_ts), `TSCreate()`, `TSDestroy()`, `TSForwardSetUp()` 1666 @*/ 1667 PetscErrorCode TSForwardReset(TS ts) 1668 { 1669 TS quadts = ts->quadraturets; 1670 1671 PetscFunctionBegin; 1672 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1673 PetscTryTypeMethod(ts, forwardreset); 1674 PetscCall(MatDestroy(&ts->mat_sensip)); 1675 if (quadts) PetscCall(MatDestroy(&quadts->mat_sensip)); 1676 PetscCall(VecDestroy(&ts->vec_sensip_col)); 1677 ts->forward_solve = PETSC_FALSE; 1678 ts->forwardsetupcalled = PETSC_FALSE; 1679 PetscFunctionReturn(PETSC_SUCCESS); 1680 } 1681 1682 /*@ 1683 TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term. 1684 1685 Input Parameters: 1686 + ts - the `TS` context obtained from `TSCreate()` 1687 . numfwdint - number of integrals 1688 - vp - the vectors containing the gradients for each integral w.r.t. parameters 1689 1690 Level: deprecated 1691 1692 .seealso: [](ch_ts), `TSForwardGetSensitivities()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()` 1693 @*/ 1694 PetscErrorCode TSForwardSetIntegralGradients(TS ts, PetscInt numfwdint, Vec *vp) 1695 { 1696 PetscFunctionBegin; 1697 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1698 PetscCheck(!ts->numcost || ts->numcost == numfwdint, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand()"); 1699 if (!ts->numcost) ts->numcost = numfwdint; 1700 1701 ts->vecs_integral_sensip = vp; 1702 PetscFunctionReturn(PETSC_SUCCESS); 1703 } 1704 1705 /*@ 1706 TSForwardGetIntegralGradients - Returns the forward sensitivities of the integral term. 1707 1708 Input Parameter: 1709 . ts - the `TS` context obtained from `TSCreate()` 1710 1711 Output Parameters: 1712 + numfwdint - number of integrals 1713 - vp - the vectors containing the gradients for each integral w.r.t. parameters 1714 1715 Level: deprecated 1716 1717 .seealso: [](ch_ts), `TSForwardSetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardStep()` 1718 @*/ 1719 PetscErrorCode TSForwardGetIntegralGradients(TS ts, PetscInt *numfwdint, Vec **vp) 1720 { 1721 PetscFunctionBegin; 1722 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1723 PetscAssertPointer(vp, 3); 1724 if (numfwdint) *numfwdint = ts->numcost; 1725 if (vp) *vp = ts->vecs_integral_sensip; 1726 PetscFunctionReturn(PETSC_SUCCESS); 1727 } 1728 1729 /*@ 1730 TSForwardStep - Compute the forward sensitivity for one time step. 1731 1732 Collective 1733 1734 Input Parameter: 1735 . ts - time stepping context 1736 1737 Level: advanced 1738 1739 Notes: 1740 This function cannot be called until `TSStep()` has been completed. 1741 1742 .seealso: [](ch_ts), `TSForwardSetSensitivities()`, `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardSetUp()` 1743 @*/ 1744 PetscErrorCode TSForwardStep(TS ts) 1745 { 1746 PetscFunctionBegin; 1747 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1748 PetscCall(PetscLogEventBegin(TS_ForwardStep, ts, 0, 0, 0)); 1749 PetscUseTypeMethod(ts, forwardstep); 1750 PetscCall(PetscLogEventEnd(TS_ForwardStep, ts, 0, 0, 0)); 1751 PetscCheck(ts->reason >= 0 || !ts->errorifstepfailed, PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSFowardStep has failed due to %s", TSConvergedReasons[ts->reason]); 1752 PetscFunctionReturn(PETSC_SUCCESS); 1753 } 1754 1755 /*@ 1756 TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution w.r.t. the problem parameters and initial values. 1757 1758 Logically Collective 1759 1760 Input Parameters: 1761 + ts - the `TS` context obtained from `TSCreate()` 1762 . nump - number of parameters 1763 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters 1764 1765 Level: beginner 1766 1767 Notes: 1768 Use `PETSC_DETERMINE` to use the number of columns of `Smat` for `nump` 1769 1770 Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems. 1771 This function turns on a flag to trigger `TSSolve()` to compute forward sensitivities automatically. 1772 You must call this function before `TSSolve()`. 1773 The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime. 1774 1775 .seealso: [](ch_ts), `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()` 1776 @*/ 1777 PetscErrorCode TSForwardSetSensitivities(TS ts, PetscInt nump, Mat Smat) 1778 { 1779 PetscFunctionBegin; 1780 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1781 PetscValidHeaderSpecific(Smat, MAT_CLASSID, 3); 1782 ts->forward_solve = PETSC_TRUE; 1783 if (nump == PETSC_DEFAULT || nump == PETSC_DETERMINE) { 1784 PetscCall(MatGetSize(Smat, NULL, &ts->num_parameters)); 1785 } else ts->num_parameters = nump; 1786 PetscCall(PetscObjectReference((PetscObject)Smat)); 1787 PetscCall(MatDestroy(&ts->mat_sensip)); 1788 ts->mat_sensip = Smat; 1789 PetscFunctionReturn(PETSC_SUCCESS); 1790 } 1791 1792 /*@ 1793 TSForwardGetSensitivities - Returns the trajectory sensitivities 1794 1795 Not Collective, but Smat returned is parallel if ts is parallel 1796 1797 Output Parameters: 1798 + ts - the `TS` context obtained from `TSCreate()` 1799 . nump - number of parameters 1800 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters 1801 1802 Level: intermediate 1803 1804 .seealso: [](ch_ts), `TSForwardSetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()` 1805 @*/ 1806 PetscErrorCode TSForwardGetSensitivities(TS ts, PetscInt *nump, Mat *Smat) 1807 { 1808 PetscFunctionBegin; 1809 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1810 if (nump) *nump = ts->num_parameters; 1811 if (Smat) *Smat = ts->mat_sensip; 1812 PetscFunctionReturn(PETSC_SUCCESS); 1813 } 1814 1815 /*@ 1816 TSForwardCostIntegral - Evaluate the cost integral in the forward run. 1817 1818 Collective 1819 1820 Input Parameter: 1821 . ts - time stepping context 1822 1823 Level: advanced 1824 1825 Note: 1826 This function cannot be called until `TSStep()` has been completed. 1827 1828 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSAdjointCostIntegral()` 1829 @*/ 1830 PetscErrorCode TSForwardCostIntegral(TS ts) 1831 { 1832 PetscFunctionBegin; 1833 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1834 PetscUseTypeMethod(ts, forwardintegral); 1835 PetscFunctionReturn(PETSC_SUCCESS); 1836 } 1837 1838 /*@ 1839 TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities 1840 1841 Collective 1842 1843 Input Parameters: 1844 + ts - the `TS` context obtained from `TSCreate()` 1845 - didp - parametric sensitivities of the initial condition 1846 1847 Level: intermediate 1848 1849 Notes: 1850 `TSSolve()` allows users to pass the initial solution directly to `TS`. But the tangent linear variables cannot be initialized in this way. 1851 This function is used to set initial values for tangent linear variables. 1852 1853 .seealso: [](ch_ts), `TS`, `TSForwardSetSensitivities()` 1854 @*/ 1855 PetscErrorCode TSForwardSetInitialSensitivities(TS ts, Mat didp) 1856 { 1857 PetscFunctionBegin; 1858 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1859 PetscValidHeaderSpecific(didp, MAT_CLASSID, 2); 1860 if (!ts->mat_sensip) PetscCall(TSForwardSetSensitivities(ts, PETSC_DETERMINE, didp)); 1861 PetscFunctionReturn(PETSC_SUCCESS); 1862 } 1863 1864 /*@ 1865 TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages 1866 1867 Input Parameter: 1868 . ts - the `TS` context obtained from `TSCreate()` 1869 1870 Output Parameters: 1871 + ns - number of stages 1872 - S - tangent linear sensitivities at the intermediate stages 1873 1874 Level: advanced 1875 1876 .seealso: `TS` 1877 @*/ 1878 PetscErrorCode TSForwardGetStages(TS ts, PetscInt *ns, Mat **S) 1879 { 1880 PetscFunctionBegin; 1881 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1882 1883 if (!ts->ops->getstages) *S = NULL; 1884 else PetscUseTypeMethod(ts, forwardgetstages, ns, S); 1885 PetscFunctionReturn(PETSC_SUCCESS); 1886 } 1887 1888 /*@ 1889 TSCreateQuadratureTS - Create a sub-`TS` that evaluates integrals over time 1890 1891 Input Parameters: 1892 + ts - the `TS` context obtained from `TSCreate()` 1893 - fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run 1894 1895 Output Parameter: 1896 . quadts - the child `TS` context 1897 1898 Level: intermediate 1899 1900 .seealso: [](ch_ts), `TSGetQuadratureTS()` 1901 @*/ 1902 PetscErrorCode TSCreateQuadratureTS(TS ts, PetscBool fwd, TS *quadts) 1903 { 1904 char prefix[128]; 1905 1906 PetscFunctionBegin; 1907 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1908 PetscAssertPointer(quadts, 3); 1909 PetscCall(TSDestroy(&ts->quadraturets)); 1910 PetscCall(TSCreate(PetscObjectComm((PetscObject)ts), &ts->quadraturets)); 1911 PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->quadraturets, (PetscObject)ts, 1)); 1912 PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%squad_", ((PetscObject)ts)->prefix ? ((PetscObject)ts)->prefix : "")); 1913 PetscCall(TSSetOptionsPrefix(ts->quadraturets, prefix)); 1914 *quadts = ts->quadraturets; 1915 1916 if (ts->numcost) { 1917 PetscCall(VecCreateSeq(PETSC_COMM_SELF, ts->numcost, &(*quadts)->vec_sol)); 1918 } else { 1919 PetscCall(VecCreateSeq(PETSC_COMM_SELF, 1, &(*quadts)->vec_sol)); 1920 } 1921 ts->costintegralfwd = fwd; 1922 PetscFunctionReturn(PETSC_SUCCESS); 1923 } 1924 1925 /*@ 1926 TSGetQuadratureTS - Return the sub-`TS` that evaluates integrals over time 1927 1928 Input Parameter: 1929 . ts - the `TS` context obtained from `TSCreate()` 1930 1931 Output Parameters: 1932 + fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run 1933 - quadts - the child `TS` context 1934 1935 Level: intermediate 1936 1937 .seealso: [](ch_ts), `TSCreateQuadratureTS()` 1938 @*/ 1939 PetscErrorCode TSGetQuadratureTS(TS ts, PetscBool *fwd, TS *quadts) 1940 { 1941 PetscFunctionBegin; 1942 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1943 if (fwd) *fwd = ts->costintegralfwd; 1944 if (quadts) *quadts = ts->quadraturets; 1945 PetscFunctionReturn(PETSC_SUCCESS); 1946 } 1947 1948 /*@ 1949 TSComputeSNESJacobian - Compute the Jacobian needed for the `SNESSolve()` in `TS` 1950 1951 Collective 1952 1953 Input Parameters: 1954 + ts - the `TS` context obtained from `TSCreate()` 1955 - x - state vector 1956 1957 Output Parameters: 1958 + J - Jacobian matrix 1959 - Jpre - preconditioning matrix for J (may be same as J) 1960 1961 Level: developer 1962 1963 Note: 1964 Uses finite differencing when `TS` Jacobian is not available. 1965 1966 .seealso: `SNES`, `TS`, `SNESSetJacobian()`, `TSSetRHSJacobian()`, `TSSetIJacobian()` 1967 @*/ 1968 PetscErrorCode TSComputeSNESJacobian(TS ts, Vec x, Mat J, Mat Jpre) 1969 { 1970 SNES snes = ts->snes; 1971 PetscErrorCode (*jac)(SNES, Vec, Mat, Mat, void *) = NULL; 1972 1973 PetscFunctionBegin; 1974 /* 1975 Unlike implicit methods, explicit methods do not have SNESMatFDColoring in the snes object 1976 because SNESSolve() has not been called yet; so querying SNESMatFDColoring does not work for 1977 explicit methods. Instead, we check the Jacobian compute function directly to determine if FD 1978 coloring is used. 1979 */ 1980 PetscCall(SNESGetJacobian(snes, NULL, NULL, &jac, NULL)); 1981 if (jac == SNESComputeJacobianDefaultColor) { 1982 Vec f; 1983 PetscCall(SNESSetSolution(snes, x)); 1984 PetscCall(SNESGetFunction(snes, &f, NULL, NULL)); 1985 /* Force MatFDColoringApply to evaluate the SNES residual function for the base vector */ 1986 PetscCall(SNESComputeFunction(snes, x, f)); 1987 } 1988 PetscCall(SNESComputeJacobian(snes, x, J, Jpre)); 1989 PetscFunctionReturn(PETSC_SUCCESS); 1990 } 1991