xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 7adebdde874734bc3a04bfb03517869e99da1cdf)
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 .keywords: TS, sensitivity, second-order adjoint
561 
562 .seealso: TSAdjointInitializeForward()
563 @*/
564 PetscErrorCode TSSetCostHessianProducts(TS ts,PetscInt numcost,Vec *lambda2,Vec *mu2,Vec dir)
565 {
566   PetscFunctionBegin;
567   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
568   PetscValidPointer(lambda2,2);
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   ts->vecs_sensi         = NULL;
700   ts->vecs_sensip        = NULL;
701   ts->vecs_sensi2        = NULL;
702   ts->vecs_sensip2       = NULL;
703   ts->vec_dir            = NULL;
704   ts->adjointsetupcalled = PETSC_FALSE;
705   PetscFunctionReturn(0);
706 }
707 
708 /*@
709    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time
710 
711    Logically Collective on TS
712 
713    Input Parameters:
714 +  ts - the TS context obtained from TSCreate()
715 .  steps - number of steps to use
716 
717    Level: intermediate
718 
719    Notes:
720     Normally one does not call this and TSAdjointSolve() integrates back to the original timestep. One can call this
721           so as to integrate back to less than the original timestep
722 
723 .keywords: TS, timestep, set, maximum, iterations
724 
725 .seealso: TSSetExactFinalTime()
726 @*/
727 PetscErrorCode TSAdjointSetSteps(TS ts,PetscInt steps)
728 {
729   PetscFunctionBegin;
730   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
731   PetscValidLogicalCollectiveInt(ts,steps,2);
732   if (steps < 0) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back a negative number of steps");
733   if (steps > ts->steps) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back more than the total number of forward steps");
734   ts->adjoint_max_steps = steps;
735   PetscFunctionReturn(0);
736 }
737 
738 /*@C
739   TSAdjointSetRHSJacobian - Deprecated, use TSSetRHSJacobianP()
740 
741   Level: deprecated
742 
743 @*/
744 PetscErrorCode TSAdjointSetRHSJacobian(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
745 {
746   PetscErrorCode ierr;
747 
748   PetscFunctionBegin;
749   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
750   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
751 
752   ts->rhsjacobianp    = func;
753   ts->rhsjacobianpctx = ctx;
754   if(Amat) {
755     ierr = PetscObjectReference((PetscObject)Amat);CHKERRQ(ierr);
756     ierr = MatDestroy(&ts->Jacp);CHKERRQ(ierr);
757     ts->Jacp = Amat;
758   }
759   PetscFunctionReturn(0);
760 }
761 
762 /*@C
763   TSAdjointComputeRHSJacobian - Deprecated, use TSComputeRHSJacobianP()
764 
765   Level: deprecated
766 
767 @*/
768 PetscErrorCode TSAdjointComputeRHSJacobian(TS ts,PetscReal t,Vec U,Mat Amat)
769 {
770   PetscErrorCode ierr;
771 
772   PetscFunctionBegin;
773   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
774   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
775   PetscValidPointer(Amat,4);
776 
777   PetscStackPush("TS user JacobianP function for sensitivity analysis");
778   ierr = (*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx); CHKERRQ(ierr);
779   PetscStackPop;
780   PetscFunctionReturn(0);
781 }
782 
783 /*@
784   TSAdjointComputeDRDYFunction - Deprecated, use TSComputeDRDUFunction()
785 
786   Level: deprecated
787 
788 @*/
789 PetscErrorCode TSAdjointComputeDRDYFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
790 {
791   PetscErrorCode ierr;
792 
793   PetscFunctionBegin;
794   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
795   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
796 
797   PetscStackPush("TS user DRDY function for sensitivity analysis");
798   ierr = (*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx); CHKERRQ(ierr);
799   PetscStackPop;
800   PetscFunctionReturn(0);
801 }
802 
803 /*@
804   TSAdjointComputeDRDPFunction - Deprecated, use TSComputeDRDPFunction()
805 
806   Level: deprecated
807 
808 @*/
809 PetscErrorCode TSAdjointComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
810 {
811   PetscErrorCode ierr;
812 
813   PetscFunctionBegin;
814   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
815   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
816 
817   PetscStackPush("TS user DRDP function for sensitivity analysis");
818   ierr = (*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx); CHKERRQ(ierr);
819   PetscStackPop;
820   PetscFunctionReturn(0);
821 }
822 
823 /*@C
824    TSAdjointMonitorSensi - monitors the first lambda sensitivity
825 
826    Level: intermediate
827 
828 .keywords: TS, set, monitor
829 
830 .seealso: TSAdjointMonitorSet()
831 @*/
832 PetscErrorCode TSAdjointMonitorSensi(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
833 {
834   PetscErrorCode ierr;
835   PetscViewer    viewer = vf->viewer;
836 
837   PetscFunctionBegin;
838   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
839   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
840   ierr = VecView(lambda[0],viewer);CHKERRQ(ierr);
841   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
842   PetscFunctionReturn(0);
843 }
844 
845 /*@C
846    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
847 
848    Collective on TS
849 
850    Input Parameters:
851 +  ts - TS object you wish to monitor
852 .  name - the monitor type one is seeking
853 .  help - message indicating what monitoring is done
854 .  manual - manual page for the monitor
855 .  monitor - the monitor function
856 -  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
857 
858    Level: developer
859 
860 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
861           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
862           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
863           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
864           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
865           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
866           PetscOptionsFList(), PetscOptionsEList()
867 @*/
868 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*))
869 {
870   PetscErrorCode    ierr;
871   PetscViewer       viewer;
872   PetscViewerFormat format;
873   PetscBool         flg;
874 
875   PetscFunctionBegin;
876   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts),((PetscObject) ts)->options,((PetscObject)ts)->prefix,name,&viewer,&format,&flg);CHKERRQ(ierr);
877   if (flg) {
878     PetscViewerAndFormat *vf;
879     ierr = PetscViewerAndFormatCreate(viewer,format,&vf);CHKERRQ(ierr);
880     ierr = PetscObjectDereference((PetscObject)viewer);CHKERRQ(ierr);
881     if (monitorsetup) {
882       ierr = (*monitorsetup)(ts,vf);CHKERRQ(ierr);
883     }
884     ierr = TSAdjointMonitorSet(ts,(PetscErrorCode (*)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*))monitor,vf,(PetscErrorCode (*)(void**))PetscViewerAndFormatDestroy);CHKERRQ(ierr);
885   }
886   PetscFunctionReturn(0);
887 }
888 
889 /*@C
890    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
891    timestep to display the iteration's  progress.
892 
893    Logically Collective on TS
894 
895    Input Parameters:
896 +  ts - the TS context obtained from TSCreate()
897 .  adjointmonitor - monitoring routine
898 .  adjointmctx - [optional] user-defined context for private data for the
899              monitor routine (use NULL if no context is desired)
900 -  adjointmonitordestroy - [optional] routine that frees monitor context
901           (may be NULL)
902 
903    Calling sequence of monitor:
904 $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)
905 
906 +    ts - the TS context
907 .    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
908                                been interpolated to)
909 .    time - current time
910 .    u - current iterate
911 .    numcost - number of cost functionos
912 .    lambda - sensitivities to initial conditions
913 .    mu - sensitivities to parameters
914 -    adjointmctx - [optional] adjoint monitoring context
915 
916    Notes:
917    This routine adds an additional monitor to the list of monitors that
918    already has been loaded.
919 
920    Fortran Notes:
921     Only a single monitor function can be set for each TS object
922 
923    Level: intermediate
924 
925 .keywords: TS, timestep, set, adjoint, monitor
926 
927 .seealso: TSAdjointMonitorCancel()
928 @*/
929 PetscErrorCode TSAdjointMonitorSet(TS ts,PetscErrorCode (*adjointmonitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*),void *adjointmctx,PetscErrorCode (*adjointmdestroy)(void**))
930 {
931   PetscErrorCode ierr;
932   PetscInt       i;
933   PetscBool      identical;
934 
935   PetscFunctionBegin;
936   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
937   for (i=0; i<ts->numbermonitors;i++) {
938     ierr = PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor,adjointmctx,adjointmdestroy,(PetscErrorCode (*)(void))ts->adjointmonitor[i],ts->adjointmonitorcontext[i],ts->adjointmonitordestroy[i],&identical);CHKERRQ(ierr);
939     if (identical) PetscFunctionReturn(0);
940   }
941   if (ts->numberadjointmonitors >= MAXTSMONITORS) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many adjoint monitors set");
942   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
943   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
944   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void*)adjointmctx;
945   PetscFunctionReturn(0);
946 }
947 
948 /*@C
949    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.
950 
951    Logically Collective on TS
952 
953    Input Parameters:
954 .  ts - the TS context obtained from TSCreate()
955 
956    Notes:
957    There is no way to remove a single, specific monitor.
958 
959    Level: intermediate
960 
961 .keywords: TS, timestep, set, adjoint, monitor
962 
963 .seealso: TSAdjointMonitorSet()
964 @*/
965 PetscErrorCode TSAdjointMonitorCancel(TS ts)
966 {
967   PetscErrorCode ierr;
968   PetscInt       i;
969 
970   PetscFunctionBegin;
971   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
972   for (i=0; i<ts->numberadjointmonitors; i++) {
973     if (ts->adjointmonitordestroy[i]) {
974       ierr = (*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
975     }
976   }
977   ts->numberadjointmonitors = 0;
978   PetscFunctionReturn(0);
979 }
980 
981 /*@C
982    TSAdjointMonitorDefault - the default monitor of adjoint computations
983 
984    Level: intermediate
985 
986 .keywords: TS, set, monitor
987 
988 .seealso: TSAdjointMonitorSet()
989 @*/
990 PetscErrorCode TSAdjointMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
991 {
992   PetscErrorCode ierr;
993   PetscViewer    viewer = vf->viewer;
994 
995   PetscFunctionBegin;
996   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
997   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
998   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
999   ierr = PetscViewerASCIIPrintf(viewer,"%D TS dt %g time %g%s",step,(double)ts->time_step,(double)ptime,ts->steprollback ? " (r)\n" : "\n");CHKERRQ(ierr);
1000   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
1001   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1002   PetscFunctionReturn(0);
1003 }
1004 
1005 /*@C
1006    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint TS solvers by calling
1007    VecView() for the sensitivities to initial states at each timestep
1008 
1009    Collective on TS
1010 
1011    Input Parameters:
1012 +  ts - the TS context
1013 .  step - current time-step
1014 .  ptime - current time
1015 .  u - current state
1016 .  numcost - number of cost functions
1017 .  lambda - sensitivities to initial conditions
1018 .  mu - sensitivities to parameters
1019 -  dummy - either a viewer or NULL
1020 
1021    Level: intermediate
1022 
1023 .keywords: TS,  vector, adjoint, monitor, view
1024 
1025 .seealso: TSAdjointMonitorSet(), TSAdjointMonitorDefault(), VecView()
1026 @*/
1027 PetscErrorCode TSAdjointMonitorDrawSensi(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda,Vec *mu,void *dummy)
1028 {
1029   PetscErrorCode   ierr;
1030   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
1031   PetscDraw        draw;
1032   PetscReal        xl,yl,xr,yr,h;
1033   char             time[32];
1034 
1035   PetscFunctionBegin;
1036   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
1037 
1038   ierr = VecView(lambda[0],ictx->viewer);CHKERRQ(ierr);
1039   ierr = PetscViewerDrawGetDraw(ictx->viewer,0,&draw);CHKERRQ(ierr);
1040   ierr = PetscSNPrintf(time,32,"Timestep %d Time %g",(int)step,(double)ptime);CHKERRQ(ierr);
1041   ierr = PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr);CHKERRQ(ierr);
1042   h    = yl + .95*(yr - yl);
1043   ierr = PetscDrawStringCentered(draw,.5*(xl+xr),h,PETSC_DRAW_BLACK,time);CHKERRQ(ierr);
1044   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1045   PetscFunctionReturn(0);
1046 }
1047 
1048 /*
1049    TSAdjointSetFromOptions - Sets various TSAdjoint parameters from user options.
1050 
1051    Collective on TSAdjoint
1052 
1053    Input Parameter:
1054 .  ts - the TS context
1055 
1056    Options Database Keys:
1057 +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
1058 .  -ts_adjoint_monitor - print information at each adjoint time step
1059 -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically
1060 
1061    Level: developer
1062 
1063    Notes:
1064     This is not normally called directly by users
1065 
1066 .keywords: TS, trajectory, timestep, set, options, database
1067 
1068 .seealso: TSSetSaveTrajectory(), TSTrajectorySetUp()
1069 */
1070 PetscErrorCode TSAdjointSetFromOptions(PetscOptionItems *PetscOptionsObject,TS ts)
1071 {
1072   PetscBool      tflg,opt;
1073   PetscErrorCode ierr;
1074 
1075   PetscFunctionBegin;
1076   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
1077   ierr = PetscOptionsHead(PetscOptionsObject,"TS Adjoint options");CHKERRQ(ierr);
1078   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
1079   ierr = PetscOptionsBool("-ts_adjoint_solve","Solve the adjoint problem immediately after solving the forward problem","",tflg,&tflg,&opt);CHKERRQ(ierr);
1080   if (opt) {
1081     ierr = TSSetSaveTrajectory(ts);CHKERRQ(ierr);
1082     ts->adjoint_solve = tflg;
1083   }
1084   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor","Monitor adjoint timestep size","TSAdjointMonitorDefault",TSAdjointMonitorDefault,NULL);CHKERRQ(ierr);
1085   ierr = TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor_sensi","Monitor sensitivity in the adjoint computation","TSAdjointMonitorSensi",TSAdjointMonitorSensi,NULL);CHKERRQ(ierr);
1086   opt  = PETSC_FALSE;
1087   ierr = PetscOptionsName("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",&opt);CHKERRQ(ierr);
1088   if (opt) {
1089     TSMonitorDrawCtx ctx;
1090     PetscInt         howoften = 1;
1091 
1092     ierr = PetscOptionsInt("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",howoften,&howoften,NULL);CHKERRQ(ierr);
1093     ierr = TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts),0,0,PETSC_DECIDE,PETSC_DECIDE,300,300,howoften,&ctx);CHKERRQ(ierr);
1094     ierr = TSAdjointMonitorSet(ts,TSAdjointMonitorDrawSensi,ctx,(PetscErrorCode (*)(void**))TSMonitorDrawCtxDestroy);CHKERRQ(ierr);
1095   }
1096   PetscFunctionReturn(0);
1097 }
1098 
1099 /*@
1100    TSAdjointStep - Steps one time step backward in the adjoint run
1101 
1102    Collective on TS
1103 
1104    Input Parameter:
1105 .  ts - the TS context obtained from TSCreate()
1106 
1107    Level: intermediate
1108 
1109 .keywords: TS, adjoint, step
1110 
1111 .seealso: TSAdjointSetUp(), TSAdjointSolve()
1112 @*/
1113 PetscErrorCode TSAdjointStep(TS ts)
1114 {
1115   DM               dm;
1116   PetscErrorCode   ierr;
1117 
1118   PetscFunctionBegin;
1119   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1120   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
1121   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1122 
1123   ierr = VecViewFromOptions(ts->vec_sol,(PetscObject)ts,"-ts_view_solution");CHKERRQ(ierr);
1124 
1125   ts->reason = TS_CONVERGED_ITERATING;
1126   ts->ptime_prev = ts->ptime;
1127   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);
1128   ierr = PetscLogEventBegin(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1129   ierr = (*ts->ops->adjointstep)(ts);CHKERRQ(ierr);
1130   ierr = PetscLogEventEnd(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1131   ts->adjoint_steps++; ts->steps--;
1132 
1133   if (ts->reason < 0) {
1134     if (ts->errorifstepfailed) {
1135       if (ts->reason == TS_DIVERGED_NONLINEAR_SOLVE) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep has failed due to %s, increase -ts_max_snes_failures or make negative to attempt recovery",TSConvergedReasons[ts->reason]);
1136       else if (ts->reason == TS_DIVERGED_STEP_REJECTED) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep has failed due to %s, increase -ts_max_reject or make negative to attempt recovery",TSConvergedReasons[ts->reason]);
1137       else SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep 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