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