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