xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 7207e0fd75b109fc2c7cc00f1ac529e33c8e3bb1)
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 TSAdjointInitializeForward() 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: TSAdjointInitializeForward()
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   TSAdjointInitializeForward - 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.
1005 
1006 .keywords: TS, sensitivity, second-order adjoint
1007 
1008 .seealso: TSSetCostHessianProducts()
1009 @*/
1010 PetscErrorCode TSAdjointInitializeForward(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(PETSC_COMM_WORLD,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) { /* TLM 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 { /* TLM 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    TSAdjointSetUp - Sets up the internal data structures for the later use
1051    of an adjoint solver
1052 
1053    Collective on TS
1054 
1055    Input Parameter:
1056 .  ts - the TS context obtained from TSCreate()
1057 
1058    Level: advanced
1059 
1060 .keywords: TS, timestep, setup
1061 
1062 .seealso: TSCreate(), TSAdjointStep(), TSSetCostGradients()
1063 @*/
1064 PetscErrorCode TSAdjointSetUp(TS ts)
1065 {
1066   PetscErrorCode ierr;
1067 
1068   PetscFunctionBegin;
1069   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1070   if (ts->adjointsetupcalled) PetscFunctionReturn(0);
1071   if (!ts->vecs_sensi) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetCostGradients() first");
1072   if (ts->vecs_sensip && !ts->Jacp && !ts->Jacprhs) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetRHSJacobianP() or TSSetIJacobianP() first");
1073 
1074   if (!ts->Jacp && ts->Jacprhs) ts->Jacp = ts->Jacprhs;
1075 
1076   if (ts->quadraturets) { /* if there is integral in the cost function */
1077     ierr = VecDuplicate(ts->vecs_sensi[0],&ts->vec_drdu_col);CHKERRQ(ierr);
1078     if (ts->vecs_sensip){
1079       ierr = VecDuplicate(ts->vecs_sensip[0],&ts->vec_drdp_col);CHKERRQ(ierr);
1080     }
1081   }
1082 
1083   if (ts->ops->adjointsetup) {
1084     ierr = (*ts->ops->adjointsetup)(ts);CHKERRQ(ierr);
1085   }
1086   ts->adjointsetupcalled = PETSC_TRUE;
1087   PetscFunctionReturn(0);
1088 }
1089 
1090 /*@
1091    TSAdjointReset - Resets a TSAdjoint context and removes any allocated Vecs and Mats.
1092 
1093    Collective on TS
1094 
1095    Input Parameter:
1096 .  ts - the TS context obtained from TSCreate()
1097 
1098    Level: beginner
1099 
1100 .keywords: TS, timestep, reset
1101 
1102 .seealso: TSCreate(), TSAdjointSetup(), TSADestroy()
1103 @*/
1104 PetscErrorCode TSAdjointReset(TS ts)
1105 {
1106   PetscErrorCode ierr;
1107 
1108   PetscFunctionBegin;
1109   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1110   if (ts->ops->adjointreset) {
1111     ierr = (*ts->ops->adjointreset)(ts);CHKERRQ(ierr);
1112   }
1113   if (ts->quadraturets) { /* if there is integral in the cost function */
1114     ierr = VecDestroy(&ts->vec_drdu_col);CHKERRQ(ierr);
1115     if (ts->vecs_sensip){
1116       ierr = VecDestroy(&ts->vec_drdp_col);CHKERRQ(ierr);
1117     }
1118   }
1119   if (ts->vec_dir) { /* second-order adjoint */
1120     ierr = TSForwardReset(ts);CHKERRQ(ierr);
1121   }
1122   ts->vecs_sensi         = NULL;
1123   ts->vecs_sensip        = NULL;
1124   ts->vecs_sensi2        = NULL;
1125   ts->vecs_sensi2p       = NULL;
1126   ts->vec_dir            = NULL;
1127   ts->adjointsetupcalled = PETSC_FALSE;
1128   PetscFunctionReturn(0);
1129 }
1130 
1131 /*@
1132    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time
1133 
1134    Logically Collective on TS
1135 
1136    Input Parameters:
1137 +  ts - the TS context obtained from TSCreate()
1138 .  steps - number of steps to use
1139 
1140    Level: intermediate
1141 
1142    Notes:
1143     Normally one does not call this and TSAdjointSolve() integrates back to the original timestep. One can call this
1144           so as to integrate back to less than the original timestep
1145 
1146 .keywords: TS, timestep, set, maximum, iterations
1147 
1148 .seealso: TSSetExactFinalTime()
1149 @*/
1150 PetscErrorCode TSAdjointSetSteps(TS ts,PetscInt steps)
1151 {
1152   PetscFunctionBegin;
1153   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1154   PetscValidLogicalCollectiveInt(ts,steps,2);
1155   if (steps < 0) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back a negative number of steps");
1156   if (steps > ts->steps) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back more than the total number of forward steps");
1157   ts->adjoint_max_steps = steps;
1158   PetscFunctionReturn(0);
1159 }
1160 
1161 /*@C
1162   TSAdjointSetRHSJacobian - Deprecated, use TSSetRHSJacobianP()
1163 
1164   Level: deprecated
1165 
1166 @*/
1167 PetscErrorCode TSAdjointSetRHSJacobian(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
1168 {
1169   PetscErrorCode ierr;
1170 
1171   PetscFunctionBegin;
1172   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1173   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
1174 
1175   ts->rhsjacobianp    = func;
1176   ts->rhsjacobianpctx = ctx;
1177   if(Amat) {
1178     ierr = PetscObjectReference((PetscObject)Amat);CHKERRQ(ierr);
1179     ierr = MatDestroy(&ts->Jacp);CHKERRQ(ierr);
1180     ts->Jacp = Amat;
1181   }
1182   PetscFunctionReturn(0);
1183 }
1184 
1185 /*@C
1186   TSAdjointComputeRHSJacobian - Deprecated, use TSComputeRHSJacobianP()
1187 
1188   Level: deprecated
1189 
1190 @*/
1191 PetscErrorCode TSAdjointComputeRHSJacobian(TS ts,PetscReal t,Vec U,Mat Amat)
1192 {
1193   PetscErrorCode ierr;
1194 
1195   PetscFunctionBegin;
1196   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1197   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1198   PetscValidPointer(Amat,4);
1199 
1200   PetscStackPush("TS user JacobianP function for sensitivity analysis");
1201   ierr = (*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx); CHKERRQ(ierr);
1202   PetscStackPop;
1203   PetscFunctionReturn(0);
1204 }
1205 
1206 /*@
1207   TSAdjointComputeDRDYFunction - Deprecated, use TSComputeDRDUFunction()
1208 
1209   Level: deprecated
1210 
1211 @*/
1212 PetscErrorCode TSAdjointComputeDRDYFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
1213 {
1214   PetscErrorCode ierr;
1215 
1216   PetscFunctionBegin;
1217   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1218   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1219 
1220   PetscStackPush("TS user DRDY function for sensitivity analysis");
1221   ierr = (*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx); CHKERRQ(ierr);
1222   PetscStackPop;
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 /*@
1227   TSAdjointComputeDRDPFunction - Deprecated, use TSComputeDRDPFunction()
1228 
1229   Level: deprecated
1230 
1231 @*/
1232 PetscErrorCode TSAdjointComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
1233 {
1234   PetscErrorCode ierr;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1238   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1239 
1240   PetscStackPush("TS user DRDP function for sensitivity analysis");
1241   ierr = (*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx); CHKERRQ(ierr);
1242   PetscStackPop;
1243   PetscFunctionReturn(0);
1244 }
1245 
1246 /*@C
1247    TSAdjointMonitorSensi - monitors the first lambda sensitivity
1248 
1249    Level: intermediate
1250 
1251 .keywords: TS, set, monitor
1252 
1253 .seealso: TSAdjointMonitorSet()
1254 @*/
1255 PetscErrorCode TSAdjointMonitorSensi(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
1256 {
1257   PetscErrorCode ierr;
1258   PetscViewer    viewer = vf->viewer;
1259 
1260   PetscFunctionBegin;
1261   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
1262   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
1263   ierr = VecView(lambda[0],viewer);CHKERRQ(ierr);
1264   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 /*@C
1269    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
1270 
1271    Collective on TS
1272 
1273    Input Parameters:
1274 +  ts - TS object you wish to monitor
1275 .  name - the monitor type one is seeking
1276 .  help - message indicating what monitoring is done
1277 .  manual - manual page for the monitor
1278 .  monitor - the monitor function
1279 -  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
1280 
1281    Level: developer
1282 
1283 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
1284           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
1285           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
1286           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
1287           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
1288           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
1289           PetscOptionsFList(), PetscOptionsEList()
1290 @*/
1291 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*))
1292 {
1293   PetscErrorCode    ierr;
1294   PetscViewer       viewer;
1295   PetscViewerFormat format;
1296   PetscBool         flg;
1297 
1298   PetscFunctionBegin;
1299   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts),((PetscObject) ts)->options,((PetscObject)ts)->prefix,name,&viewer,&format,&flg);CHKERRQ(ierr);
1300   if (flg) {
1301     PetscViewerAndFormat *vf;
1302     ierr = PetscViewerAndFormatCreate(viewer,format,&vf);CHKERRQ(ierr);
1303     ierr = PetscObjectDereference((PetscObject)viewer);CHKERRQ(ierr);
1304     if (monitorsetup) {
1305       ierr = (*monitorsetup)(ts,vf);CHKERRQ(ierr);
1306     }
1307     ierr = TSAdjointMonitorSet(ts,(PetscErrorCode (*)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*))monitor,vf,(PetscErrorCode (*)(void**))PetscViewerAndFormatDestroy);CHKERRQ(ierr);
1308   }
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 /*@C
1313    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
1314    timestep to display the iteration's  progress.
1315 
1316    Logically Collective on TS
1317 
1318    Input Parameters:
1319 +  ts - the TS context obtained from TSCreate()
1320 .  adjointmonitor - monitoring routine
1321 .  adjointmctx - [optional] user-defined context for private data for the
1322              monitor routine (use NULL if no context is desired)
1323 -  adjointmonitordestroy - [optional] routine that frees monitor context
1324           (may be NULL)
1325 
1326    Calling sequence of monitor:
1327 $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)
1328 
1329 +    ts - the TS context
1330 .    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
1331                                been interpolated to)
1332 .    time - current time
1333 .    u - current iterate
1334 .    numcost - number of cost functionos
1335 .    lambda - sensitivities to initial conditions
1336 .    mu - sensitivities to parameters
1337 -    adjointmctx - [optional] adjoint monitoring context
1338 
1339    Notes:
1340    This routine adds an additional monitor to the list of monitors that
1341    already has been loaded.
1342 
1343    Fortran Notes:
1344     Only a single monitor function can be set for each TS object
1345 
1346    Level: intermediate
1347 
1348 .keywords: TS, timestep, set, adjoint, monitor
1349 
1350 .seealso: TSAdjointMonitorCancel()
1351 @*/
1352 PetscErrorCode TSAdjointMonitorSet(TS ts,PetscErrorCode (*adjointmonitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*),void *adjointmctx,PetscErrorCode (*adjointmdestroy)(void**))
1353 {
1354   PetscErrorCode ierr;
1355   PetscInt       i;
1356   PetscBool      identical;
1357 
1358   PetscFunctionBegin;
1359   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1360   for (i=0; i<ts->numbermonitors;i++) {
1361     ierr = PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor,adjointmctx,adjointmdestroy,(PetscErrorCode (*)(void))ts->adjointmonitor[i],ts->adjointmonitorcontext[i],ts->adjointmonitordestroy[i],&identical);CHKERRQ(ierr);
1362     if (identical) PetscFunctionReturn(0);
1363   }
1364   if (ts->numberadjointmonitors >= MAXTSMONITORS) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many adjoint monitors set");
1365   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
1366   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
1367   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void*)adjointmctx;
1368   PetscFunctionReturn(0);
1369 }
1370 
1371 /*@C
1372    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.
1373 
1374    Logically Collective on TS
1375 
1376    Input Parameters:
1377 .  ts - the TS context obtained from TSCreate()
1378 
1379    Notes:
1380    There is no way to remove a single, specific monitor.
1381 
1382    Level: intermediate
1383 
1384 .keywords: TS, timestep, set, adjoint, monitor
1385 
1386 .seealso: TSAdjointMonitorSet()
1387 @*/
1388 PetscErrorCode TSAdjointMonitorCancel(TS ts)
1389 {
1390   PetscErrorCode ierr;
1391   PetscInt       i;
1392 
1393   PetscFunctionBegin;
1394   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1395   for (i=0; i<ts->numberadjointmonitors; i++) {
1396     if (ts->adjointmonitordestroy[i]) {
1397       ierr = (*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
1398     }
1399   }
1400   ts->numberadjointmonitors = 0;
1401   PetscFunctionReturn(0);
1402 }
1403 
1404 /*@C
1405    TSAdjointMonitorDefault - the default monitor of adjoint computations
1406 
1407    Level: intermediate
1408 
1409 .keywords: TS, set, monitor
1410 
1411 .seealso: TSAdjointMonitorSet()
1412 @*/
1413 PetscErrorCode TSAdjointMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
1414 {
1415   PetscErrorCode ierr;
1416   PetscViewer    viewer = vf->viewer;
1417 
1418   PetscFunctionBegin;
1419   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
1420   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
1421   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1422   ierr = PetscViewerASCIIPrintf(viewer,"%D TS dt %g time %g%s",step,(double)ts->time_step,(double)ptime,ts->steprollback ? " (r)\n" : "\n");CHKERRQ(ierr);
1423   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1424   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1425   PetscFunctionReturn(0);
1426 }
1427 
1428 /*@C
1429    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint TS solvers by calling
1430    VecView() for the sensitivities to initial states at each timestep
1431 
1432    Collective on TS
1433 
1434    Input Parameters:
1435 +  ts - the TS context
1436 .  step - current time-step
1437 .  ptime - current time
1438 .  u - current state
1439 .  numcost - number of cost functions
1440 .  lambda - sensitivities to initial conditions
1441 .  mu - sensitivities to parameters
1442 -  dummy - either a viewer or NULL
1443 
1444    Level: intermediate
1445 
1446 .keywords: TS,  vector, adjoint, monitor, view
1447 
1448 .seealso: TSAdjointMonitorSet(), TSAdjointMonitorDefault(), VecView()
1449 @*/
1450 PetscErrorCode TSAdjointMonitorDrawSensi(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda,Vec *mu,void *dummy)
1451 {
1452   PetscErrorCode   ierr;
1453   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
1454   PetscDraw        draw;
1455   PetscReal        xl,yl,xr,yr,h;
1456   char             time[32];
1457 
1458   PetscFunctionBegin;
1459   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
1460 
1461   ierr = VecView(lambda[0],ictx->viewer);CHKERRQ(ierr);
1462   ierr = PetscViewerDrawGetDraw(ictx->viewer,0,&draw);CHKERRQ(ierr);
1463   ierr = PetscSNPrintf(time,32,"Timestep %d Time %g",(int)step,(double)ptime);CHKERRQ(ierr);
1464   ierr = PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr);CHKERRQ(ierr);
1465   h    = yl + .95*(yr - yl);
1466   ierr = PetscDrawStringCentered(draw,.5*(xl+xr),h,PETSC_DRAW_BLACK,time);CHKERRQ(ierr);
1467   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1468   PetscFunctionReturn(0);
1469 }
1470 
1471 /*
1472    TSAdjointSetFromOptions - Sets various TSAdjoint parameters from user options.
1473 
1474    Collective on TSAdjoint
1475 
1476    Input Parameter:
1477 .  ts - the TS context
1478 
1479    Options Database Keys:
1480 +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
1481 .  -ts_adjoint_monitor - print information at each adjoint time step
1482 -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically
1483 
1484    Level: developer
1485 
1486    Notes:
1487     This is not normally called directly by users
1488 
1489 .keywords: TS, trajectory, timestep, set, options, database
1490 
1491 .seealso: TSSetSaveTrajectory(), TSTrajectorySetUp()
1492 */
1493 PetscErrorCode TSAdjointSetFromOptions(PetscOptionItems *PetscOptionsObject,TS ts)
1494 {
1495   PetscBool      tflg,opt;
1496   PetscErrorCode ierr;
1497 
1498   PetscFunctionBegin;
1499   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
1500   ierr = PetscOptionsHead(PetscOptionsObject,"TS Adjoint options");CHKERRQ(ierr);
1501   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
1502   ierr = PetscOptionsBool("-ts_adjoint_solve","Solve the adjoint problem immediately after solving the forward problem","",tflg,&tflg,&opt);CHKERRQ(ierr);
1503   if (opt) {
1504     ierr = TSSetSaveTrajectory(ts);CHKERRQ(ierr);
1505     ts->adjoint_solve = tflg;
1506   }
1507   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor","Monitor adjoint timestep size","TSAdjointMonitorDefault",TSAdjointMonitorDefault,NULL);CHKERRQ(ierr);
1508   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor_sensi","Monitor sensitivity in the adjoint computation","TSAdjointMonitorSensi",TSAdjointMonitorSensi,NULL);CHKERRQ(ierr);
1509   opt  = PETSC_FALSE;
1510   ierr = PetscOptionsName("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",&opt);CHKERRQ(ierr);
1511   if (opt) {
1512     TSMonitorDrawCtx ctx;
1513     PetscInt         howoften = 1;
1514 
1515     ierr = PetscOptionsInt("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",howoften,&howoften,NULL);CHKERRQ(ierr);
1516     ierr = TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts),0,0,PETSC_DECIDE,PETSC_DECIDE,300,300,howoften,&ctx);CHKERRQ(ierr);
1517     ierr = TSAdjointMonitorSet(ts,TSAdjointMonitorDrawSensi,ctx,(PetscErrorCode (*)(void**))TSMonitorDrawCtxDestroy);CHKERRQ(ierr);
1518   }
1519   PetscFunctionReturn(0);
1520 }
1521 
1522 /*@
1523    TSAdjointStep - Steps one time step backward in the adjoint run
1524 
1525    Collective on TS
1526 
1527    Input Parameter:
1528 .  ts - the TS context obtained from TSCreate()
1529 
1530    Level: intermediate
1531 
1532 .keywords: TS, adjoint, step
1533 
1534 .seealso: TSAdjointSetUp(), TSAdjointSolve()
1535 @*/
1536 PetscErrorCode TSAdjointStep(TS ts)
1537 {
1538   DM               dm;
1539   PetscErrorCode   ierr;
1540 
1541   PetscFunctionBegin;
1542   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1543   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
1544   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1545 
1546   ts->reason = TS_CONVERGED_ITERATING;
1547   ts->ptime_prev = ts->ptime;
1548   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);
1549   ierr = PetscLogEventBegin(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1550   ierr = (*ts->ops->adjointstep)(ts);CHKERRQ(ierr);
1551   ierr = PetscLogEventEnd(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1552   ts->adjoint_steps++; ts->steps--;
1553 
1554   if (ts->reason < 0) {
1555     if (ts->errorifstepfailed) {
1556       if (ts->reason == TSADJOINT_DIVERGED_LINEAR_SOLVE) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1557       else SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1558     }
1559   } else if (!ts->reason) {
1560     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1561   }
1562   PetscFunctionReturn(0);
1563 }
1564 
1565 /*@
1566    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE
1567 
1568    Collective on TS
1569 
1570    Input Parameter:
1571 .  ts - the TS context obtained from TSCreate()
1572 
1573    Options Database:
1574 . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values
1575 
1576    Level: intermediate
1577 
1578    Notes:
1579    This must be called after a call to TSSolve() that solves the forward problem
1580 
1581    By default this will integrate back to the initial time, one can use TSAdjointSetSteps() to step back to a later time
1582 
1583 .keywords: TS, timestep, solve
1584 
1585 .seealso: TSCreate(), TSSetCostGradients(), TSSetSolution(), TSAdjointStep()
1586 @*/
1587 PetscErrorCode TSAdjointSolve(TS ts)
1588 {
1589   PetscErrorCode    ierr;
1590 
1591   PetscFunctionBegin;
1592   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1593   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1594 
1595   /* reset time step and iteration counters */
1596   ts->adjoint_steps     = 0;
1597   ts->ksp_its           = 0;
1598   ts->snes_its          = 0;
1599   ts->num_snes_failures = 0;
1600   ts->reject            = 0;
1601   ts->reason            = TS_CONVERGED_ITERATING;
1602 
1603   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
1604   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1605 
1606   while (!ts->reason) {
1607     ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1608     ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1609     ierr = TSAdjointEventHandler(ts);CHKERRQ(ierr);
1610     ierr = TSAdjointStep(ts);CHKERRQ(ierr);
1611     if ((ts->vec_costintegral || ts->quadraturets) && !ts->costintegralfwd) {
1612       ierr = TSAdjointCostIntegral(ts);CHKERRQ(ierr);
1613     }
1614   }
1615   ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1616   ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1617   ts->solvetime = ts->ptime;
1618   ierr = TSTrajectoryViewFromOptions(ts->trajectory,NULL,"-ts_trajectory_view");CHKERRQ(ierr);
1619   ierr = VecViewFromOptions(ts->vecs_sensi[0],(PetscObject) ts, "-ts_adjoint_view_solution");CHKERRQ(ierr);
1620   ts->adjoint_max_steps = 0;
1621   PetscFunctionReturn(0);
1622 }
1623 
1624 /*@C
1625    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using TSAdjointMonitorSet()
1626 
1627    Collective on TS
1628 
1629    Input Parameters:
1630 +  ts - time stepping context obtained from TSCreate()
1631 .  step - step number that has just completed
1632 .  ptime - model time of the state
1633 .  u - state at the current model time
1634 .  numcost - number of cost functions (dimension of lambda  or mu)
1635 .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
1636 -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
1637 
1638    Notes:
1639    TSAdjointMonitor() is typically used automatically within the time stepping implementations.
1640    Users would almost never call this routine directly.
1641 
1642    Level: developer
1643 
1644 .keywords: TS, timestep
1645 @*/
1646 PetscErrorCode TSAdjointMonitor(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda, Vec *mu)
1647 {
1648   PetscErrorCode ierr;
1649   PetscInt       i,n = ts->numberadjointmonitors;
1650 
1651   PetscFunctionBegin;
1652   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1653   PetscValidHeaderSpecific(u,VEC_CLASSID,4);
1654   ierr = VecLockReadPush(u);CHKERRQ(ierr);
1655   for (i=0; i<n; i++) {
1656     ierr = (*ts->adjointmonitor[i])(ts,step,ptime,u,numcost,lambda,mu,ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
1657   }
1658   ierr = VecLockReadPop(u);CHKERRQ(ierr);
1659   PetscFunctionReturn(0);
1660 }
1661 
1662 /*@
1663  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.
1664 
1665  Collective on TS
1666 
1667  Input Arguments:
1668  .  ts - time stepping context
1669 
1670  Level: advanced
1671 
1672  Notes:
1673  This function cannot be called until TSAdjointStep() has been completed.
1674 
1675  .seealso: TSAdjointSolve(), TSAdjointStep
1676  @*/
1677 PetscErrorCode TSAdjointCostIntegral(TS ts)
1678 {
1679     PetscErrorCode ierr;
1680     PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1681     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);
1682     ierr = (*ts->ops->adjointintegral)(ts);CHKERRQ(ierr);
1683     PetscFunctionReturn(0);
1684 }
1685 
1686 /* ------------------ Forward (tangent linear) sensitivity  ------------------*/
1687 
1688 /*@
1689   TSForwardSetUp - Sets up the internal data structures for the later use
1690   of forward sensitivity analysis
1691 
1692   Collective on TS
1693 
1694   Input Parameter:
1695 . ts - the TS context obtained from TSCreate()
1696 
1697   Level: advanced
1698 
1699 .keywords: TS, forward sensitivity, setup
1700 
1701 .seealso: TSCreate(), TSDestroy(), TSSetUp()
1702 @*/
1703 PetscErrorCode TSForwardSetUp(TS ts)
1704 {
1705   PetscErrorCode ierr;
1706 
1707   PetscFunctionBegin;
1708   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1709   if (ts->forwardsetupcalled) PetscFunctionReturn(0);
1710   if (!ts->Jacp && ts->Jacprhs) ts->Jacp = ts->Jacprhs;
1711 
1712   if (ts->ops->forwardsetup) {
1713     ierr = (*ts->ops->forwardsetup)(ts);CHKERRQ(ierr);
1714   }
1715   ierr = VecDuplicate(ts->vec_sol,&ts->vec_sensip_col);CHKERRQ(ierr);
1716   ts->forwardsetupcalled = PETSC_TRUE;
1717   PetscFunctionReturn(0);
1718 }
1719 
1720 /*@
1721   TSForwardReset - Reset the internal data structures used by forward sensitivity analysis
1722 
1723   Collective on TS
1724 
1725   Input Parameter:
1726 . ts - the TS context obtained from TSCreate()
1727 
1728   Level: advanced
1729 
1730 .keywords: TS, forward sensitivity, reset
1731 
1732 .seealso: TSCreate(), TSDestroy(), TSForwardSetUp()
1733 @*/
1734 PetscErrorCode TSForwardReset(TS ts)
1735 {
1736   TS             quadts = ts->quadraturets;
1737   PetscErrorCode ierr;
1738 
1739   PetscFunctionBegin;
1740   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1741   if (ts->ops->forwardreset) {
1742     ierr = (*ts->ops->forwardreset)(ts);CHKERRQ(ierr);
1743   }
1744   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1745   if (quadts) {
1746     ierr = MatDestroy(&quadts->mat_sensip);CHKERRQ(ierr);
1747   }
1748   ierr = VecDestroy(&ts->vec_sensip_col);CHKERRQ(ierr);
1749   ts->forward_solve      = PETSC_FALSE;
1750   ts->forwardsetupcalled = PETSC_FALSE;
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 /*@
1755   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.
1756 
1757   Input Parameter:
1758 . ts- the TS context obtained from TSCreate()
1759 . numfwdint- number of integrals
1760 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1761 
1762   Level: deprecated
1763 
1764 .keywords: TS, forward sensitivity
1765 
1766 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1767 @*/
1768 PetscErrorCode TSForwardSetIntegralGradients(TS ts,PetscInt numfwdint,Vec *vp)
1769 {
1770   PetscFunctionBegin;
1771   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1772   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()");
1773   if (!ts->numcost) ts->numcost = numfwdint;
1774 
1775   ts->vecs_integral_sensip = vp;
1776   PetscFunctionReturn(0);
1777 }
1778 
1779 /*@
1780   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.
1781 
1782   Input Parameter:
1783 . ts- the TS context obtained from TSCreate()
1784 
1785   Output Parameter:
1786 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1787 
1788   Level: deprecated
1789 
1790 .keywords: TS, forward sensitivity
1791 
1792 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1793 @*/
1794 PetscErrorCode TSForwardGetIntegralGradients(TS ts,PetscInt *numfwdint,Vec **vp)
1795 {
1796   PetscFunctionBegin;
1797   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1798   PetscValidPointer(vp,3);
1799   if (numfwdint) *numfwdint = ts->numcost;
1800   if (vp) *vp = ts->vecs_integral_sensip;
1801   PetscFunctionReturn(0);
1802 }
1803 
1804 /*@
1805   TSForwardStep - Compute the forward sensitivity for one time step.
1806 
1807   Collective on TS
1808 
1809   Input Arguments:
1810 . ts - time stepping context
1811 
1812   Level: advanced
1813 
1814   Notes:
1815   This function cannot be called until TSStep() has been completed.
1816 
1817 .keywords: TS, forward sensitivity
1818 
1819 .seealso: TSForwardSetSensitivities(), TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardSetUp()
1820 @*/
1821 PetscErrorCode TSForwardStep(TS ts)
1822 {
1823   PetscErrorCode ierr;
1824   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1825   if (!ts->ops->forwardstep) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide forward sensitivity analysis",((PetscObject)ts)->type_name);
1826   ierr = PetscLogEventBegin(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1827   ierr = (*ts->ops->forwardstep)(ts);CHKERRQ(ierr);
1828   ierr = PetscLogEventEnd(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1829   PetscFunctionReturn(0);
1830 }
1831 
1832 /*@
1833   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.
1834 
1835   Logically Collective on TS and Vec
1836 
1837   Input Parameters:
1838 + ts - the TS context obtained from TSCreate()
1839 . nump - number of parameters
1840 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1841 
1842   Level: beginner
1843 
1844   Notes:
1845   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
1846   This function turns on a flag to trigger TSSolve() to compute forward sensitivities automatically.
1847   You must call this function before TSSolve().
1848   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.
1849 
1850 .keywords: TS, timestep, set, forward sensitivity, initial values
1851 
1852 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1853 @*/
1854 PetscErrorCode TSForwardSetSensitivities(TS ts,PetscInt nump,Mat Smat)
1855 {
1856   PetscErrorCode ierr;
1857 
1858   PetscFunctionBegin;
1859   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1860   PetscValidHeaderSpecific(Smat,MAT_CLASSID,3);
1861   ts->forward_solve  = PETSC_TRUE;
1862   if (nump == PETSC_DEFAULT) {
1863     ierr = MatGetSize(Smat,NULL,&ts->num_parameters);CHKERRQ(ierr);
1864   } else ts->num_parameters = nump;
1865   ierr = PetscObjectReference((PetscObject)Smat);CHKERRQ(ierr);
1866   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1867   ts->mat_sensip = Smat;
1868   PetscFunctionReturn(0);
1869 }
1870 
1871 /*@
1872   TSForwardGetSensitivities - Returns the trajectory sensitivities
1873 
1874   Not Collective, but Vec returned is parallel if TS is parallel
1875 
1876   Output Parameter:
1877 + ts - the TS context obtained from TSCreate()
1878 . nump - number of parameters
1879 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1880 
1881   Level: intermediate
1882 
1883 .keywords: TS, forward sensitivity
1884 
1885 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1886 @*/
1887 PetscErrorCode TSForwardGetSensitivities(TS ts,PetscInt *nump,Mat *Smat)
1888 {
1889   PetscFunctionBegin;
1890   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1891   if (nump) *nump = ts->num_parameters;
1892   if (Smat) *Smat = ts->mat_sensip;
1893   PetscFunctionReturn(0);
1894 }
1895 
1896 /*@
1897    TSForwardCostIntegral - Evaluate the cost integral in the forward run.
1898 
1899    Collective on TS
1900 
1901    Input Arguments:
1902 .  ts - time stepping context
1903 
1904    Level: advanced
1905 
1906    Notes:
1907    This function cannot be called until TSStep() has been completed.
1908 
1909 .seealso: TSSolve(), TSAdjointCostIntegral()
1910 @*/
1911 PetscErrorCode TSForwardCostIntegral(TS ts)
1912 {
1913   PetscErrorCode ierr;
1914   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1915   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);
1916   ierr = (*ts->ops->forwardintegral)(ts);CHKERRQ(ierr);
1917   PetscFunctionReturn(0);
1918 }
1919 
1920 /*@
1921   TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities
1922 
1923   Collective on TS and Mat
1924 
1925   Input Parameter
1926 + ts - the TS context obtained from TSCreate()
1927 - didp - parametric sensitivities of the initial condition
1928 
1929   Level: intermediate
1930 
1931   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.
1932 
1933 .seealso: TSForwardSetSensitivities()
1934 @*/
1935 PetscErrorCode TSForwardSetInitialSensitivities(TS ts,Mat didp)
1936 {
1937   PetscErrorCode ierr;
1938 
1939   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1940   PetscValidHeaderSpecific(didp,MAT_CLASSID,2);
1941   if (!ts->mat_sensip) {
1942     ierr = TSForwardSetSensitivities(ts,PETSC_DEFAULT,didp);CHKERRQ(ierr);
1943   }
1944   PetscFunctionReturn(0);
1945 }
1946 
1947 /*@
1948    TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages
1949 
1950    Input Parameter:
1951 .  ts - the TS context obtained from TSCreate()
1952 
1953    Output Parameters:
1954 +  ns - number of stages
1955 -  S - tangent linear sensitivities at the intermediate stages
1956 
1957    Level: advanced
1958 
1959 .keywords: TS, second-order adjoint, forward sensitivity
1960 @*/
1961 PetscErrorCode TSForwardGetStages(TS ts,PetscInt *ns,Mat **S)
1962 {
1963   PetscErrorCode ierr;
1964 
1965   PetscFunctionBegin;
1966   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1967 
1968   if (!ts->ops->getstages) *S=NULL;
1969   else {
1970     ierr = (*ts->ops->forwardgetstages)(ts,ns,S);CHKERRQ(ierr);
1971   }
1972   PetscFunctionReturn(0);
1973 }
1974 
1975 /*@
1976    TSCreateQuadratureTS - Create a sub-TS that evaluates integrals over time
1977 
1978    Input Parameter:
1979 +  ts - the TS context obtained from TSCreate()
1980 -  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
1981 
1982    Output Parameters:
1983 .  quadts - the child TS context
1984 
1985    Level: intermediate
1986 
1987 .keywords: TS, quadrature evaluation
1988 
1989 .seealso: TSGetQuadratureTS()
1990 @*/
1991 PetscErrorCode TSCreateQuadratureTS(TS ts,PetscBool fwd,TS *quadts)
1992 {
1993   char prefix[128];
1994   PetscErrorCode ierr;
1995 
1996   PetscFunctionBegin;
1997   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1998   PetscValidPointer(quadts,2);
1999   ierr = TSDestroy(&ts->quadraturets);CHKERRQ(ierr);
2000   ierr = TSCreate(PetscObjectComm((PetscObject)ts),&ts->quadraturets);CHKERRQ(ierr);
2001   ierr = PetscObjectIncrementTabLevel((PetscObject)ts->quadraturets,(PetscObject)ts,1);CHKERRQ(ierr);
2002   ierr = PetscLogObjectParent((PetscObject)ts,(PetscObject)ts->quadraturets);CHKERRQ(ierr);
2003   ierr = PetscSNPrintf(prefix,sizeof(prefix),"%squad_",((PetscObject)ts)->prefix ? ((PetscObject)ts)->prefix : "");CHKERRQ(ierr);
2004   ierr = TSSetOptionsPrefix(ts->quadraturets,prefix);CHKERRQ(ierr);
2005   *quadts = ts->quadraturets;
2006 
2007   if (ts->numcost) {
2008     ierr = VecCreateSeq(PETSC_COMM_SELF,ts->numcost,&(*quadts)->vec_sol);CHKERRQ(ierr);
2009   } else {
2010     ierr = VecCreateSeq(PETSC_COMM_SELF,1,&(*quadts)->vec_sol);CHKERRQ(ierr);
2011   }
2012   ts->costintegralfwd = fwd;
2013   PetscFunctionReturn(0);
2014 }
2015 
2016 /*@
2017    TSGetQuadratureTS - Return the sub-TS that evaluates integrals over time
2018 
2019    Input Parameter:
2020 .  ts - the TS context obtained from TSCreate()
2021 
2022    Output Parameters:
2023 +  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
2024 -  quadts - the child TS context
2025 
2026    Level: intermediate
2027 
2028 .keywords: TS, quadrature evaluation
2029 
2030 .seealso: TSCreateQuadratureTS()
2031 @*/
2032 PetscErrorCode TSGetQuadratureTS(TS ts,PetscBool *fwd,TS *quadts)
2033 {
2034   PetscFunctionBegin;
2035   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
2036   if (fwd) *fwd = ts->costintegralfwd;
2037   if (quadts) *quadts = ts->quadraturets;
2038   PetscFunctionReturn(0);
2039 }
2040