xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 1d14d03bfa806db18a4efd8bfa987efa26a1ddb0)
1 #include <petsc/private/tsimpl.h>        /*I "petscts.h"  I*/
2 #include <petscdraw.h>
3 
4 PetscLogEvent TS_AdjointStep, TS_ForwardStep;
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:
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->Jacp);CHKERRQ(ierr);
47     ts->Jacp = Amat;
48   }
49   PetscFunctionReturn(0);
50 }
51 
52 /*@C
53   TSComputeRHSJacobianP - Runs the user-defined JacobianP function.
54 
55   Collective on TS
56 
57   Input Parameters:
58 . ts   - The TS context obtained from TSCreate()
59 
60   Level: developer
61 
62 .keywords: TS, sensitivity
63 .seealso: TSSetRHSJacobianP()
64 @*/
65 PetscErrorCode TSComputeRHSJacobianP(TS ts,PetscReal t,Vec U,Mat Amat)
66 {
67   PetscErrorCode ierr;
68 
69   PetscFunctionBegin;
70   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
71   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
72   PetscValidPointer(Amat,4);
73 
74   PetscStackPush("TS user JacobianP function for sensitivity analysis");
75   ierr = (*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx);CHKERRQ(ierr);
76   PetscStackPop;
77   PetscFunctionReturn(0);
78 }
79 
80 /*@C
81     TSSetCostIntegrand - Sets the routine for evaluating the integral term in one or more cost functions
82 
83     Logically Collective on TS
84 
85     Input Parameters:
86 +   ts - the TS context obtained from TSCreate()
87 .   numcost - number of gradients to be computed, this is the number of cost functions
88 .   costintegral - vector that stores the integral values
89 .   rf - routine for evaluating the integrand function
90 .   drduf - function that computes the gradients of the r's with respect to u
91 .   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)
92 .   fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
93 -   ctx - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
94 
95     Calling sequence of rf:
96 $   PetscErrorCode rf(TS ts,PetscReal t,Vec U,Vec F,void *ctx);
97 
98     Calling sequence of drduf:
99 $   PetscErroCode drduf(TS ts,PetscReal t,Vec U,Vec *dRdU,void *ctx);
100 
101     Calling sequence of drdpf:
102 $   PetscErroCode drdpf(TS ts,PetscReal t,Vec U,Vec *dRdP,void *ctx);
103 
104     Level: intermediate
105 
106     Notes:
107     For optimization there is usually a single cost function (numcost = 1). For sensitivities there may be multiple cost functions
108 
109 .keywords: TS, sensitivity analysis, timestep, set, quadrature, function
110 
111 .seealso: TSSetRHSJacobianP(), TSGetCostGradients(), TSSetCostGradients()
112 @*/
113 PetscErrorCode TSSetCostIntegrand(TS ts,PetscInt numcost,Vec costintegral,PetscErrorCode (*rf)(TS,PetscReal,Vec,Vec,void*),
114                                                           PetscErrorCode (*drduf)(TS,PetscReal,Vec,Vec*,void*),
115                                                           PetscErrorCode (*drdpf)(TS,PetscReal,Vec,Vec*,void*),
116                                                           PetscBool fwd,void *ctx)
117 {
118   PetscErrorCode ierr;
119 
120   PetscFunctionBegin;
121   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
122   if (costintegral) PetscValidHeaderSpecific(costintegral,VEC_CLASSID,3);
123   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()");
124   if (!ts->numcost) ts->numcost=numcost;
125 
126   if (costintegral) {
127     ierr = PetscObjectReference((PetscObject)costintegral);CHKERRQ(ierr);
128     ierr = VecDestroy(&ts->vec_costintegral);CHKERRQ(ierr);
129     ts->vec_costintegral = costintegral;
130   } else {
131     if (!ts->vec_costintegral) { /* Create a seq vec if user does not provide one */
132       ierr = VecCreateSeq(PETSC_COMM_SELF,numcost,&ts->vec_costintegral);CHKERRQ(ierr);
133     } else {
134       ierr = VecSet(ts->vec_costintegral,0.0);CHKERRQ(ierr);
135     }
136   }
137   if (!ts->vec_costintegrand) {
138     ierr = VecDuplicate(ts->vec_costintegral,&ts->vec_costintegrand);CHKERRQ(ierr);
139   } else {
140     ierr = VecSet(ts->vec_costintegrand,0.0);CHKERRQ(ierr);
141   }
142   ts->costintegralfwd  = fwd; /* Evaluate the cost integral in forward run if fwd is true */
143   ts->costintegrand    = rf;
144   ts->costintegrandctx = ctx;
145   ts->drdufunction     = drduf;
146   ts->drdpfunction     = drdpf;
147   PetscFunctionReturn(0);
148 }
149 
150 /*@C
151    TSGetCostIntegral - Returns the values of the integral term in the cost functions.
152    It is valid to call the routine after a backward run.
153 
154    Not Collective
155 
156    Input Parameter:
157 .  ts - the TS context obtained from TSCreate()
158 
159    Output Parameter:
160 .  v - the vector containing the integrals for each cost function
161 
162    Level: intermediate
163 
164 .seealso: TSSetCostIntegrand()
165 
166 .keywords: TS, sensitivity analysis
167 @*/
168 PetscErrorCode  TSGetCostIntegral(TS ts,Vec *v)
169 {
170   PetscFunctionBegin;
171   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
172   PetscValidPointer(v,2);
173   *v = ts->vec_costintegral;
174   PetscFunctionReturn(0);
175 }
176 
177 /*@C
178    TSComputeCostIntegrand - Evaluates the integral function in the cost functions.
179 
180    Input Parameters:
181 +  ts - the TS context
182 .  t - current time
183 -  U - state vector, i.e. current solution
184 
185    Output Parameter:
186 .  Q - vector of size numcost to hold the outputs
187 
188    Note:
189    Most users should not need to explicitly call this routine, as it
190    is used internally within the sensitivity analysis context.
191 
192    Level: developer
193 
194 .keywords: TS, compute
195 
196 .seealso: TSSetCostIntegrand()
197 @*/
198 PetscErrorCode TSComputeCostIntegrand(TS ts,PetscReal t,Vec U,Vec Q)
199 {
200   PetscErrorCode ierr;
201 
202   PetscFunctionBegin;
203   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
204   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
205   PetscValidHeaderSpecific(Q,VEC_CLASSID,4);
206 
207   ierr = PetscLogEventBegin(TS_FunctionEval,ts,U,Q,0);CHKERRQ(ierr);
208   if (ts->costintegrand) {
209     PetscStackPush("TS user integrand in the cost function");
210     ierr = (*ts->costintegrand)(ts,t,U,Q,ts->costintegrandctx);CHKERRQ(ierr);
211     PetscStackPop;
212   } else {
213     ierr = VecZeroEntries(Q);CHKERRQ(ierr);
214   }
215 
216   ierr = PetscLogEventEnd(TS_FunctionEval,ts,U,Q,0);CHKERRQ(ierr);
217   PetscFunctionReturn(0);
218 }
219 
220 /*@C
221   TSComputeDRDUFunction - Runs the user-defined DRDU function.
222 
223   Collective on TS
224 
225   Input Parameters:
226 + ts - the TS context obtained from TSCreate()
227 . t - current time
228 - U - stata vector
229 
230   Output Parameters:
231 . DRDU - vector array to hold the outputs
232 
233   Notes:
234   TSComputeDRDUFunction() is typically used for sensitivity implementation,
235   so most users would not generally call this routine themselves.
236 
237   Level: developer
238 
239 .keywords: TS, sensitivity
240 .seealso: TSSetCostIntegrand()
241 @*/
242 PetscErrorCode TSComputeDRDUFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
243 {
244   PetscErrorCode ierr;
245 
246   PetscFunctionBegin;
247   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
248   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
249 
250   PetscStackPush("TS user DRDU function for sensitivity analysis");
251   ierr = (*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx); CHKERRQ(ierr);
252   PetscStackPop;
253   PetscFunctionReturn(0);
254 }
255 
256 /*@C
257   TSComputeDRDPFunction - Runs the user-defined DRDP function.
258 
259   Collective on TS
260 
261   Input Parameters:
262 + ts - the TS context obtained from TSCreate()
263 . t - current time
264 - U - stata vector
265 
266   Output Parameters:
267 . DRDP - vector array to hold the outputs
268 
269   Notes:
270   TSComputeDRDPFunction() is typically used for sensitivity implementation,
271   so most users would not generally call this routine themselves.
272 
273   Level: developer
274 
275 .keywords: TS, sensitivity
276 .seealso: TSSetCostIntegrand()
277 @*/
278 PetscErrorCode TSComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
279 {
280   PetscErrorCode ierr;
281 
282   PetscFunctionBegin;
283   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
284   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
285 
286   PetscStackPush("TS user DRDP function for sensitivity analysis");
287   ierr = (*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx); CHKERRQ(ierr);
288   PetscStackPop;
289   PetscFunctionReturn(0);
290 }
291 
292 /*@C
293   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.
294 
295   Logically Collective on TS
296 
297   Input Parameters:
298 + ts - TS context obtained from TSCreate()
299 . ihp1 - an array of vectors storing the result of vector-Hessian-vector product for F_UU
300 . hessianproductfunc1 - vector-Hessian-vector product function for F_UU
301 . ihp2 - an array of vectors storing the result of vector-Hessian-vector product for F_UP
302 . hessianproductfunc2 - vector-Hessian-vector product function for F_UP
303 . ihp3 - an array of vectors storing the result of vector-Hessian-vector product for F_PU
304 . hessianproductfunc3 - vector-Hessian-vector product function for F_PU
305 . ihp4 - an array of vectors storing the result of vector-Hessian-vector product for F_PP
306 . hessianproductfunc4 - vector-Hessian-vector product function for F_PP
307 
308   Calling sequence of ihessianproductfunc:
309 $ ihessianproductfunc (TS ts,PetscReal t,Vec U,Vec Vl,Vec Vr,Vec VHV,void *ctx);
310 +   t - current timestep
311 .   U - input vector (current ODE solution)
312 .   Vl - input vector to be left-multiplied with the Hessian
313 .   Vr - input vector to be right-multiplied with the Hessian
314 .   VHV - output vector for vector-Hessian-vector product
315 -   ctx - [optional] user-defined function context
316 
317   Level: intermediate
318 
319 Note: The first Hessian function and the working array are required.
320 
321 .keywords: TS, sensitivity
322 
323 .seealso:
324 @*/
325 PetscErrorCode TSSetIHessianProduct(TS ts,Vec *ihp1,PetscErrorCode (*ihessianproductfunc1)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
326                                           Vec *ihp2,PetscErrorCode (*ihessianproductfunc2)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
327                                           Vec *ihp3,PetscErrorCode (*ihessianproductfunc3)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
328                                           Vec *ihp4,PetscErrorCode (*ihessianproductfunc4)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
329                                     void *ctx)
330 {
331   PetscFunctionBegin;
332   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
333   PetscValidPointer(ihp1,2);
334 
335   ts->ihessianproductctx = ctx;
336   if (ihp1) ts->vecs_fuu = ihp1;
337   if (ihp2) ts->vecs_fup = ihp2;
338   if (ihp3) ts->vecs_fpu = ihp3;
339   if (ihp4) ts->vecs_fpp = ihp4;
340   ts->ihessianproduct_fuu = ihessianproductfunc1;
341   ts->ihessianproduct_fup = ihessianproductfunc2;
342   ts->ihessianproduct_fpu = ihessianproductfunc3;
343   ts->ihessianproduct_fpp = ihessianproductfunc4;
344   PetscFunctionReturn(0);
345 }
346 
347 /*@C
348   TSComputeIHessianProductFunction1 - Runs the user-defined vector-Hessian-vector product function for Fuu.
349 
350   Collective on TS
351 
352   Input Parameters:
353 . ts   - The TS context obtained from TSCreate()
354 
355   Notes:
356   TSComputeIHessianProductFunction1() is typically used for sensitivity implementation,
357   so most users would not generally call this routine themselves.
358 
359   Level: developer
360 
361 .keywords: TS, sensitivity
362 
363 .seealso: TSSetIHessianProduct()
364 @*/
365 PetscErrorCode TSComputeIHessianProductFunction1(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
366 {
367   PetscErrorCode ierr;
368 
369   PetscFunctionBegin;
370   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
371   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
372 
373   PetscStackPush("TS user IHessianProduct function 1 for sensitivity analysis");
374   ierr = (*ts->ihessianproduct_fuu)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
375   PetscStackPop;
376   PetscFunctionReturn(0);
377 }
378 
379 /*@C
380   TSComputeIHessianProductFunction2 - Runs the user-defined vector-Hessian-vector product function for Fup.
381 
382   Collective on TS
383 
384   Input Parameters:
385 . ts   - The TS context obtained from TSCreate()
386 
387   Notes:
388   TSComputeIHessianProductFunction2() is typically used for sensitivity implementation,
389   so most users would not generally call this routine themselves.
390 
391   Level: developer
392 
393 .keywords: TS, sensitivity
394 
395 .seealso: TSSetIHessianProduct()
396 @*/
397 PetscErrorCode TSComputeIHessianProductFunction2(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
398 {
399   PetscErrorCode ierr;
400 
401   PetscFunctionBegin;
402   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
403   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
404 
405   PetscStackPush("TS user IHessianProduct function 2 for sensitivity analysis");
406   ierr = (*ts->ihessianproduct_fup)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
407   PetscStackPop;
408   PetscFunctionReturn(0);
409 }
410 
411 /*@C
412   TSComputeIHessianProductFunction3 - Runs the user-defined vector-Hessian-vector product function for Fpu.
413 
414   Collective on TS
415 
416   Input Parameters:
417 . ts   - The TS context obtained from TSCreate()
418 
419   Notes:
420   TSComputeIHessianProductFunction3() is typically used for sensitivity implementation,
421   so most users would not generally call this routine themselves.
422 
423   Level: developer
424 
425 .keywords: TS, sensitivity
426 
427 .seealso: TSSetIHessianProduct()
428 @*/
429 PetscErrorCode TSComputeIHessianProductFunction3(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
430 {
431   PetscErrorCode ierr;
432 
433   PetscFunctionBegin;
434   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
435   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
436 
437   PetscStackPush("TS user IHessianProduct function 3 for sensitivity analysis");
438   ierr = (*ts->ihessianproduct_fpu)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
439   PetscStackPop;
440   PetscFunctionReturn(0);
441 }
442 
443 /*@C
444   TSComputeIHessianProductFunction4 - Runs the user-defined vector-Hessian-vector product function for Fpp.
445 
446   Collective on TS
447 
448   Input Parameters:
449 . ts   - The TS context obtained from TSCreate()
450 
451   Notes:
452   TSComputeIHessianProductFunction4() is typically used for sensitivity implementation,
453   so most users would not generally call this routine themselves.
454 
455   Level: developer
456 
457 .keywords: TS, sensitivity
458 
459 .seealso: TSSetIHessianProduct()
460 @*/
461 PetscErrorCode TSComputeIHessianProductFunction4(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
462 {
463   PetscErrorCode ierr;
464 
465   PetscFunctionBegin;
466   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
467   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
468 
469   PetscStackPush("TS user IHessianProduct function 3 for sensitivity analysis");
470   ierr = (*ts->ihessianproduct_fpp)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx);CHKERRQ(ierr);
471   PetscStackPop;
472   PetscFunctionReturn(0);
473 }
474 
475 /* --------------------------- Adjoint sensitivity ---------------------------*/
476 
477 /*@
478    TSSetCostGradients - Sets the initial value of the gradients of the cost function w.r.t. initial values and w.r.t. the problem parameters
479       for use by the TSAdjoint routines.
480 
481    Logically Collective on TS and Vec
482 
483    Input Parameters:
484 +  ts - the TS context obtained from TSCreate()
485 .  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
486 -  mu - gradients with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
487 
488    Level: beginner
489 
490    Notes:
491     the entries in these vectors must be correctly initialized with the values lamda_i = df/dy|finaltime  mu_i = df/dp|finaltime
492 
493    After TSAdjointSolve() is called the lamba and the mu contain the computed sensitivities
494 
495 .keywords: TS, timestep, set, sensitivity, initial values
496 
497 .seealso TSGetCostGradients()
498 @*/
499 PetscErrorCode TSSetCostGradients(TS ts,PetscInt numcost,Vec *lambda,Vec *mu)
500 {
501   PetscFunctionBegin;
502   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
503   PetscValidPointer(lambda,2);
504   ts->vecs_sensi  = lambda;
505   ts->vecs_sensip = mu;
506   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");
507   ts->numcost  = numcost;
508   PetscFunctionReturn(0);
509 }
510 
511 /*@
512    TSGetCostGradients - Returns the gradients from the TSAdjointSolve()
513 
514    Not Collective, but Vec returned is parallel if TS is parallel
515 
516    Input Parameter:
517 .  ts - the TS context obtained from TSCreate()
518 
519    Output Parameter:
520 +  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
521 -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
522 
523    Level: intermediate
524 
525 .keywords: TS, timestep, get, sensitivity
526 
527 .seealso: TSSetCostGradients()
528 @*/
529 PetscErrorCode TSGetCostGradients(TS ts,PetscInt *numcost,Vec **lambda,Vec **mu)
530 {
531   PetscFunctionBegin;
532   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
533   if (numcost) *numcost = ts->numcost;
534   if (lambda)  *lambda  = ts->vecs_sensi;
535   if (mu)      *mu      = ts->vecs_sensip;
536   PetscFunctionReturn(0);
537 }
538 
539 /*@
540    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
541       for use by the TSAdjoint routines.
542 
543    Logically Collective on TS and Vec
544 
545    Input Parameters:
546 +  ts - the TS context obtained from TSCreate()
547 .  numcost - number of cost functions
548 .  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
549 .  mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
550 -  dir - the direction vector that are multiplied with the Hessian of the cost functions
551 
552    Level: beginner
553 
554    Notes: Hessian of the cost function is completely different from Hessian of the ODE/DAE system
555 
556    For second-order adjoint, one needs to call this function and then TSAdjointInitializeForward() before TSSolve().
557 
558    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.
559 
560    Passing NULL for lambda2 disables the second-order calculation.
561 .keywords: TS, sensitivity, second-order adjoint
562 
563 .seealso: TSAdjointInitializeForward()
564 @*/
565 PetscErrorCode TSSetCostHessianProducts(TS ts,PetscInt numcost,Vec *lambda2,Vec *mu2,Vec dir)
566 {
567   PetscFunctionBegin;
568   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
569   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");
570   ts->numcost       = numcost;
571   ts->vecs_sensi2   = lambda2;
572   ts->vecs_sensip2  = mu2;
573   ts->vec_dir       = dir;
574   PetscFunctionReturn(0);
575 }
576 
577 /*@
578    TSGetCostHessianProducts - Returns the gradients from the TSAdjointSolve()
579 
580    Not Collective, but Vec returned is parallel if TS is parallel
581 
582    Input Parameter:
583 .  ts - the TS context obtained from TSCreate()
584 
585    Output Parameter:
586 +  numcost - number of cost functions
587 .  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
588 .  mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
589 -  dir - the direction vector that are multiplied with the Hessian of the cost functions
590 
591    Level: intermediate
592 
593 .keywords: TS, sensitivity, second-order adjoint
594 
595 .seealso: TSSetCostHessianProducts()
596 @*/
597 PetscErrorCode TSGetCostHessianProducts(TS ts,PetscInt *numcost,Vec **lambda2,Vec **mu2, Vec *dir)
598 {
599   PetscFunctionBegin;
600   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
601   if (numcost) *numcost = ts->numcost;
602   if (lambda2) *lambda2 = ts->vecs_sensi2;
603   if (mu2)     *mu2     = ts->vecs_sensip2;
604   if (dir)     *dir     = ts->vec_dir;
605   PetscFunctionReturn(0);
606 }
607 
608 /*@
609   TSAdjointInitializeForward - Trigger the tangent linear solver and initialize the forward sensitivities
610 
611   Logically Collective on TS and Mat
612 
613   Input Parameters:
614 +  ts - the TS context obtained from TSCreate()
615 -  didp - the derivative of initial values w.r.t. parameters
616 
617   Level: intermediate
618 
619   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.
620 
621 .keywords: TS, sensitivity, second-order adjoint
622 
623 .seealso: TSSetCostHessianProducts()
624 @*/
625 PetscErrorCode TSAdjointInitializeForward(TS ts,Mat didp)
626 {
627   PetscErrorCode ierr;
628 
629   PetscFunctionBegin;
630   ts->forward_solve = PETSC_TRUE; /* turn on tangent linear mode */
631   if (!ts->vecs_sensi2) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Must call TSSetCostHessianProducts() first");
632   if (ts->vecs_sensip2 && !didp) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The fourth argument is not NULL, indicating parametric sensitivities are desired, so the dIdP matrix must be provided"); /* check conflicted settings */
633   ierr = TSForwardSetInitialSensitivities(ts,didp);CHKERRQ(ierr); /* if didp is NULL, identity matrix is assumed */
634   PetscFunctionReturn(0);
635 }
636 
637 /*@
638    TSAdjointSetUp - Sets up the internal data structures for the later use
639    of an adjoint solver
640 
641    Collective on TS
642 
643    Input Parameter:
644 .  ts - the TS context obtained from TSCreate()
645 
646    Level: advanced
647 
648 .keywords: TS, timestep, setup
649 
650 .seealso: TSCreate(), TSAdjointStep(), TSSetCostGradients()
651 @*/
652 PetscErrorCode TSAdjointSetUp(TS ts)
653 {
654   PetscErrorCode ierr;
655 
656   PetscFunctionBegin;
657   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
658   if (ts->adjointsetupcalled) PetscFunctionReturn(0);
659   if (!ts->vecs_sensi) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetCostGradients() first");
660   if (ts->vecs_sensip && !ts->Jacp) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSAdjointSetRHSJacobian() first");
661 
662   if (ts->vec_costintegral) { /* if there is integral in the cost function */
663     ierr = VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&ts->vecs_drdu);CHKERRQ(ierr);
664     if (ts->vecs_sensip){
665       ierr = VecDuplicateVecs(ts->vecs_sensip[0],ts->numcost,&ts->vecs_drdp);CHKERRQ(ierr);
666     }
667   }
668 
669   if (ts->ops->adjointsetup) {
670     ierr = (*ts->ops->adjointsetup)(ts);CHKERRQ(ierr);
671   }
672   ts->adjointsetupcalled = PETSC_TRUE;
673   PetscFunctionReturn(0);
674 }
675 
676 /*@
677    TSAdjointReset - Resets a TSAdjoint context and removes any allocated Vecs and Mats.
678 
679    Collective on TS
680 
681    Input Parameter:
682 .  ts - the TS context obtained from TSCreate()
683 
684    Level: beginner
685 
686 .keywords: TS, timestep, reset
687 
688 .seealso: TSCreate(), TSAdjointSetup(), TSADestroy()
689 @*/
690 PetscErrorCode TSAdjointReset(TS ts)
691 {
692   PetscErrorCode ierr;
693 
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
696   if (ts->ops->adjointreset) {
697     ierr = (*ts->ops->adjointreset)(ts);CHKERRQ(ierr);
698   }
699   if (ts->vec_dir) { /* second-order adjoint */
700     ierr = TSForwardReset(ts);CHKERRQ(ierr);
701   }
702   ts->vecs_sensi         = NULL;
703   ts->vecs_sensip        = NULL;
704   ts->vecs_sensi2        = NULL;
705   ts->vecs_sensip2       = NULL;
706   ts->vec_dir            = NULL;
707   ts->adjointsetupcalled = PETSC_FALSE;
708   PetscFunctionReturn(0);
709 }
710 
711 /*@
712    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time
713 
714    Logically Collective on TS
715 
716    Input Parameters:
717 +  ts - the TS context obtained from TSCreate()
718 .  steps - number of steps to use
719 
720    Level: intermediate
721 
722    Notes:
723     Normally one does not call this and TSAdjointSolve() integrates back to the original timestep. One can call this
724           so as to integrate back to less than the original timestep
725 
726 .keywords: TS, timestep, set, maximum, iterations
727 
728 .seealso: TSSetExactFinalTime()
729 @*/
730 PetscErrorCode TSAdjointSetSteps(TS ts,PetscInt steps)
731 {
732   PetscFunctionBegin;
733   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
734   PetscValidLogicalCollectiveInt(ts,steps,2);
735   if (steps < 0) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back a negative number of steps");
736   if (steps > ts->steps) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back more than the total number of forward steps");
737   ts->adjoint_max_steps = steps;
738   PetscFunctionReturn(0);
739 }
740 
741 /*@C
742   TSAdjointSetRHSJacobian - Deprecated, use TSSetRHSJacobianP()
743 
744   Level: deprecated
745 
746 @*/
747 PetscErrorCode TSAdjointSetRHSJacobian(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
748 {
749   PetscErrorCode ierr;
750 
751   PetscFunctionBegin;
752   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
753   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
754 
755   ts->rhsjacobianp    = func;
756   ts->rhsjacobianpctx = ctx;
757   if(Amat) {
758     ierr = PetscObjectReference((PetscObject)Amat);CHKERRQ(ierr);
759     ierr = MatDestroy(&ts->Jacp);CHKERRQ(ierr);
760     ts->Jacp = Amat;
761   }
762   PetscFunctionReturn(0);
763 }
764 
765 /*@C
766   TSAdjointComputeRHSJacobian - Deprecated, use TSComputeRHSJacobianP()
767 
768   Level: deprecated
769 
770 @*/
771 PetscErrorCode TSAdjointComputeRHSJacobian(TS ts,PetscReal t,Vec U,Mat Amat)
772 {
773   PetscErrorCode ierr;
774 
775   PetscFunctionBegin;
776   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
777   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
778   PetscValidPointer(Amat,4);
779 
780   PetscStackPush("TS user JacobianP function for sensitivity analysis");
781   ierr = (*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx); CHKERRQ(ierr);
782   PetscStackPop;
783   PetscFunctionReturn(0);
784 }
785 
786 /*@
787   TSAdjointComputeDRDYFunction - Deprecated, use TSComputeDRDUFunction()
788 
789   Level: deprecated
790 
791 @*/
792 PetscErrorCode TSAdjointComputeDRDYFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
793 {
794   PetscErrorCode ierr;
795 
796   PetscFunctionBegin;
797   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
798   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
799 
800   PetscStackPush("TS user DRDY function for sensitivity analysis");
801   ierr = (*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx); CHKERRQ(ierr);
802   PetscStackPop;
803   PetscFunctionReturn(0);
804 }
805 
806 /*@
807   TSAdjointComputeDRDPFunction - Deprecated, use TSComputeDRDPFunction()
808 
809   Level: deprecated
810 
811 @*/
812 PetscErrorCode TSAdjointComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
813 {
814   PetscErrorCode ierr;
815 
816   PetscFunctionBegin;
817   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
818   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
819 
820   PetscStackPush("TS user DRDP function for sensitivity analysis");
821   ierr = (*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx); CHKERRQ(ierr);
822   PetscStackPop;
823   PetscFunctionReturn(0);
824 }
825 
826 /*@C
827    TSAdjointMonitorSensi - monitors the first lambda sensitivity
828 
829    Level: intermediate
830 
831 .keywords: TS, set, monitor
832 
833 .seealso: TSAdjointMonitorSet()
834 @*/
835 PetscErrorCode TSAdjointMonitorSensi(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
836 {
837   PetscErrorCode ierr;
838   PetscViewer    viewer = vf->viewer;
839 
840   PetscFunctionBegin;
841   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
842   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
843   ierr = VecView(lambda[0],viewer);CHKERRQ(ierr);
844   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
845   PetscFunctionReturn(0);
846 }
847 
848 /*@C
849    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
850 
851    Collective on TS
852 
853    Input Parameters:
854 +  ts - TS object you wish to monitor
855 .  name - the monitor type one is seeking
856 .  help - message indicating what monitoring is done
857 .  manual - manual page for the monitor
858 .  monitor - the monitor function
859 -  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
860 
861    Level: developer
862 
863 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
864           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
865           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
866           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
867           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
868           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
869           PetscOptionsFList(), PetscOptionsEList()
870 @*/
871 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*))
872 {
873   PetscErrorCode    ierr;
874   PetscViewer       viewer;
875   PetscViewerFormat format;
876   PetscBool         flg;
877 
878   PetscFunctionBegin;
879   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts),((PetscObject) ts)->options,((PetscObject)ts)->prefix,name,&viewer,&format,&flg);CHKERRQ(ierr);
880   if (flg) {
881     PetscViewerAndFormat *vf;
882     ierr = PetscViewerAndFormatCreate(viewer,format,&vf);CHKERRQ(ierr);
883     ierr = PetscObjectDereference((PetscObject)viewer);CHKERRQ(ierr);
884     if (monitorsetup) {
885       ierr = (*monitorsetup)(ts,vf);CHKERRQ(ierr);
886     }
887     ierr = TSAdjointMonitorSet(ts,(PetscErrorCode (*)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*))monitor,vf,(PetscErrorCode (*)(void**))PetscViewerAndFormatDestroy);CHKERRQ(ierr);
888   }
889   PetscFunctionReturn(0);
890 }
891 
892 /*@C
893    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
894    timestep to display the iteration's  progress.
895 
896    Logically Collective on TS
897 
898    Input Parameters:
899 +  ts - the TS context obtained from TSCreate()
900 .  adjointmonitor - monitoring routine
901 .  adjointmctx - [optional] user-defined context for private data for the
902              monitor routine (use NULL if no context is desired)
903 -  adjointmonitordestroy - [optional] routine that frees monitor context
904           (may be NULL)
905 
906    Calling sequence of monitor:
907 $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)
908 
909 +    ts - the TS context
910 .    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
911                                been interpolated to)
912 .    time - current time
913 .    u - current iterate
914 .    numcost - number of cost functionos
915 .    lambda - sensitivities to initial conditions
916 .    mu - sensitivities to parameters
917 -    adjointmctx - [optional] adjoint monitoring context
918 
919    Notes:
920    This routine adds an additional monitor to the list of monitors that
921    already has been loaded.
922 
923    Fortran Notes:
924     Only a single monitor function can be set for each TS object
925 
926    Level: intermediate
927 
928 .keywords: TS, timestep, set, adjoint, monitor
929 
930 .seealso: TSAdjointMonitorCancel()
931 @*/
932 PetscErrorCode TSAdjointMonitorSet(TS ts,PetscErrorCode (*adjointmonitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*),void *adjointmctx,PetscErrorCode (*adjointmdestroy)(void**))
933 {
934   PetscErrorCode ierr;
935   PetscInt       i;
936   PetscBool      identical;
937 
938   PetscFunctionBegin;
939   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
940   for (i=0; i<ts->numbermonitors;i++) {
941     ierr = PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor,adjointmctx,adjointmdestroy,(PetscErrorCode (*)(void))ts->adjointmonitor[i],ts->adjointmonitorcontext[i],ts->adjointmonitordestroy[i],&identical);CHKERRQ(ierr);
942     if (identical) PetscFunctionReturn(0);
943   }
944   if (ts->numberadjointmonitors >= MAXTSMONITORS) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many adjoint monitors set");
945   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
946   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
947   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void*)adjointmctx;
948   PetscFunctionReturn(0);
949 }
950 
951 /*@C
952    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.
953 
954    Logically Collective on TS
955 
956    Input Parameters:
957 .  ts - the TS context obtained from TSCreate()
958 
959    Notes:
960    There is no way to remove a single, specific monitor.
961 
962    Level: intermediate
963 
964 .keywords: TS, timestep, set, adjoint, monitor
965 
966 .seealso: TSAdjointMonitorSet()
967 @*/
968 PetscErrorCode TSAdjointMonitorCancel(TS ts)
969 {
970   PetscErrorCode ierr;
971   PetscInt       i;
972 
973   PetscFunctionBegin;
974   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
975   for (i=0; i<ts->numberadjointmonitors; i++) {
976     if (ts->adjointmonitordestroy[i]) {
977       ierr = (*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
978     }
979   }
980   ts->numberadjointmonitors = 0;
981   PetscFunctionReturn(0);
982 }
983 
984 /*@C
985    TSAdjointMonitorDefault - the default monitor of adjoint computations
986 
987    Level: intermediate
988 
989 .keywords: TS, set, monitor
990 
991 .seealso: TSAdjointMonitorSet()
992 @*/
993 PetscErrorCode TSAdjointMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
994 {
995   PetscErrorCode ierr;
996   PetscViewer    viewer = vf->viewer;
997 
998   PetscFunctionBegin;
999   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
1000   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
1001   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1002   ierr = PetscViewerASCIIPrintf(viewer,"%D TS dt %g time %g%s",step,(double)ts->time_step,(double)ptime,ts->steprollback ? " (r)\n" : "\n");CHKERRQ(ierr);
1003   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1004   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1005   PetscFunctionReturn(0);
1006 }
1007 
1008 /*@C
1009    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint TS solvers by calling
1010    VecView() for the sensitivities to initial states at each timestep
1011 
1012    Collective on TS
1013 
1014    Input Parameters:
1015 +  ts - the TS context
1016 .  step - current time-step
1017 .  ptime - current time
1018 .  u - current state
1019 .  numcost - number of cost functions
1020 .  lambda - sensitivities to initial conditions
1021 .  mu - sensitivities to parameters
1022 -  dummy - either a viewer or NULL
1023 
1024    Level: intermediate
1025 
1026 .keywords: TS,  vector, adjoint, monitor, view
1027 
1028 .seealso: TSAdjointMonitorSet(), TSAdjointMonitorDefault(), VecView()
1029 @*/
1030 PetscErrorCode TSAdjointMonitorDrawSensi(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda,Vec *mu,void *dummy)
1031 {
1032   PetscErrorCode   ierr;
1033   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
1034   PetscDraw        draw;
1035   PetscReal        xl,yl,xr,yr,h;
1036   char             time[32];
1037 
1038   PetscFunctionBegin;
1039   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
1040 
1041   ierr = VecView(lambda[0],ictx->viewer);CHKERRQ(ierr);
1042   ierr = PetscViewerDrawGetDraw(ictx->viewer,0,&draw);CHKERRQ(ierr);
1043   ierr = PetscSNPrintf(time,32,"Timestep %d Time %g",(int)step,(double)ptime);CHKERRQ(ierr);
1044   ierr = PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr);CHKERRQ(ierr);
1045   h    = yl + .95*(yr - yl);
1046   ierr = PetscDrawStringCentered(draw,.5*(xl+xr),h,PETSC_DRAW_BLACK,time);CHKERRQ(ierr);
1047   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1048   PetscFunctionReturn(0);
1049 }
1050 
1051 /*
1052    TSAdjointSetFromOptions - Sets various TSAdjoint parameters from user options.
1053 
1054    Collective on TSAdjoint
1055 
1056    Input Parameter:
1057 .  ts - the TS context
1058 
1059    Options Database Keys:
1060 +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
1061 .  -ts_adjoint_monitor - print information at each adjoint time step
1062 -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically
1063 
1064    Level: developer
1065 
1066    Notes:
1067     This is not normally called directly by users
1068 
1069 .keywords: TS, trajectory, timestep, set, options, database
1070 
1071 .seealso: TSSetSaveTrajectory(), TSTrajectorySetUp()
1072 */
1073 PetscErrorCode TSAdjointSetFromOptions(PetscOptionItems *PetscOptionsObject,TS ts)
1074 {
1075   PetscBool      tflg,opt;
1076   PetscErrorCode ierr;
1077 
1078   PetscFunctionBegin;
1079   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
1080   ierr = PetscOptionsHead(PetscOptionsObject,"TS Adjoint options");CHKERRQ(ierr);
1081   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
1082   ierr = PetscOptionsBool("-ts_adjoint_solve","Solve the adjoint problem immediately after solving the forward problem","",tflg,&tflg,&opt);CHKERRQ(ierr);
1083   if (opt) {
1084     ierr = TSSetSaveTrajectory(ts);CHKERRQ(ierr);
1085     ts->adjoint_solve = tflg;
1086   }
1087   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor","Monitor adjoint timestep size","TSAdjointMonitorDefault",TSAdjointMonitorDefault,NULL);CHKERRQ(ierr);
1088   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor_sensi","Monitor sensitivity in the adjoint computation","TSAdjointMonitorSensi",TSAdjointMonitorSensi,NULL);CHKERRQ(ierr);
1089   opt  = PETSC_FALSE;
1090   ierr = PetscOptionsName("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",&opt);CHKERRQ(ierr);
1091   if (opt) {
1092     TSMonitorDrawCtx ctx;
1093     PetscInt         howoften = 1;
1094 
1095     ierr = PetscOptionsInt("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",howoften,&howoften,NULL);CHKERRQ(ierr);
1096     ierr = TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts),0,0,PETSC_DECIDE,PETSC_DECIDE,300,300,howoften,&ctx);CHKERRQ(ierr);
1097     ierr = TSAdjointMonitorSet(ts,TSAdjointMonitorDrawSensi,ctx,(PetscErrorCode (*)(void**))TSMonitorDrawCtxDestroy);CHKERRQ(ierr);
1098   }
1099   PetscFunctionReturn(0);
1100 }
1101 
1102 /*@
1103    TSAdjointStep - Steps one time step backward in the adjoint run
1104 
1105    Collective on TS
1106 
1107    Input Parameter:
1108 .  ts - the TS context obtained from TSCreate()
1109 
1110    Level: intermediate
1111 
1112 .keywords: TS, adjoint, step
1113 
1114 .seealso: TSAdjointSetUp(), TSAdjointSolve()
1115 @*/
1116 PetscErrorCode TSAdjointStep(TS ts)
1117 {
1118   DM               dm;
1119   PetscErrorCode   ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1123   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
1124   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1125 
1126   ts->reason = TS_CONVERGED_ITERATING;
1127   ts->ptime_prev = ts->ptime;
1128   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);
1129   ierr = PetscLogEventBegin(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1130   ierr = (*ts->ops->adjointstep)(ts);CHKERRQ(ierr);
1131   ierr = PetscLogEventEnd(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1132   ts->adjoint_steps++; ts->steps--;
1133 
1134   if (ts->reason < 0) {
1135     if (ts->errorifstepfailed) {
1136       if (ts->reason == TSADJOINT_DIVERGED_LINEAR_SOLVE) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1137       else SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1138     }
1139   } else if (!ts->reason) {
1140     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1141   }
1142   PetscFunctionReturn(0);
1143 }
1144 
1145 /*@
1146    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE
1147 
1148    Collective on TS
1149 
1150    Input Parameter:
1151 .  ts - the TS context obtained from TSCreate()
1152 
1153    Options Database:
1154 . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values
1155 
1156    Level: intermediate
1157 
1158    Notes:
1159    This must be called after a call to TSSolve() that solves the forward problem
1160 
1161    By default this will integrate back to the initial time, one can use TSAdjointSetSteps() to step back to a later time
1162 
1163 .keywords: TS, timestep, solve
1164 
1165 .seealso: TSCreate(), TSSetCostGradients(), TSSetSolution(), TSAdjointStep()
1166 @*/
1167 PetscErrorCode TSAdjointSolve(TS ts)
1168 {
1169   PetscErrorCode    ierr;
1170 
1171   PetscFunctionBegin;
1172   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1173   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1174 
1175   /* reset time step and iteration counters */
1176   ts->adjoint_steps     = 0;
1177   ts->ksp_its           = 0;
1178   ts->snes_its          = 0;
1179   ts->num_snes_failures = 0;
1180   ts->reject            = 0;
1181   ts->reason            = TS_CONVERGED_ITERATING;
1182 
1183   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
1184   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1185 
1186   while (!ts->reason) {
1187     ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1188     ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1189     ierr = TSAdjointEventHandler(ts);CHKERRQ(ierr);
1190     ierr = TSAdjointStep(ts);CHKERRQ(ierr);
1191     if (ts->vec_costintegral && !ts->costintegralfwd) {
1192       ierr = TSAdjointCostIntegral(ts);CHKERRQ(ierr);
1193     }
1194   }
1195   ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1196   ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1197   ts->solvetime = ts->ptime;
1198   ierr = TSTrajectoryViewFromOptions(ts->trajectory,NULL,"-ts_trajectory_view");CHKERRQ(ierr);
1199   ierr = VecViewFromOptions(ts->vecs_sensi[0],(PetscObject) ts, "-ts_adjoint_view_solution");CHKERRQ(ierr);
1200   ts->adjoint_max_steps = 0;
1201   PetscFunctionReturn(0);
1202 }
1203 
1204 /*@C
1205    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using TSAdjointMonitorSet()
1206 
1207    Collective on TS
1208 
1209    Input Parameters:
1210 +  ts - time stepping context obtained from TSCreate()
1211 .  step - step number that has just completed
1212 .  ptime - model time of the state
1213 .  u - state at the current model time
1214 .  numcost - number of cost functions (dimension of lambda  or mu)
1215 .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
1216 -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
1217 
1218    Notes:
1219    TSAdjointMonitor() is typically used automatically within the time stepping implementations.
1220    Users would almost never call this routine directly.
1221 
1222    Level: developer
1223 
1224 .keywords: TS, timestep
1225 @*/
1226 PetscErrorCode TSAdjointMonitor(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda, Vec *mu)
1227 {
1228   PetscErrorCode ierr;
1229   PetscInt       i,n = ts->numberadjointmonitors;
1230 
1231   PetscFunctionBegin;
1232   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1233   PetscValidHeaderSpecific(u,VEC_CLASSID,4);
1234   ierr = VecLockReadPush(u);CHKERRQ(ierr);
1235   for (i=0; i<n; i++) {
1236     ierr = (*ts->adjointmonitor[i])(ts,step,ptime,u,numcost,lambda,mu,ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
1237   }
1238   ierr = VecLockReadPop(u);CHKERRQ(ierr);
1239   PetscFunctionReturn(0);
1240 }
1241 
1242 /*@
1243  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.
1244 
1245  Collective on TS
1246 
1247  Input Arguments:
1248  .  ts - time stepping context
1249 
1250  Level: advanced
1251 
1252  Notes:
1253  This function cannot be called until TSAdjointStep() has been completed.
1254 
1255  .seealso: TSAdjointSolve(), TSAdjointStep
1256  @*/
1257 PetscErrorCode TSAdjointCostIntegral(TS ts)
1258 {
1259     PetscErrorCode ierr;
1260     PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1261     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);
1262     ierr = (*ts->ops->adjointintegral)(ts);CHKERRQ(ierr);
1263     PetscFunctionReturn(0);
1264 }
1265 
1266 /* ------------------ Forward (tangent linear) sensitivity  ------------------*/
1267 
1268 /*@
1269   TSForwardSetUp - Sets up the internal data structures for the later use
1270   of forward sensitivity analysis
1271 
1272   Collective on TS
1273 
1274   Input Parameter:
1275 . ts - the TS context obtained from TSCreate()
1276 
1277   Level: advanced
1278 
1279 .keywords: TS, forward sensitivity, setup
1280 
1281 .seealso: TSCreate(), TSDestroy(), TSSetUp()
1282 @*/
1283 PetscErrorCode TSForwardSetUp(TS ts)
1284 {
1285   PetscErrorCode ierr;
1286 
1287   PetscFunctionBegin;
1288   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1289   if (ts->forwardsetupcalled) PetscFunctionReturn(0);
1290   if (ts->vec_costintegral && !ts->vecs_integral_sensip ) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call TSForwardSetIntegralGradients() before TSSetCostIntegrand()");
1291   if (ts->vecs_integral_sensip) {
1292     ierr = VecDuplicateVecs(ts->vec_sol,ts->numcost,&ts->vecs_drdu);CHKERRQ(ierr);
1293     ierr = VecDuplicateVecs(ts->vecs_integral_sensip[0],ts->numcost,&ts->vecs_drdp);CHKERRQ(ierr);
1294   }
1295 
1296   if (ts->ops->forwardsetup) {
1297     ierr = (*ts->ops->forwardsetup)(ts);CHKERRQ(ierr);
1298   }
1299   ts->forwardsetupcalled = PETSC_TRUE;
1300   PetscFunctionReturn(0);
1301 }
1302 
1303 /*@
1304   TSForwardReset - Reset the internal data structures used by forward sensitivity analysis
1305 
1306   Collective on TS
1307 
1308   Input Parameter:
1309 . ts - the TS context obtained from TSCreate()
1310 
1311   Level: advanced
1312 
1313 .keywords: TS, forward sensitivity, reset
1314 
1315 .seealso: TSCreate(), TSDestroy(), TSForwardSetUp()
1316 @*/
1317 PetscErrorCode TSForwardReset(TS ts)
1318 {
1319   PetscErrorCode ierr;
1320 
1321   PetscFunctionBegin;
1322   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1323   if (ts->ops->forwardreset) {
1324     ierr = (*ts->ops->forwardreset)(ts);CHKERRQ(ierr);
1325   }
1326   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1327   ts->vecs_integral_sensip = NULL;
1328   ts->forward_solve        = PETSC_FALSE;
1329   ts->forwardsetupcalled   = PETSC_FALSE;
1330   PetscFunctionReturn(0);
1331 }
1332 
1333 /*@
1334   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.
1335 
1336   Input Parameter:
1337 . ts- the TS context obtained from TSCreate()
1338 . numfwdint- number of integrals
1339 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1340 
1341   Level: intermediate
1342 
1343 .keywords: TS, forward sensitivity
1344 
1345 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1346 @*/
1347 PetscErrorCode TSForwardSetIntegralGradients(TS ts,PetscInt numfwdint,Vec *vp)
1348 {
1349   PetscFunctionBegin;
1350   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1351   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()");
1352   if (!ts->numcost) ts->numcost = numfwdint;
1353 
1354   ts->vecs_integral_sensip = vp;
1355   PetscFunctionReturn(0);
1356 }
1357 
1358 /*@
1359   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.
1360 
1361   Input Parameter:
1362 . ts- the TS context obtained from TSCreate()
1363 
1364   Output Parameter:
1365 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1366 
1367   Level: intermediate
1368 
1369 .keywords: TS, forward sensitivity
1370 
1371 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1372 @*/
1373 PetscErrorCode TSForwardGetIntegralGradients(TS ts,PetscInt *numfwdint,Vec **vp)
1374 {
1375   PetscFunctionBegin;
1376   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1377   PetscValidPointer(vp,3);
1378   if (numfwdint) *numfwdint = ts->numcost;
1379   if (vp) *vp = ts->vecs_integral_sensip;
1380   PetscFunctionReturn(0);
1381 }
1382 
1383 /*@
1384   TSForwardStep - Compute the forward sensitivity for one time step.
1385 
1386   Collective on TS
1387 
1388   Input Arguments:
1389 . ts - time stepping context
1390 
1391   Level: advanced
1392 
1393   Notes:
1394   This function cannot be called until TSStep() has been completed.
1395 
1396 .keywords: TS, forward sensitivity
1397 
1398 .seealso: TSForwardSetSensitivities(), TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardSetUp()
1399 @*/
1400 PetscErrorCode TSForwardStep(TS ts)
1401 {
1402   PetscErrorCode ierr;
1403   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1404   if (!ts->ops->forwardstep) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide forward sensitivity analysis",((PetscObject)ts)->type_name);
1405   ierr = PetscLogEventBegin(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1406   ierr = (*ts->ops->forwardstep)(ts);CHKERRQ(ierr);
1407   ierr = PetscLogEventEnd(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 /*@
1412   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.
1413 
1414   Logically Collective on TS and Vec
1415 
1416   Input Parameters:
1417 + ts - the TS context obtained from TSCreate()
1418 . nump - number of parameters
1419 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1420 
1421   Level: beginner
1422 
1423   Notes:
1424   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
1425   This function turns on a flag to trigger TSSolve() to compute forward sensitivities automatically.
1426   You must call this function before TSSolve().
1427   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.
1428 
1429 .keywords: TS, timestep, set, forward sensitivity, initial values
1430 
1431 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1432 @*/
1433 PetscErrorCode TSForwardSetSensitivities(TS ts,PetscInt nump,Mat Smat)
1434 {
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1439   PetscValidHeaderSpecific(Smat,MAT_CLASSID,3);
1440   ts->forward_solve  = PETSC_TRUE;
1441   if (nump == PETSC_DEFAULT) {
1442     ierr = MatGetSize(Smat,NULL,&ts->num_parameters);CHKERRQ(ierr);
1443   } else ts->num_parameters = nump;
1444   ierr = PetscObjectReference((PetscObject)Smat);CHKERRQ(ierr);
1445   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1446   ts->mat_sensip = Smat;
1447   PetscFunctionReturn(0);
1448 }
1449 
1450 /*@
1451   TSForwardGetSensitivities - Returns the trajectory sensitivities
1452 
1453   Not Collective, but Vec returned is parallel if TS is parallel
1454 
1455   Output Parameter:
1456 + ts - the TS context obtained from TSCreate()
1457 . nump - number of parameters
1458 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1459 
1460   Level: intermediate
1461 
1462 .keywords: TS, forward sensitivity
1463 
1464 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1465 @*/
1466 PetscErrorCode TSForwardGetSensitivities(TS ts,PetscInt *nump,Mat *Smat)
1467 {
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1470   if (nump) *nump = ts->num_parameters;
1471   if (Smat) *Smat = ts->mat_sensip;
1472   PetscFunctionReturn(0);
1473 }
1474 
1475 /*@
1476    TSForwardCostIntegral - Evaluate the cost integral in the forward run.
1477 
1478    Collective on TS
1479 
1480    Input Arguments:
1481 .  ts - time stepping context
1482 
1483    Level: advanced
1484 
1485    Notes:
1486    This function cannot be called until TSStep() has been completed.
1487 
1488 .seealso: TSSolve(), TSAdjointCostIntegral()
1489 @*/
1490 PetscErrorCode TSForwardCostIntegral(TS ts)
1491 {
1492   PetscErrorCode ierr;
1493   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1494   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);
1495   ierr = (*ts->ops->forwardintegral)(ts);CHKERRQ(ierr);
1496   PetscFunctionReturn(0);
1497 }
1498 
1499 /*@
1500   TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities
1501 
1502   Collective on TS and Mat
1503 
1504   Input Parameter
1505 + ts - the TS context obtained from TSCreate()
1506 - didp - parametric sensitivities of the initial condition
1507 
1508   Level: intermediate
1509 
1510   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.
1511 
1512 .seealso: TSForwardSetSensitivities()
1513 @*/
1514 PetscErrorCode TSForwardSetInitialSensitivities(TS ts,Mat didp)
1515 {
1516   Vec            sp;
1517   PetscInt       lsize;
1518   PetscScalar    *xarr;
1519   PetscErrorCode ierr;
1520 
1521   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1522   if (ts->vec_dir) { /* indicates second-order adjoint caculation */
1523     Mat A;
1524     ierr = TSForwardGetSensitivities(ts,NULL,&A);CHKERRQ(ierr);
1525     if (!A) { /* create a single-column dense matrix */
1526       ierr = VecGetLocalSize(ts->vec_dir,&lsize);CHKERRQ(ierr);
1527       ierr = MatCreateDense(PETSC_COMM_WORLD,lsize,PETSC_DECIDE,PETSC_DECIDE,1,NULL,&A);CHKERRQ(ierr);
1528     }
1529     ierr = VecDuplicate(ts->vec_dir,&sp);CHKERRQ(ierr);
1530     ierr = MatDenseGetColumn(A,0,&xarr);CHKERRQ(ierr);
1531     ierr = VecPlaceArray(sp,xarr);CHKERRQ(ierr);
1532     if (didp) {
1533       ierr = MatMult(didp,ts->vec_dir,sp);CHKERRQ(ierr);
1534     } else { /* identity matrix assumed */
1535       ierr = VecCopy(ts->vec_dir,sp);CHKERRQ(ierr);
1536     }
1537     ierr = VecResetArray(sp);CHKERRQ(ierr);
1538     ierr = MatDenseRestoreColumn(A,&xarr);CHKERRQ(ierr);
1539     ierr = VecDestroy(&sp);CHKERRQ(ierr);
1540     ierr = TSForwardSetSensitivities(ts,1,A);CHKERRQ(ierr);
1541   } else {
1542     PetscValidHeaderSpecific(didp,MAT_CLASSID,2);
1543     if (!ts->mat_sensip) {
1544       ierr = TSForwardSetSensitivities(ts,PETSC_DEFAULT,didp);CHKERRQ(ierr);
1545     }
1546   }
1547   PetscFunctionReturn(0);
1548 }
1549 
1550 /*@
1551    TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages
1552 
1553    Input Parameter:
1554 .  ts - the TS context obtained from TSCreate()
1555 
1556    Output Parameters:
1557 +  ns - nu
1558 -  S - tangent linear sensitivities at the intermediate stages
1559 
1560    Level: advanced
1561 
1562 .keywords: TS, second-order adjoint, forward sensitivity
1563 @*/
1564 PetscErrorCode TSForwardGetStages(TS ts,PetscInt *ns,Mat **S)
1565 {
1566   PetscErrorCode ierr;
1567 
1568   PetscFunctionBegin;
1569   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1570 
1571   if (!ts->ops->getstages) *S=NULL;
1572   else {
1573     ierr = (*ts->ops->forwardgetstages)(ts,ns,S);CHKERRQ(ierr);
1574   }
1575   PetscFunctionReturn(0);
1576 }
1577