xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 881c1a9bd7e2febf75cfabeec1482a574c2003d5)
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    Note:
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 - input vector to be left-multiplied with the Hessian
467 .   Vr - input vector to be right-multiplied with the Hessian
468 .   VHV - output vector for vector-Hessian-vector product
469 -   ctx - [optional] user-defined function context
470 
471   Level: intermediate
472 
473 Note: The first Hessian function and the working array are required.
474 
475 .keywords: TS, sensitivity
476 
477 .seealso:
478 @*/
479 PetscErrorCode TSSetIHessianProduct(TS ts,Vec *ihp1,PetscErrorCode (*ihessianproductfunc1)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
480                                           Vec *ihp2,PetscErrorCode (*ihessianproductfunc2)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
481                                           Vec *ihp3,PetscErrorCode (*ihessianproductfunc3)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
482                                           Vec *ihp4,PetscErrorCode (*ihessianproductfunc4)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
483                                     void *ctx)
484 {
485   PetscFunctionBegin;
486   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
487   PetscValidPointer(ihp1,2);
488 
489   ts->ihessianproductctx = ctx;
490   if (ihp1) ts->vecs_fuu = ihp1;
491   if (ihp2) ts->vecs_fup = ihp2;
492   if (ihp3) ts->vecs_fpu = ihp3;
493   if (ihp4) ts->vecs_fpp = ihp4;
494   ts->ihessianproduct_fuu = ihessianproductfunc1;
495   ts->ihessianproduct_fup = ihessianproductfunc2;
496   ts->ihessianproduct_fpu = ihessianproductfunc3;
497   ts->ihessianproduct_fpp = ihessianproductfunc4;
498   PetscFunctionReturn(0);
499 }
500 
501 /*@C
502   TSComputeIHessianProductFunction1 - Runs the user-defined vector-Hessian-vector product function for Fuu.
503 
504   Collective on TS
505 
506   Input Parameters:
507 . ts   - The TS context obtained from TSCreate()
508 
509   Notes:
510   TSComputeIHessianProductFunction1() is typically used for sensitivity implementation,
511   so most users would not generally call this routine themselves.
512 
513   Level: developer
514 
515 .keywords: TS, sensitivity
516 
517 .seealso: TSSetIHessianProduct()
518 @*/
519 PetscErrorCode TSComputeIHessianProductFunction1(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
520 {
521   PetscErrorCode ierr;
522 
523   PetscFunctionBegin;
524   if (!VHV) PetscFunctionReturn(0);
525   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
526   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
527 
528   if (ts->ihessianproduct_fuu) {
529     PetscStackPush("TS user IHessianProduct function 1 for sensitivity analysis");
530     ierr = (*ts->ihessianproduct_fuu)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
531     PetscStackPop;
532   }
533   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
534   if (ts->rhshessianproduct_guu) {
535     PetscInt nadj;
536     ierr = TSComputeRHSHessianProductFunction1(ts,t,U,Vl,Vr,VHV);CHKERRQ(ierr);
537     for (nadj=0; nadj<ts->numcost; nadj++) {
538       ierr = VecScale(VHV[nadj],-1);CHKERRQ(ierr);
539     }
540   }
541   PetscFunctionReturn(0);
542 }
543 
544 /*@C
545   TSComputeIHessianProductFunction2 - Runs the user-defined vector-Hessian-vector product function for Fup.
546 
547   Collective on TS
548 
549   Input Parameters:
550 . ts   - The TS context obtained from TSCreate()
551 
552   Notes:
553   TSComputeIHessianProductFunction2() is typically used for sensitivity implementation,
554   so most users would not generally call this routine themselves.
555 
556   Level: developer
557 
558 .keywords: TS, sensitivity
559 
560 .seealso: TSSetIHessianProduct()
561 @*/
562 PetscErrorCode TSComputeIHessianProductFunction2(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
563 {
564   PetscErrorCode ierr;
565 
566   PetscFunctionBegin;
567   if (!VHV) PetscFunctionReturn(0);
568   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
569   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
570 
571   if (ts->ihessianproduct_fup) {
572     PetscStackPush("TS user IHessianProduct function 2 for sensitivity analysis");
573     ierr = (*ts->ihessianproduct_fup)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
574     PetscStackPop;
575   }
576   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
577   if (ts->rhshessianproduct_gup) {
578     PetscInt nadj;
579     ierr = TSComputeRHSHessianProductFunction2(ts,t,U,Vl,Vr,VHV);CHKERRQ(ierr);
580     for (nadj=0; nadj<ts->numcost; nadj++) {
581       ierr = VecScale(VHV[nadj],-1);CHKERRQ(ierr);
582     }
583   }
584   PetscFunctionReturn(0);
585 }
586 
587 /*@C
588   TSComputeIHessianProductFunction3 - Runs the user-defined vector-Hessian-vector product function for Fpu.
589 
590   Collective on TS
591 
592   Input Parameters:
593 . ts   - The TS context obtained from TSCreate()
594 
595   Notes:
596   TSComputeIHessianProductFunction3() is typically used for sensitivity implementation,
597   so most users would not generally call this routine themselves.
598 
599   Level: developer
600 
601 .keywords: TS, sensitivity
602 
603 .seealso: TSSetIHessianProduct()
604 @*/
605 PetscErrorCode TSComputeIHessianProductFunction3(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
606 {
607   PetscErrorCode ierr;
608 
609   PetscFunctionBegin;
610   if (!VHV) PetscFunctionReturn(0);
611   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
612   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
613 
614   if (ts->ihessianproduct_fpu) {
615     PetscStackPush("TS user IHessianProduct function 3 for sensitivity analysis");
616     ierr = (*ts->ihessianproduct_fpu)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
617     PetscStackPop;
618   }
619   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
620   if (ts->rhshessianproduct_gpu) {
621     PetscInt nadj;
622     ierr = TSComputeRHSHessianProductFunction3(ts,t,U,Vl,Vr,VHV);CHKERRQ(ierr);
623     for (nadj=0; nadj<ts->numcost; nadj++) {
624       ierr = VecScale(VHV[nadj],-1);CHKERRQ(ierr);
625     }
626   }
627   PetscFunctionReturn(0);
628 }
629 
630 /*@C
631   TSComputeIHessianProductFunction4 - Runs the user-defined vector-Hessian-vector product function for Fpp.
632 
633   Collective on TS
634 
635   Input Parameters:
636 . ts   - The TS context obtained from TSCreate()
637 
638   Notes:
639   TSComputeIHessianProductFunction4() is typically used for sensitivity implementation,
640   so most users would not generally call this routine themselves.
641 
642   Level: developer
643 
644 .keywords: TS, sensitivity
645 
646 .seealso: TSSetIHessianProduct()
647 @*/
648 PetscErrorCode TSComputeIHessianProductFunction4(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
649 {
650   PetscErrorCode ierr;
651 
652   PetscFunctionBegin;
653   if (!VHV) PetscFunctionReturn(0);
654   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
655   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
656 
657   if (ts->ihessianproduct_fpp) {
658     PetscStackPush("TS user IHessianProduct function 3 for sensitivity analysis");
659     ierr = (*ts->ihessianproduct_fpp)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
660     PetscStackPop;
661   }
662   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
663   if (ts->rhshessianproduct_gpp) {
664     PetscInt nadj;
665     ierr = TSComputeRHSHessianProductFunction4(ts,t,U,Vl,Vr,VHV);CHKERRQ(ierr);
666     for (nadj=0; nadj<ts->numcost; nadj++) {
667       ierr = VecScale(VHV[nadj],-1);CHKERRQ(ierr);
668     }
669   }
670   PetscFunctionReturn(0);
671 }
672 
673 /*@C
674   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.
675 
676   Logically Collective on TS
677 
678   Input Parameters:
679 + ts - TS context obtained from TSCreate()
680 . rhshp1 - an array of vectors storing the result of vector-Hessian-vector product for G_UU
681 . hessianproductfunc1 - vector-Hessian-vector product function for G_UU
682 . rhshp2 - an array of vectors storing the result of vector-Hessian-vector product for G_UP
683 . hessianproductfunc2 - vector-Hessian-vector product function for G_UP
684 . rhshp3 - an array of vectors storing the result of vector-Hessian-vector product for G_PU
685 . hessianproductfunc3 - vector-Hessian-vector product function for G_PU
686 . rhshp4 - an array of vectors storing the result of vector-Hessian-vector product for G_PP
687 . hessianproductfunc4 - vector-Hessian-vector product function for G_PP
688 
689   Calling sequence of ihessianproductfunc:
690 $ rhshessianproductfunc (TS ts,PetscReal t,Vec U,Vec Vl,Vec Vr,Vec VHV,void *ctx);
691 +   t - current timestep
692 .   U - input vector (current ODE solution)
693 .   Vl - input vector to be left-multiplied with the Hessian
694 .   Vr - input vector to be right-multiplied with the Hessian
695 .   VHV - output vector for vector-Hessian-vector product
696 -   ctx - [optional] user-defined function context
697 
698   Level: intermediate
699 
700 Note: The first Hessian function and the working array are required.
701 
702 .keywords: TS, sensitivity
703 
704 .seealso:
705 @*/
706 PetscErrorCode TSSetRHSHessianProduct(TS ts,Vec *rhshp1,PetscErrorCode (*rhshessianproductfunc1)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
707                                           Vec *rhshp2,PetscErrorCode (*rhshessianproductfunc2)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
708                                           Vec *rhshp3,PetscErrorCode (*rhshessianproductfunc3)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
709                                           Vec *rhshp4,PetscErrorCode (*rhshessianproductfunc4)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
710                                     void *ctx)
711 {
712   PetscFunctionBegin;
713   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
714   PetscValidPointer(rhshp1,2);
715 
716   ts->rhshessianproductctx = ctx;
717   if (rhshp1) ts->vecs_guu = rhshp1;
718   if (rhshp2) ts->vecs_gup = rhshp2;
719   if (rhshp3) ts->vecs_gpu = rhshp3;
720   if (rhshp4) ts->vecs_gpp = rhshp4;
721   ts->rhshessianproduct_guu = rhshessianproductfunc1;
722   ts->rhshessianproduct_gup = rhshessianproductfunc2;
723   ts->rhshessianproduct_gpu = rhshessianproductfunc3;
724   ts->rhshessianproduct_gpp = rhshessianproductfunc4;
725   PetscFunctionReturn(0);
726 }
727 
728 /*@C
729   TSComputeRHSHessianProductFunction1 - Runs the user-defined vector-Hessian-vector product function for Guu.
730 
731   Collective on TS
732 
733   Input Parameters:
734 . ts   - The TS context obtained from TSCreate()
735 
736   Notes:
737   TSComputeRHSHessianProductFunction1() is typically used for sensitivity implementation,
738   so most users would not generally call this routine themselves.
739 
740   Level: developer
741 
742 .keywords: TS, sensitivity
743 
744 .seealso: TSSetRHSHessianProduct()
745 @*/
746 PetscErrorCode TSComputeRHSHessianProductFunction1(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
747 {
748   PetscErrorCode ierr;
749 
750   PetscFunctionBegin;
751   if (!VHV) PetscFunctionReturn(0);
752   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
753   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
754 
755   PetscStackPush("TS user RHSHessianProduct function 1 for sensitivity analysis");
756   ierr = (*ts->rhshessianproduct_guu)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx);CHKERRQ(ierr);
757   PetscStackPop;
758   PetscFunctionReturn(0);
759 }
760 
761 /*@C
762   TSComputeRHSHessianProductFunction2 - Runs the user-defined vector-Hessian-vector product function for Gup.
763 
764   Collective on TS
765 
766   Input Parameters:
767 . ts   - The TS context obtained from TSCreate()
768 
769   Notes:
770   TSComputeRHSHessianProductFunction2() is typically used for sensitivity implementation,
771   so most users would not generally call this routine themselves.
772 
773   Level: developer
774 
775 .keywords: TS, sensitivity
776 
777 .seealso: TSSetRHSHessianProduct()
778 @*/
779 PetscErrorCode TSComputeRHSHessianProductFunction2(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
780 {
781   PetscErrorCode ierr;
782 
783   PetscFunctionBegin;
784   if (!VHV) PetscFunctionReturn(0);
785   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
786   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
787 
788   PetscStackPush("TS user RHSHessianProduct function 2 for sensitivity analysis");
789   ierr = (*ts->rhshessianproduct_gup)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx);CHKERRQ(ierr);
790   PetscStackPop;
791   PetscFunctionReturn(0);
792 }
793 
794 /*@C
795   TSComputeRHSHessianProductFunction3 - Runs the user-defined vector-Hessian-vector product function for Gpu.
796 
797   Collective on TS
798 
799   Input Parameters:
800 . ts   - The TS context obtained from TSCreate()
801 
802   Notes:
803   TSComputeRHSHessianProductFunction3() is typically used for sensitivity implementation,
804   so most users would not generally call this routine themselves.
805 
806   Level: developer
807 
808 .keywords: TS, sensitivity
809 
810 .seealso: TSSetRHSHessianProduct()
811 @*/
812 PetscErrorCode TSComputeRHSHessianProductFunction3(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
813 {
814   PetscErrorCode ierr;
815 
816   PetscFunctionBegin;
817   if (!VHV) PetscFunctionReturn(0);
818   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
819   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
820 
821   PetscStackPush("TS user RHSHessianProduct function 3 for sensitivity analysis");
822   ierr = (*ts->rhshessianproduct_gpu)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx);CHKERRQ(ierr);
823   PetscStackPop;
824   PetscFunctionReturn(0);
825 }
826 
827 /*@C
828   TSComputeRHSHessianProductFunction4 - Runs the user-defined vector-Hessian-vector product function for Gpp.
829 
830   Collective on TS
831 
832   Input Parameters:
833 . ts   - The TS context obtained from TSCreate()
834 
835   Notes:
836   TSComputeRHSHessianProductFunction4() is typically used for sensitivity implementation,
837   so most users would not generally call this routine themselves.
838 
839   Level: developer
840 
841 .keywords: TS, sensitivity
842 
843 .seealso: TSSetRHSHessianProduct()
844 @*/
845 PetscErrorCode TSComputeRHSHessianProductFunction4(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
846 {
847   PetscErrorCode ierr;
848 
849   PetscFunctionBegin;
850   if (!VHV) PetscFunctionReturn(0);
851   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
852   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
853 
854   PetscStackPush("TS user RHSHessianProduct function 3 for sensitivity analysis");
855   ierr = (*ts->rhshessianproduct_gpp)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx);CHKERRQ(ierr);
856   PetscStackPop;
857   PetscFunctionReturn(0);
858 }
859 
860 /* --------------------------- Adjoint sensitivity ---------------------------*/
861 
862 /*@
863    TSSetCostGradients - Sets the initial value of the gradients of the cost function w.r.t. initial values and w.r.t. the problem parameters
864       for use by the TSAdjoint routines.
865 
866    Logically Collective on TS and Vec
867 
868    Input Parameters:
869 +  ts - the TS context obtained from TSCreate()
870 .  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
871 -  mu - gradients with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
872 
873    Level: beginner
874 
875    Notes:
876     the entries in these vectors must be correctly initialized with the values lamda_i = df/dy|finaltime  mu_i = df/dp|finaltime
877 
878    After TSAdjointSolve() is called the lamba and the mu contain the computed sensitivities
879 
880 .keywords: TS, timestep, set, sensitivity, initial values
881 
882 .seealso TSGetCostGradients()
883 @*/
884 PetscErrorCode TSSetCostGradients(TS ts,PetscInt numcost,Vec *lambda,Vec *mu)
885 {
886   PetscFunctionBegin;
887   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
888   PetscValidPointer(lambda,2);
889   ts->vecs_sensi  = lambda;
890   ts->vecs_sensip = mu;
891   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");
892   ts->numcost  = numcost;
893   PetscFunctionReturn(0);
894 }
895 
896 /*@
897    TSGetCostGradients - Returns the gradients from the TSAdjointSolve()
898 
899    Not Collective, but Vec returned is parallel if TS is parallel
900 
901    Input Parameter:
902 .  ts - the TS context obtained from TSCreate()
903 
904    Output Parameter:
905 +  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
906 -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
907 
908    Level: intermediate
909 
910 .keywords: TS, timestep, get, sensitivity
911 
912 .seealso: TSSetCostGradients()
913 @*/
914 PetscErrorCode TSGetCostGradients(TS ts,PetscInt *numcost,Vec **lambda,Vec **mu)
915 {
916   PetscFunctionBegin;
917   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
918   if (numcost) *numcost = ts->numcost;
919   if (lambda)  *lambda  = ts->vecs_sensi;
920   if (mu)      *mu      = ts->vecs_sensip;
921   PetscFunctionReturn(0);
922 }
923 
924 /*@
925    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
926       for use by the TSAdjoint routines.
927 
928    Logically Collective on TS and Vec
929 
930    Input Parameters:
931 +  ts - the TS context obtained from TSCreate()
932 .  numcost - number of cost functions
933 .  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
934 .  mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
935 -  dir - the direction vector that are multiplied with the Hessian of the cost functions
936 
937    Level: beginner
938 
939    Notes: Hessian of the cost function is completely different from Hessian of the ODE/DAE system
940 
941    For second-order adjoint, one needs to call this function and then TSAdjointSetForward() before TSSolve().
942 
943    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.
944 
945    Passing NULL for lambda2 disables the second-order calculation.
946 .keywords: TS, sensitivity, second-order adjoint
947 
948 .seealso: TSAdjointSetForward()
949 @*/
950 PetscErrorCode TSSetCostHessianProducts(TS ts,PetscInt numcost,Vec *lambda2,Vec *mu2,Vec dir)
951 {
952   PetscFunctionBegin;
953   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
954   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");
955   ts->numcost       = numcost;
956   ts->vecs_sensi2   = lambda2;
957   ts->vecs_sensi2p  = mu2;
958   ts->vec_dir       = dir;
959   PetscFunctionReturn(0);
960 }
961 
962 /*@
963    TSGetCostHessianProducts - Returns the gradients from the TSAdjointSolve()
964 
965    Not Collective, but Vec returned is parallel if TS is parallel
966 
967    Input Parameter:
968 .  ts - the TS context obtained from TSCreate()
969 
970    Output Parameter:
971 +  numcost - number of cost functions
972 .  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
973 .  mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
974 -  dir - the direction vector that are multiplied with the Hessian of the cost functions
975 
976    Level: intermediate
977 
978 .keywords: TS, sensitivity, second-order adjoint
979 
980 .seealso: TSSetCostHessianProducts()
981 @*/
982 PetscErrorCode TSGetCostHessianProducts(TS ts,PetscInt *numcost,Vec **lambda2,Vec **mu2, Vec *dir)
983 {
984   PetscFunctionBegin;
985   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
986   if (numcost) *numcost = ts->numcost;
987   if (lambda2) *lambda2 = ts->vecs_sensi2;
988   if (mu2)     *mu2     = ts->vecs_sensi2p;
989   if (dir)     *dir     = ts->vec_dir;
990   PetscFunctionReturn(0);
991 }
992 
993 /*@
994   TSAdjointSetForward - Trigger the tangent linear solver and initialize the forward sensitivities
995 
996   Logically Collective on TS and Mat
997 
998   Input Parameters:
999 +  ts - the TS context obtained from TSCreate()
1000 -  didp - the derivative of initial values w.r.t. parameters
1001 
1002   Level: intermediate
1003 
1004   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.
1005 
1006 .keywords: TS, sensitivity, second-order adjoint
1007 
1008 .seealso: TSSetCostHessianProducts(), TSAdjointResetForward()
1009 @*/
1010 PetscErrorCode TSAdjointSetForward(TS ts,Mat didp)
1011 {
1012   Mat            A;
1013   Vec            sp;
1014   PetscScalar    *xarr;
1015   PetscInt       lsize;
1016   PetscErrorCode ierr;
1017 
1018   PetscFunctionBegin;
1019   ts->forward_solve = PETSC_TRUE; /* turn on tangent linear mode */
1020   if (!ts->vecs_sensi2) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Must call TSSetCostHessianProducts() first");
1021   if (!ts->vec_dir) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Directional vector is missing. Call TSSetCostHessianProducts() to set it.");
1022   /* create a single-column dense matrix */
1023   ierr = VecGetLocalSize(ts->vec_sol,&lsize);CHKERRQ(ierr);
1024   ierr = MatCreateDense(PetscObjectComm((PetscObject)ts),lsize,PETSC_DECIDE,PETSC_DECIDE,1,NULL,&A);CHKERRQ(ierr);
1025 
1026   ierr = VecDuplicate(ts->vec_sol,&sp);CHKERRQ(ierr);
1027   ierr = MatDenseGetColumn(A,0,&xarr);CHKERRQ(ierr);
1028   ierr = VecPlaceArray(sp,xarr);CHKERRQ(ierr);
1029   if (ts->vecs_sensi2p) { /* tangent linear variable initialized as 2*dIdP*dir */
1030     if (didp) {
1031       ierr = MatMult(didp,ts->vec_dir,sp);CHKERRQ(ierr);
1032       ierr = VecScale(sp,2.);CHKERRQ(ierr);
1033     } else {
1034       ierr = VecZeroEntries(sp);CHKERRQ(ierr);
1035     }
1036   } else { /* tangent linear variable initialized as dir */
1037     ierr = VecCopy(ts->vec_dir,sp);CHKERRQ(ierr);
1038   }
1039   ierr = VecResetArray(sp);CHKERRQ(ierr);
1040   ierr = MatDenseRestoreColumn(A,&xarr);CHKERRQ(ierr);
1041   ierr = VecDestroy(&sp);CHKERRQ(ierr);
1042 
1043   ierr = TSForwardSetInitialSensitivities(ts,A);CHKERRQ(ierr); /* if didp is NULL, identity matrix is assumed */
1044 
1045   ierr = MatDestroy(&A);CHKERRQ(ierr);
1046   PetscFunctionReturn(0);
1047 }
1048 
1049 /*@
1050   TSAdjointResetForward - Reset the tangent linear solver and destroy the tangent linear context
1051 
1052   Logically Collective on TS and Mat
1053 
1054   Input Parameters:
1055 .  ts - the TS context obtained from TSCreate()
1056 
1057   Level: intermediate
1058 
1059 .keywords: TS, sensitivity, second-order adjoint
1060 
1061 .seealso: TSAdjointSetForward()
1062 @*/
1063 PetscErrorCode TSAdjointResetForward(TS ts)
1064 {
1065   PetscErrorCode ierr;
1066 
1067   PetscFunctionBegin;
1068   ts->forward_solve = PETSC_FALSE; /* turn off tangent linear mode */
1069   ierr = TSForwardReset(ts);CHKERRQ(ierr);
1070   PetscFunctionReturn(0);
1071 }
1072 
1073 /*@
1074    TSAdjointSetUp - Sets up the internal data structures for the later use
1075    of an adjoint solver
1076 
1077    Collective on TS
1078 
1079    Input Parameter:
1080 .  ts - the TS context obtained from TSCreate()
1081 
1082    Level: advanced
1083 
1084 .keywords: TS, timestep, setup
1085 
1086 .seealso: TSCreate(), TSAdjointStep(), TSSetCostGradients()
1087 @*/
1088 PetscErrorCode TSAdjointSetUp(TS ts)
1089 {
1090   TSTrajectory     tj;
1091   TSTrajectoryType tjtype;
1092   PetscBool        match;
1093   PetscErrorCode   ierr;
1094 
1095   PetscFunctionBegin;
1096   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1097   if (ts->adjointsetupcalled) PetscFunctionReturn(0);
1098   if (!ts->vecs_sensi) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetCostGradients() first");
1099   if (ts->vecs_sensip && !ts->Jacp && !ts->Jacprhs) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetRHSJacobianP() or TSSetIJacobianP() first");
1100   ierr = TSGetTrajectory(ts,&tj);CHKERRQ(ierr);
1101   ierr = TSTrajectoryGetType(tj,ts,&tjtype);CHKERRQ(ierr);
1102   ierr = PetscStrcmp(TSTRAJECTORYBASIC,tjtype,&match);CHKERRQ(ierr);
1103   if (match) {
1104     PetscBool solution_only;
1105     ierr = TSTrajectoryGetSolutionOnly(tj,&solution_only);CHKERRQ(ierr);
1106     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");
1107   }
1108 
1109   if (!ts->Jacp && ts->Jacprhs) ts->Jacp = ts->Jacprhs;
1110 
1111   if (ts->quadraturets) { /* if there is integral in the cost function */
1112     ierr = VecDuplicate(ts->vecs_sensi[0],&ts->vec_drdu_col);CHKERRQ(ierr);
1113     if (ts->vecs_sensip){
1114       ierr = VecDuplicate(ts->vecs_sensip[0],&ts->vec_drdp_col);CHKERRQ(ierr);
1115     }
1116   }
1117 
1118   if (ts->ops->adjointsetup) {
1119     ierr = (*ts->ops->adjointsetup)(ts);CHKERRQ(ierr);
1120   }
1121   ts->adjointsetupcalled = PETSC_TRUE;
1122   PetscFunctionReturn(0);
1123 }
1124 
1125 /*@
1126    TSAdjointReset - Resets a TSAdjoint context and removes any allocated Vecs and Mats.
1127 
1128    Collective on TS
1129 
1130    Input Parameter:
1131 .  ts - the TS context obtained from TSCreate()
1132 
1133    Level: beginner
1134 
1135 .keywords: TS, timestep, reset
1136 
1137 .seealso: TSCreate(), TSAdjointSetup(), TSADestroy()
1138 @*/
1139 PetscErrorCode TSAdjointReset(TS ts)
1140 {
1141   PetscErrorCode ierr;
1142 
1143   PetscFunctionBegin;
1144   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1145   if (ts->ops->adjointreset) {
1146     ierr = (*ts->ops->adjointreset)(ts);CHKERRQ(ierr);
1147   }
1148   if (ts->quadraturets) { /* if there is integral in the cost function */
1149     ierr = VecDestroy(&ts->vec_drdu_col);CHKERRQ(ierr);
1150     if (ts->vecs_sensip){
1151       ierr = VecDestroy(&ts->vec_drdp_col);CHKERRQ(ierr);
1152     }
1153   }
1154   ts->vecs_sensi         = NULL;
1155   ts->vecs_sensip        = NULL;
1156   ts->vecs_sensi2        = NULL;
1157   ts->vecs_sensi2p       = NULL;
1158   ts->vec_dir            = NULL;
1159   ts->adjointsetupcalled = PETSC_FALSE;
1160   PetscFunctionReturn(0);
1161 }
1162 
1163 /*@
1164    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time
1165 
1166    Logically Collective on TS
1167 
1168    Input Parameters:
1169 +  ts - the TS context obtained from TSCreate()
1170 .  steps - number of steps to use
1171 
1172    Level: intermediate
1173 
1174    Notes:
1175     Normally one does not call this and TSAdjointSolve() integrates back to the original timestep. One can call this
1176           so as to integrate back to less than the original timestep
1177 
1178 .keywords: TS, timestep, set, maximum, iterations
1179 
1180 .seealso: TSSetExactFinalTime()
1181 @*/
1182 PetscErrorCode TSAdjointSetSteps(TS ts,PetscInt steps)
1183 {
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1186   PetscValidLogicalCollectiveInt(ts,steps,2);
1187   if (steps < 0) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back a negative number of steps");
1188   if (steps > ts->steps) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back more than the total number of forward steps");
1189   ts->adjoint_max_steps = steps;
1190   PetscFunctionReturn(0);
1191 }
1192 
1193 /*@C
1194   TSAdjointSetRHSJacobian - Deprecated, use TSSetRHSJacobianP()
1195 
1196   Level: deprecated
1197 
1198 @*/
1199 PetscErrorCode TSAdjointSetRHSJacobian(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
1200 {
1201   PetscErrorCode ierr;
1202 
1203   PetscFunctionBegin;
1204   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1205   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
1206 
1207   ts->rhsjacobianp    = func;
1208   ts->rhsjacobianpctx = ctx;
1209   if(Amat) {
1210     ierr = PetscObjectReference((PetscObject)Amat);CHKERRQ(ierr);
1211     ierr = MatDestroy(&ts->Jacp);CHKERRQ(ierr);
1212     ts->Jacp = Amat;
1213   }
1214   PetscFunctionReturn(0);
1215 }
1216 
1217 /*@C
1218   TSAdjointComputeRHSJacobian - Deprecated, use TSComputeRHSJacobianP()
1219 
1220   Level: deprecated
1221 
1222 @*/
1223 PetscErrorCode TSAdjointComputeRHSJacobian(TS ts,PetscReal t,Vec U,Mat Amat)
1224 {
1225   PetscErrorCode ierr;
1226 
1227   PetscFunctionBegin;
1228   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1229   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1230   PetscValidPointer(Amat,4);
1231 
1232   PetscStackPush("TS user JacobianP function for sensitivity analysis");
1233   ierr = (*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx); CHKERRQ(ierr);
1234   PetscStackPop;
1235   PetscFunctionReturn(0);
1236 }
1237 
1238 /*@
1239   TSAdjointComputeDRDYFunction - Deprecated, use TSComputeDRDUFunction()
1240 
1241   Level: deprecated
1242 
1243 @*/
1244 PetscErrorCode TSAdjointComputeDRDYFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
1245 {
1246   PetscErrorCode ierr;
1247 
1248   PetscFunctionBegin;
1249   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1250   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1251 
1252   PetscStackPush("TS user DRDY function for sensitivity analysis");
1253   ierr = (*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx); CHKERRQ(ierr);
1254   PetscStackPop;
1255   PetscFunctionReturn(0);
1256 }
1257 
1258 /*@
1259   TSAdjointComputeDRDPFunction - Deprecated, use TSComputeDRDPFunction()
1260 
1261   Level: deprecated
1262 
1263 @*/
1264 PetscErrorCode TSAdjointComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
1265 {
1266   PetscErrorCode ierr;
1267 
1268   PetscFunctionBegin;
1269   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1270   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1271 
1272   PetscStackPush("TS user DRDP function for sensitivity analysis");
1273   ierr = (*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx); CHKERRQ(ierr);
1274   PetscStackPop;
1275   PetscFunctionReturn(0);
1276 }
1277 
1278 /*@C
1279    TSAdjointMonitorSensi - monitors the first lambda sensitivity
1280 
1281    Level: intermediate
1282 
1283 .keywords: TS, set, monitor
1284 
1285 .seealso: TSAdjointMonitorSet()
1286 @*/
1287 PetscErrorCode TSAdjointMonitorSensi(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
1288 {
1289   PetscErrorCode ierr;
1290   PetscViewer    viewer = vf->viewer;
1291 
1292   PetscFunctionBegin;
1293   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
1294   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
1295   ierr = VecView(lambda[0],viewer);CHKERRQ(ierr);
1296   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1297   PetscFunctionReturn(0);
1298 }
1299 
1300 /*@C
1301    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
1302 
1303    Collective on TS
1304 
1305    Input Parameters:
1306 +  ts - TS object you wish to monitor
1307 .  name - the monitor type one is seeking
1308 .  help - message indicating what monitoring is done
1309 .  manual - manual page for the monitor
1310 .  monitor - the monitor function
1311 -  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
1312 
1313    Level: developer
1314 
1315 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
1316           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
1317           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
1318           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
1319           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
1320           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
1321           PetscOptionsFList(), PetscOptionsEList()
1322 @*/
1323 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*))
1324 {
1325   PetscErrorCode    ierr;
1326   PetscViewer       viewer;
1327   PetscViewerFormat format;
1328   PetscBool         flg;
1329 
1330   PetscFunctionBegin;
1331   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts),((PetscObject) ts)->options,((PetscObject)ts)->prefix,name,&viewer,&format,&flg);CHKERRQ(ierr);
1332   if (flg) {
1333     PetscViewerAndFormat *vf;
1334     ierr = PetscViewerAndFormatCreate(viewer,format,&vf);CHKERRQ(ierr);
1335     ierr = PetscObjectDereference((PetscObject)viewer);CHKERRQ(ierr);
1336     if (monitorsetup) {
1337       ierr = (*monitorsetup)(ts,vf);CHKERRQ(ierr);
1338     }
1339     ierr = TSAdjointMonitorSet(ts,(PetscErrorCode (*)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*))monitor,vf,(PetscErrorCode (*)(void**))PetscViewerAndFormatDestroy);CHKERRQ(ierr);
1340   }
1341   PetscFunctionReturn(0);
1342 }
1343 
1344 /*@C
1345    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
1346    timestep to display the iteration's  progress.
1347 
1348    Logically Collective on TS
1349 
1350    Input Parameters:
1351 +  ts - the TS context obtained from TSCreate()
1352 .  adjointmonitor - monitoring routine
1353 .  adjointmctx - [optional] user-defined context for private data for the
1354              monitor routine (use NULL if no context is desired)
1355 -  adjointmonitordestroy - [optional] routine that frees monitor context
1356           (may be NULL)
1357 
1358    Calling sequence of monitor:
1359 $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)
1360 
1361 +    ts - the TS context
1362 .    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
1363                                been interpolated to)
1364 .    time - current time
1365 .    u - current iterate
1366 .    numcost - number of cost functionos
1367 .    lambda - sensitivities to initial conditions
1368 .    mu - sensitivities to parameters
1369 -    adjointmctx - [optional] adjoint monitoring context
1370 
1371    Notes:
1372    This routine adds an additional monitor to the list of monitors that
1373    already has been loaded.
1374 
1375    Fortran Notes:
1376     Only a single monitor function can be set for each TS object
1377 
1378    Level: intermediate
1379 
1380 .keywords: TS, timestep, set, adjoint, monitor
1381 
1382 .seealso: TSAdjointMonitorCancel()
1383 @*/
1384 PetscErrorCode TSAdjointMonitorSet(TS ts,PetscErrorCode (*adjointmonitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*),void *adjointmctx,PetscErrorCode (*adjointmdestroy)(void**))
1385 {
1386   PetscErrorCode ierr;
1387   PetscInt       i;
1388   PetscBool      identical;
1389 
1390   PetscFunctionBegin;
1391   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1392   for (i=0; i<ts->numbermonitors;i++) {
1393     ierr = PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor,adjointmctx,adjointmdestroy,(PetscErrorCode (*)(void))ts->adjointmonitor[i],ts->adjointmonitorcontext[i],ts->adjointmonitordestroy[i],&identical);CHKERRQ(ierr);
1394     if (identical) PetscFunctionReturn(0);
1395   }
1396   if (ts->numberadjointmonitors >= MAXTSMONITORS) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many adjoint monitors set");
1397   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
1398   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
1399   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void*)adjointmctx;
1400   PetscFunctionReturn(0);
1401 }
1402 
1403 /*@C
1404    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.
1405 
1406    Logically Collective on TS
1407 
1408    Input Parameters:
1409 .  ts - the TS context obtained from TSCreate()
1410 
1411    Notes:
1412    There is no way to remove a single, specific monitor.
1413 
1414    Level: intermediate
1415 
1416 .keywords: TS, timestep, set, adjoint, monitor
1417 
1418 .seealso: TSAdjointMonitorSet()
1419 @*/
1420 PetscErrorCode TSAdjointMonitorCancel(TS ts)
1421 {
1422   PetscErrorCode ierr;
1423   PetscInt       i;
1424 
1425   PetscFunctionBegin;
1426   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1427   for (i=0; i<ts->numberadjointmonitors; i++) {
1428     if (ts->adjointmonitordestroy[i]) {
1429       ierr = (*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
1430     }
1431   }
1432   ts->numberadjointmonitors = 0;
1433   PetscFunctionReturn(0);
1434 }
1435 
1436 /*@C
1437    TSAdjointMonitorDefault - the default monitor of adjoint computations
1438 
1439    Level: intermediate
1440 
1441 .keywords: TS, set, monitor
1442 
1443 .seealso: TSAdjointMonitorSet()
1444 @*/
1445 PetscErrorCode TSAdjointMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
1446 {
1447   PetscErrorCode ierr;
1448   PetscViewer    viewer = vf->viewer;
1449 
1450   PetscFunctionBegin;
1451   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
1452   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
1453   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1454   ierr = PetscViewerASCIIPrintf(viewer,"%D TS dt %g time %g%s",step,(double)ts->time_step,(double)ptime,ts->steprollback ? " (r)\n" : "\n");CHKERRQ(ierr);
1455   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1456   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1457   PetscFunctionReturn(0);
1458 }
1459 
1460 /*@C
1461    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint TS solvers by calling
1462    VecView() for the sensitivities to initial states at each timestep
1463 
1464    Collective on TS
1465 
1466    Input Parameters:
1467 +  ts - the TS context
1468 .  step - current time-step
1469 .  ptime - current time
1470 .  u - current state
1471 .  numcost - number of cost functions
1472 .  lambda - sensitivities to initial conditions
1473 .  mu - sensitivities to parameters
1474 -  dummy - either a viewer or NULL
1475 
1476    Level: intermediate
1477 
1478 .keywords: TS,  vector, adjoint, monitor, view
1479 
1480 .seealso: TSAdjointMonitorSet(), TSAdjointMonitorDefault(), VecView()
1481 @*/
1482 PetscErrorCode TSAdjointMonitorDrawSensi(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda,Vec *mu,void *dummy)
1483 {
1484   PetscErrorCode   ierr;
1485   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
1486   PetscDraw        draw;
1487   PetscReal        xl,yl,xr,yr,h;
1488   char             time[32];
1489 
1490   PetscFunctionBegin;
1491   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
1492 
1493   ierr = VecView(lambda[0],ictx->viewer);CHKERRQ(ierr);
1494   ierr = PetscViewerDrawGetDraw(ictx->viewer,0,&draw);CHKERRQ(ierr);
1495   ierr = PetscSNPrintf(time,32,"Timestep %d Time %g",(int)step,(double)ptime);CHKERRQ(ierr);
1496   ierr = PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr);CHKERRQ(ierr);
1497   h    = yl + .95*(yr - yl);
1498   ierr = PetscDrawStringCentered(draw,.5*(xl+xr),h,PETSC_DRAW_BLACK,time);CHKERRQ(ierr);
1499   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1500   PetscFunctionReturn(0);
1501 }
1502 
1503 /*
1504    TSAdjointSetFromOptions - Sets various TSAdjoint parameters from user options.
1505 
1506    Collective on TSAdjoint
1507 
1508    Input Parameter:
1509 .  ts - the TS context
1510 
1511    Options Database Keys:
1512 +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
1513 .  -ts_adjoint_monitor - print information at each adjoint time step
1514 -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically
1515 
1516    Level: developer
1517 
1518    Notes:
1519     This is not normally called directly by users
1520 
1521 .keywords: TS, trajectory, timestep, set, options, database
1522 
1523 .seealso: TSSetSaveTrajectory(), TSTrajectorySetUp()
1524 */
1525 PetscErrorCode TSAdjointSetFromOptions(PetscOptionItems *PetscOptionsObject,TS ts)
1526 {
1527   PetscBool      tflg,opt;
1528   PetscErrorCode ierr;
1529 
1530   PetscFunctionBegin;
1531   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
1532   ierr = PetscOptionsHead(PetscOptionsObject,"TS Adjoint options");CHKERRQ(ierr);
1533   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
1534   ierr = PetscOptionsBool("-ts_adjoint_solve","Solve the adjoint problem immediately after solving the forward problem","",tflg,&tflg,&opt);CHKERRQ(ierr);
1535   if (opt) {
1536     ierr = TSSetSaveTrajectory(ts);CHKERRQ(ierr);
1537     ts->adjoint_solve = tflg;
1538   }
1539   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor","Monitor adjoint timestep size","TSAdjointMonitorDefault",TSAdjointMonitorDefault,NULL);CHKERRQ(ierr);
1540   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor_sensi","Monitor sensitivity in the adjoint computation","TSAdjointMonitorSensi",TSAdjointMonitorSensi,NULL);CHKERRQ(ierr);
1541   opt  = PETSC_FALSE;
1542   ierr = PetscOptionsName("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",&opt);CHKERRQ(ierr);
1543   if (opt) {
1544     TSMonitorDrawCtx ctx;
1545     PetscInt         howoften = 1;
1546 
1547     ierr = PetscOptionsInt("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",howoften,&howoften,NULL);CHKERRQ(ierr);
1548     ierr = TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts),0,0,PETSC_DECIDE,PETSC_DECIDE,300,300,howoften,&ctx);CHKERRQ(ierr);
1549     ierr = TSAdjointMonitorSet(ts,TSAdjointMonitorDrawSensi,ctx,(PetscErrorCode (*)(void**))TSMonitorDrawCtxDestroy);CHKERRQ(ierr);
1550   }
1551   PetscFunctionReturn(0);
1552 }
1553 
1554 /*@
1555    TSAdjointStep - Steps one time step backward in the adjoint run
1556 
1557    Collective on TS
1558 
1559    Input Parameter:
1560 .  ts - the TS context obtained from TSCreate()
1561 
1562    Level: intermediate
1563 
1564 .keywords: TS, adjoint, step
1565 
1566 .seealso: TSAdjointSetUp(), TSAdjointSolve()
1567 @*/
1568 PetscErrorCode TSAdjointStep(TS ts)
1569 {
1570   DM               dm;
1571   PetscErrorCode   ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1575   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
1576   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1577 
1578   ts->reason = TS_CONVERGED_ITERATING;
1579   ts->ptime_prev = ts->ptime;
1580   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);
1581   ierr = PetscLogEventBegin(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1582   ierr = (*ts->ops->adjointstep)(ts);CHKERRQ(ierr);
1583   ierr = PetscLogEventEnd(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1584   ts->adjoint_steps++; ts->steps--;
1585 
1586   if (ts->reason < 0) {
1587     if (ts->errorifstepfailed) {
1588       if (ts->reason == TSADJOINT_DIVERGED_LINEAR_SOLVE) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1589       else SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1590     }
1591   } else if (!ts->reason) {
1592     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1593   }
1594   PetscFunctionReturn(0);
1595 }
1596 
1597 /*@
1598    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE
1599 
1600    Collective on TS
1601 
1602    Input Parameter:
1603 .  ts - the TS context obtained from TSCreate()
1604 
1605    Options Database:
1606 . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values
1607 
1608    Level: intermediate
1609 
1610    Notes:
1611    This must be called after a call to TSSolve() that solves the forward problem
1612 
1613    By default this will integrate back to the initial time, one can use TSAdjointSetSteps() to step back to a later time
1614 
1615 .keywords: TS, timestep, solve
1616 
1617 .seealso: TSCreate(), TSSetCostGradients(), TSSetSolution(), TSAdjointStep()
1618 @*/
1619 PetscErrorCode TSAdjointSolve(TS ts)
1620 {
1621   PetscErrorCode    ierr;
1622 
1623   PetscFunctionBegin;
1624   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1625   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1626 
1627   /* reset time step and iteration counters */
1628   ts->adjoint_steps     = 0;
1629   ts->ksp_its           = 0;
1630   ts->snes_its          = 0;
1631   ts->num_snes_failures = 0;
1632   ts->reject            = 0;
1633   ts->reason            = TS_CONVERGED_ITERATING;
1634 
1635   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
1636   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1637 
1638   while (!ts->reason) {
1639     ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1640     ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1641     ierr = TSAdjointEventHandler(ts);CHKERRQ(ierr);
1642     ierr = TSAdjointStep(ts);CHKERRQ(ierr);
1643     if ((ts->vec_costintegral || ts->quadraturets) && !ts->costintegralfwd) {
1644       ierr = TSAdjointCostIntegral(ts);CHKERRQ(ierr);
1645     }
1646   }
1647   ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1648   ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1649   ts->solvetime = ts->ptime;
1650   ierr = TSTrajectoryViewFromOptions(ts->trajectory,NULL,"-ts_trajectory_view");CHKERRQ(ierr);
1651   ierr = VecViewFromOptions(ts->vecs_sensi[0],(PetscObject) ts, "-ts_adjoint_view_solution");CHKERRQ(ierr);
1652   ts->adjoint_max_steps = 0;
1653   PetscFunctionReturn(0);
1654 }
1655 
1656 /*@C
1657    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using TSAdjointMonitorSet()
1658 
1659    Collective on TS
1660 
1661    Input Parameters:
1662 +  ts - time stepping context obtained from TSCreate()
1663 .  step - step number that has just completed
1664 .  ptime - model time of the state
1665 .  u - state at the current model time
1666 .  numcost - number of cost functions (dimension of lambda  or mu)
1667 .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
1668 -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
1669 
1670    Notes:
1671    TSAdjointMonitor() is typically used automatically within the time stepping implementations.
1672    Users would almost never call this routine directly.
1673 
1674    Level: developer
1675 
1676 .keywords: TS, timestep
1677 @*/
1678 PetscErrorCode TSAdjointMonitor(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda, Vec *mu)
1679 {
1680   PetscErrorCode ierr;
1681   PetscInt       i,n = ts->numberadjointmonitors;
1682 
1683   PetscFunctionBegin;
1684   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1685   PetscValidHeaderSpecific(u,VEC_CLASSID,4);
1686   ierr = VecLockReadPush(u);CHKERRQ(ierr);
1687   for (i=0; i<n; i++) {
1688     ierr = (*ts->adjointmonitor[i])(ts,step,ptime,u,numcost,lambda,mu,ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
1689   }
1690   ierr = VecLockReadPop(u);CHKERRQ(ierr);
1691   PetscFunctionReturn(0);
1692 }
1693 
1694 /*@
1695  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.
1696 
1697  Collective on TS
1698 
1699  Input Arguments:
1700  .  ts - time stepping context
1701 
1702  Level: advanced
1703 
1704  Notes:
1705  This function cannot be called until TSAdjointStep() has been completed.
1706 
1707  .seealso: TSAdjointSolve(), TSAdjointStep
1708  @*/
1709 PetscErrorCode TSAdjointCostIntegral(TS ts)
1710 {
1711     PetscErrorCode ierr;
1712     PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1713     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);
1714     ierr = (*ts->ops->adjointintegral)(ts);CHKERRQ(ierr);
1715     PetscFunctionReturn(0);
1716 }
1717 
1718 /* ------------------ Forward (tangent linear) sensitivity  ------------------*/
1719 
1720 /*@
1721   TSForwardSetUp - Sets up the internal data structures for the later use
1722   of forward sensitivity analysis
1723 
1724   Collective on TS
1725 
1726   Input Parameter:
1727 . ts - the TS context obtained from TSCreate()
1728 
1729   Level: advanced
1730 
1731 .keywords: TS, forward sensitivity, setup
1732 
1733 .seealso: TSCreate(), TSDestroy(), TSSetUp()
1734 @*/
1735 PetscErrorCode TSForwardSetUp(TS ts)
1736 {
1737   PetscErrorCode ierr;
1738 
1739   PetscFunctionBegin;
1740   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1741   if (ts->forwardsetupcalled) PetscFunctionReturn(0);
1742   if (!ts->Jacp && ts->Jacprhs) ts->Jacp = ts->Jacprhs;
1743 
1744   if (ts->ops->forwardsetup) {
1745     ierr = (*ts->ops->forwardsetup)(ts);CHKERRQ(ierr);
1746   }
1747   ierr = VecDuplicate(ts->vec_sol,&ts->vec_sensip_col);CHKERRQ(ierr);
1748   ts->forwardsetupcalled = PETSC_TRUE;
1749   PetscFunctionReturn(0);
1750 }
1751 
1752 /*@
1753   TSForwardReset - Reset the internal data structures used by forward sensitivity analysis
1754 
1755   Collective on TS
1756 
1757   Input Parameter:
1758 . ts - the TS context obtained from TSCreate()
1759 
1760   Level: advanced
1761 
1762 .keywords: TS, forward sensitivity, reset
1763 
1764 .seealso: TSCreate(), TSDestroy(), TSForwardSetUp()
1765 @*/
1766 PetscErrorCode TSForwardReset(TS ts)
1767 {
1768   TS             quadts = ts->quadraturets;
1769   PetscErrorCode ierr;
1770 
1771   PetscFunctionBegin;
1772   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1773   if (ts->ops->forwardreset) {
1774     ierr = (*ts->ops->forwardreset)(ts);CHKERRQ(ierr);
1775   }
1776   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1777   if (quadts) {
1778     ierr = MatDestroy(&quadts->mat_sensip);CHKERRQ(ierr);
1779   }
1780   ierr = VecDestroy(&ts->vec_sensip_col);CHKERRQ(ierr);
1781   ts->forward_solve      = PETSC_FALSE;
1782   ts->forwardsetupcalled = PETSC_FALSE;
1783   PetscFunctionReturn(0);
1784 }
1785 
1786 /*@
1787   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.
1788 
1789   Input Parameter:
1790 . ts- the TS context obtained from TSCreate()
1791 . numfwdint- number of integrals
1792 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1793 
1794   Level: deprecated
1795 
1796 .keywords: TS, forward sensitivity
1797 
1798 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1799 @*/
1800 PetscErrorCode TSForwardSetIntegralGradients(TS ts,PetscInt numfwdint,Vec *vp)
1801 {
1802   PetscFunctionBegin;
1803   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1804   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()");
1805   if (!ts->numcost) ts->numcost = numfwdint;
1806 
1807   ts->vecs_integral_sensip = vp;
1808   PetscFunctionReturn(0);
1809 }
1810 
1811 /*@
1812   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.
1813 
1814   Input Parameter:
1815 . ts- the TS context obtained from TSCreate()
1816 
1817   Output Parameter:
1818 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1819 
1820   Level: deprecated
1821 
1822 .keywords: TS, forward sensitivity
1823 
1824 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1825 @*/
1826 PetscErrorCode TSForwardGetIntegralGradients(TS ts,PetscInt *numfwdint,Vec **vp)
1827 {
1828   PetscFunctionBegin;
1829   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1830   PetscValidPointer(vp,3);
1831   if (numfwdint) *numfwdint = ts->numcost;
1832   if (vp) *vp = ts->vecs_integral_sensip;
1833   PetscFunctionReturn(0);
1834 }
1835 
1836 /*@
1837   TSForwardStep - Compute the forward sensitivity for one time step.
1838 
1839   Collective on TS
1840 
1841   Input Arguments:
1842 . ts - time stepping context
1843 
1844   Level: advanced
1845 
1846   Notes:
1847   This function cannot be called until TSStep() has been completed.
1848 
1849 .keywords: TS, forward sensitivity
1850 
1851 .seealso: TSForwardSetSensitivities(), TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardSetUp()
1852 @*/
1853 PetscErrorCode TSForwardStep(TS ts)
1854 {
1855   PetscErrorCode ierr;
1856   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1857   if (!ts->ops->forwardstep) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide forward sensitivity analysis",((PetscObject)ts)->type_name);
1858   ierr = PetscLogEventBegin(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1859   ierr = (*ts->ops->forwardstep)(ts);CHKERRQ(ierr);
1860   ierr = PetscLogEventEnd(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1861   PetscFunctionReturn(0);
1862 }
1863 
1864 /*@
1865   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.
1866 
1867   Logically Collective on TS and Vec
1868 
1869   Input Parameters:
1870 + ts - the TS context obtained from TSCreate()
1871 . nump - number of parameters
1872 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1873 
1874   Level: beginner
1875 
1876   Notes:
1877   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
1878   This function turns on a flag to trigger TSSolve() to compute forward sensitivities automatically.
1879   You must call this function before TSSolve().
1880   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.
1881 
1882 .keywords: TS, timestep, set, forward sensitivity, initial values
1883 
1884 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1885 @*/
1886 PetscErrorCode TSForwardSetSensitivities(TS ts,PetscInt nump,Mat Smat)
1887 {
1888   PetscErrorCode ierr;
1889 
1890   PetscFunctionBegin;
1891   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1892   PetscValidHeaderSpecific(Smat,MAT_CLASSID,3);
1893   ts->forward_solve  = PETSC_TRUE;
1894   if (nump == PETSC_DEFAULT) {
1895     ierr = MatGetSize(Smat,NULL,&ts->num_parameters);CHKERRQ(ierr);
1896   } else ts->num_parameters = nump;
1897   ierr = PetscObjectReference((PetscObject)Smat);CHKERRQ(ierr);
1898   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1899   ts->mat_sensip = Smat;
1900   PetscFunctionReturn(0);
1901 }
1902 
1903 /*@
1904   TSForwardGetSensitivities - Returns the trajectory sensitivities
1905 
1906   Not Collective, but Vec returned is parallel if TS is parallel
1907 
1908   Output Parameter:
1909 + ts - the TS context obtained from TSCreate()
1910 . nump - number of parameters
1911 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1912 
1913   Level: intermediate
1914 
1915 .keywords: TS, forward sensitivity
1916 
1917 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1918 @*/
1919 PetscErrorCode TSForwardGetSensitivities(TS ts,PetscInt *nump,Mat *Smat)
1920 {
1921   PetscFunctionBegin;
1922   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1923   if (nump) *nump = ts->num_parameters;
1924   if (Smat) *Smat = ts->mat_sensip;
1925   PetscFunctionReturn(0);
1926 }
1927 
1928 /*@
1929    TSForwardCostIntegral - Evaluate the cost integral in the forward run.
1930 
1931    Collective on TS
1932 
1933    Input Arguments:
1934 .  ts - time stepping context
1935 
1936    Level: advanced
1937 
1938    Notes:
1939    This function cannot be called until TSStep() has been completed.
1940 
1941 .seealso: TSSolve(), TSAdjointCostIntegral()
1942 @*/
1943 PetscErrorCode TSForwardCostIntegral(TS ts)
1944 {
1945   PetscErrorCode ierr;
1946   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1947   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);
1948   ierr = (*ts->ops->forwardintegral)(ts);CHKERRQ(ierr);
1949   PetscFunctionReturn(0);
1950 }
1951 
1952 /*@
1953   TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities
1954 
1955   Collective on TS and Mat
1956 
1957   Input Parameter
1958 + ts - the TS context obtained from TSCreate()
1959 - didp - parametric sensitivities of the initial condition
1960 
1961   Level: intermediate
1962 
1963   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.
1964 
1965 .seealso: TSForwardSetSensitivities()
1966 @*/
1967 PetscErrorCode TSForwardSetInitialSensitivities(TS ts,Mat didp)
1968 {
1969   PetscErrorCode ierr;
1970 
1971   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1972   PetscValidHeaderSpecific(didp,MAT_CLASSID,2);
1973   if (!ts->mat_sensip) {
1974     ierr = TSForwardSetSensitivities(ts,PETSC_DEFAULT,didp);CHKERRQ(ierr);
1975   }
1976   PetscFunctionReturn(0);
1977 }
1978 
1979 /*@
1980    TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages
1981 
1982    Input Parameter:
1983 .  ts - the TS context obtained from TSCreate()
1984 
1985    Output Parameters:
1986 +  ns - number of stages
1987 -  S - tangent linear sensitivities at the intermediate stages
1988 
1989    Level: advanced
1990 
1991 .keywords: TS, second-order adjoint, forward sensitivity
1992 @*/
1993 PetscErrorCode TSForwardGetStages(TS ts,PetscInt *ns,Mat **S)
1994 {
1995   PetscErrorCode ierr;
1996 
1997   PetscFunctionBegin;
1998   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1999 
2000   if (!ts->ops->getstages) *S=NULL;
2001   else {
2002     ierr = (*ts->ops->forwardgetstages)(ts,ns,S);CHKERRQ(ierr);
2003   }
2004   PetscFunctionReturn(0);
2005 }
2006 
2007 /*@
2008    TSCreateQuadratureTS - Create a sub-TS that evaluates integrals over time
2009 
2010    Input Parameter:
2011 +  ts - the TS context obtained from TSCreate()
2012 -  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
2013 
2014    Output Parameters:
2015 .  quadts - the child TS context
2016 
2017    Level: intermediate
2018 
2019 .keywords: TS, quadrature evaluation
2020 
2021 .seealso: TSGetQuadratureTS()
2022 @*/
2023 PetscErrorCode TSCreateQuadratureTS(TS ts,PetscBool fwd,TS *quadts)
2024 {
2025   char prefix[128];
2026   PetscErrorCode ierr;
2027 
2028   PetscFunctionBegin;
2029   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
2030   PetscValidPointer(quadts,2);
2031   ierr = TSDestroy(&ts->quadraturets);CHKERRQ(ierr);
2032   ierr = TSCreate(PetscObjectComm((PetscObject)ts),&ts->quadraturets);CHKERRQ(ierr);
2033   ierr = PetscObjectIncrementTabLevel((PetscObject)ts->quadraturets,(PetscObject)ts,1);CHKERRQ(ierr);
2034   ierr = PetscLogObjectParent((PetscObject)ts,(PetscObject)ts->quadraturets);CHKERRQ(ierr);
2035   ierr = PetscSNPrintf(prefix,sizeof(prefix),"%squad_",((PetscObject)ts)->prefix ? ((PetscObject)ts)->prefix : "");CHKERRQ(ierr);
2036   ierr = TSSetOptionsPrefix(ts->quadraturets,prefix);CHKERRQ(ierr);
2037   *quadts = ts->quadraturets;
2038 
2039   if (ts->numcost) {
2040     ierr = VecCreateSeq(PETSC_COMM_SELF,ts->numcost,&(*quadts)->vec_sol);CHKERRQ(ierr);
2041   } else {
2042     ierr = VecCreateSeq(PETSC_COMM_SELF,1,&(*quadts)->vec_sol);CHKERRQ(ierr);
2043   }
2044   ts->costintegralfwd = fwd;
2045   PetscFunctionReturn(0);
2046 }
2047 
2048 /*@
2049    TSGetQuadratureTS - Return the sub-TS that evaluates integrals over time
2050 
2051    Input Parameter:
2052 .  ts - the TS context obtained from TSCreate()
2053 
2054    Output Parameters:
2055 +  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
2056 -  quadts - the child TS context
2057 
2058    Level: intermediate
2059 
2060 .keywords: TS, quadrature evaluation
2061 
2062 .seealso: TSCreateQuadratureTS()
2063 @*/
2064 PetscErrorCode TSGetQuadratureTS(TS ts,PetscBool *fwd,TS *quadts)
2065 {
2066   PetscFunctionBegin;
2067   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
2068   if (fwd) *fwd = ts->costintegralfwd;
2069   if (quadts) *quadts = ts->quadraturets;
2070   PetscFunctionReturn(0);
2071 }
2072