xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 05c9950e5bf5e2fb2fbf8b6ba335b0596453c987)
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   ierr = VecViewFromOptions(ts->vec_sol,(PetscObject)ts,"-ts_view_solution");CHKERRQ(ierr);
1127 
1128   ts->reason = TS_CONVERGED_ITERATING;
1129   ts->ptime_prev = ts->ptime;
1130   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);
1131   ierr = PetscLogEventBegin(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1132   ierr = (*ts->ops->adjointstep)(ts);CHKERRQ(ierr);
1133   ierr = PetscLogEventEnd(TS_AdjointStep,ts,0,0,0);CHKERRQ(ierr);
1134   ts->adjoint_steps++; ts->steps--;
1135 
1136   if (ts->reason < 0) {
1137     if (ts->errorifstepfailed) {
1138       if (ts->reason == TSADJOINT_DIVERGED_LINEAR_SOLVE) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1139       else SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1140     }
1141   } else if (!ts->reason) {
1142     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1143   }
1144   PetscFunctionReturn(0);
1145 }
1146 
1147 /*@
1148    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE
1149 
1150    Collective on TS
1151 
1152    Input Parameter:
1153 .  ts - the TS context obtained from TSCreate()
1154 
1155    Options Database:
1156 . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values
1157 
1158    Level: intermediate
1159 
1160    Notes:
1161    This must be called after a call to TSSolve() that solves the forward problem
1162 
1163    By default this will integrate back to the initial time, one can use TSAdjointSetSteps() to step back to a later time
1164 
1165 .keywords: TS, timestep, solve
1166 
1167 .seealso: TSCreate(), TSSetCostGradients(), TSSetSolution(), TSAdjointStep()
1168 @*/
1169 PetscErrorCode TSAdjointSolve(TS ts)
1170 {
1171   PetscErrorCode    ierr;
1172 
1173   PetscFunctionBegin;
1174   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1175   ierr = TSAdjointSetUp(ts);CHKERRQ(ierr);
1176 
1177   /* reset time step and iteration counters */
1178   ts->adjoint_steps     = 0;
1179   ts->ksp_its           = 0;
1180   ts->snes_its          = 0;
1181   ts->num_snes_failures = 0;
1182   ts->reject            = 0;
1183   ts->reason            = TS_CONVERGED_ITERATING;
1184 
1185   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
1186   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1187 
1188   while (!ts->reason) {
1189     ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1190     ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1191     ierr = TSAdjointEventHandler(ts);CHKERRQ(ierr);
1192     ierr = TSAdjointStep(ts);CHKERRQ(ierr);
1193     if (ts->vec_costintegral && !ts->costintegralfwd) {
1194       ierr = TSAdjointCostIntegral(ts);CHKERRQ(ierr);
1195     }
1196   }
1197   ierr = TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);CHKERRQ(ierr);
1198   ierr = TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);CHKERRQ(ierr);
1199   ts->solvetime = ts->ptime;
1200   ierr = TSTrajectoryViewFromOptions(ts->trajectory,NULL,"-ts_trajectory_view");CHKERRQ(ierr);
1201   ierr = VecViewFromOptions(ts->vecs_sensi[0],(PetscObject) ts, "-ts_adjoint_view_solution");CHKERRQ(ierr);
1202   ts->adjoint_max_steps = 0;
1203   PetscFunctionReturn(0);
1204 }
1205 
1206 /*@C
1207    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using TSAdjointMonitorSet()
1208 
1209    Collective on TS
1210 
1211    Input Parameters:
1212 +  ts - time stepping context obtained from TSCreate()
1213 .  step - step number that has just completed
1214 .  ptime - model time of the state
1215 .  u - state at the current model time
1216 .  numcost - number of cost functions (dimension of lambda  or mu)
1217 .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
1218 -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
1219 
1220    Notes:
1221    TSAdjointMonitor() is typically used automatically within the time stepping implementations.
1222    Users would almost never call this routine directly.
1223 
1224    Level: developer
1225 
1226 .keywords: TS, timestep
1227 @*/
1228 PetscErrorCode TSAdjointMonitor(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda, Vec *mu)
1229 {
1230   PetscErrorCode ierr;
1231   PetscInt       i,n = ts->numberadjointmonitors;
1232 
1233   PetscFunctionBegin;
1234   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1235   PetscValidHeaderSpecific(u,VEC_CLASSID,4);
1236   ierr = VecLockReadPush(u);CHKERRQ(ierr);
1237   for (i=0; i<n; i++) {
1238     ierr = (*ts->adjointmonitor[i])(ts,step,ptime,u,numcost,lambda,mu,ts->adjointmonitorcontext[i]);CHKERRQ(ierr);
1239   }
1240   ierr = VecLockReadPop(u);CHKERRQ(ierr);
1241   PetscFunctionReturn(0);
1242 }
1243 
1244 /*@
1245  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.
1246 
1247  Collective on TS
1248 
1249  Input Arguments:
1250  .  ts - time stepping context
1251 
1252  Level: advanced
1253 
1254  Notes:
1255  This function cannot be called until TSAdjointStep() has been completed.
1256 
1257  .seealso: TSAdjointSolve(), TSAdjointStep
1258  @*/
1259 PetscErrorCode TSAdjointCostIntegral(TS ts)
1260 {
1261     PetscErrorCode ierr;
1262     PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1263     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);
1264     ierr = (*ts->ops->adjointintegral)(ts);CHKERRQ(ierr);
1265     PetscFunctionReturn(0);
1266 }
1267 
1268 /* ------------------ Forward (tangent linear) sensitivity  ------------------*/
1269 
1270 /*@
1271   TSForwardSetUp - Sets up the internal data structures for the later use
1272   of forward sensitivity analysis
1273 
1274   Collective on TS
1275 
1276   Input Parameter:
1277 . ts - the TS context obtained from TSCreate()
1278 
1279   Level: advanced
1280 
1281 .keywords: TS, forward sensitivity, setup
1282 
1283 .seealso: TSCreate(), TSDestroy(), TSSetUp()
1284 @*/
1285 PetscErrorCode TSForwardSetUp(TS ts)
1286 {
1287   PetscErrorCode ierr;
1288 
1289   PetscFunctionBegin;
1290   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1291   if (ts->forwardsetupcalled) PetscFunctionReturn(0);
1292   if (ts->vec_costintegral && !ts->vecs_integral_sensip ) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call TSForwardSetIntegralGradients() before TSSetCostIntegrand()");
1293   if (ts->vecs_integral_sensip) {
1294     ierr = VecDuplicateVecs(ts->vec_sol,ts->numcost,&ts->vecs_drdu);CHKERRQ(ierr);
1295     ierr = VecDuplicateVecs(ts->vecs_integral_sensip[0],ts->numcost,&ts->vecs_drdp);CHKERRQ(ierr);
1296   }
1297 
1298   if (ts->ops->forwardsetup) {
1299     ierr = (*ts->ops->forwardsetup)(ts);CHKERRQ(ierr);
1300   }
1301   ts->forwardsetupcalled = PETSC_TRUE;
1302   PetscFunctionReturn(0);
1303 }
1304 
1305 /*@
1306   TSForwardReset - Reset the internal data structures used by forward sensitivity analysis
1307 
1308   Collective on TS
1309 
1310   Input Parameter:
1311 . ts - the TS context obtained from TSCreate()
1312 
1313   Level: advanced
1314 
1315 .keywords: TS, forward sensitivity, reset
1316 
1317 .seealso: TSCreate(), TSDestroy(), TSForwardSetUp()
1318 @*/
1319 PetscErrorCode TSForwardReset(TS ts)
1320 {
1321   PetscErrorCode ierr;
1322 
1323   PetscFunctionBegin;
1324   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1325   if (ts->ops->forwardreset) {
1326     ierr = (*ts->ops->forwardreset)(ts);CHKERRQ(ierr);
1327   }
1328   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1329   ts->vecs_integral_sensip = NULL;
1330   ts->forward_solve        = PETSC_FALSE;
1331   ts->forwardsetupcalled   = PETSC_FALSE;
1332   PetscFunctionReturn(0);
1333 }
1334 
1335 /*@
1336   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.
1337 
1338   Input Parameter:
1339 . ts- the TS context obtained from TSCreate()
1340 . numfwdint- number of integrals
1341 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1342 
1343   Level: intermediate
1344 
1345 .keywords: TS, forward sensitivity
1346 
1347 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1348 @*/
1349 PetscErrorCode TSForwardSetIntegralGradients(TS ts,PetscInt numfwdint,Vec *vp)
1350 {
1351   PetscFunctionBegin;
1352   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1353   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()");
1354   if (!ts->numcost) ts->numcost = numfwdint;
1355 
1356   ts->vecs_integral_sensip = vp;
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 /*@
1361   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.
1362 
1363   Input Parameter:
1364 . ts- the TS context obtained from TSCreate()
1365 
1366   Output Parameter:
1367 . vp = the vectors containing the gradients for each integral w.r.t. parameters
1368 
1369   Level: intermediate
1370 
1371 .keywords: TS, forward sensitivity
1372 
1373 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1374 @*/
1375 PetscErrorCode TSForwardGetIntegralGradients(TS ts,PetscInt *numfwdint,Vec **vp)
1376 {
1377   PetscFunctionBegin;
1378   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1379   PetscValidPointer(vp,3);
1380   if (numfwdint) *numfwdint = ts->numcost;
1381   if (vp) *vp = ts->vecs_integral_sensip;
1382   PetscFunctionReturn(0);
1383 }
1384 
1385 /*@
1386   TSForwardStep - Compute the forward sensitivity for one time step.
1387 
1388   Collective on TS
1389 
1390   Input Arguments:
1391 . ts - time stepping context
1392 
1393   Level: advanced
1394 
1395   Notes:
1396   This function cannot be called until TSStep() has been completed.
1397 
1398 .keywords: TS, forward sensitivity
1399 
1400 .seealso: TSForwardSetSensitivities(), TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardSetUp()
1401 @*/
1402 PetscErrorCode TSForwardStep(TS ts)
1403 {
1404   PetscErrorCode ierr;
1405   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1406   if (!ts->ops->forwardstep) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide forward sensitivity analysis",((PetscObject)ts)->type_name);
1407   ierr = PetscLogEventBegin(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1408   ierr = (*ts->ops->forwardstep)(ts);CHKERRQ(ierr);
1409   ierr = PetscLogEventEnd(TS_ForwardStep,ts,0,0,0);CHKERRQ(ierr);
1410   PetscFunctionReturn(0);
1411 }
1412 
1413 /*@
1414   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.
1415 
1416   Logically Collective on TS and Vec
1417 
1418   Input Parameters:
1419 + ts - the TS context obtained from TSCreate()
1420 . nump - number of parameters
1421 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1422 
1423   Level: beginner
1424 
1425   Notes:
1426   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
1427   This function turns on a flag to trigger TSSolve() to compute forward sensitivities automatically.
1428   You must call this function before TSSolve().
1429   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.
1430 
1431 .keywords: TS, timestep, set, forward sensitivity, initial values
1432 
1433 .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1434 @*/
1435 PetscErrorCode TSForwardSetSensitivities(TS ts,PetscInt nump,Mat Smat)
1436 {
1437   PetscErrorCode ierr;
1438 
1439   PetscFunctionBegin;
1440   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1441   PetscValidHeaderSpecific(Smat,MAT_CLASSID,3);
1442   ts->forward_solve  = PETSC_TRUE;
1443   if (nump == PETSC_DEFAULT) {
1444     ierr = MatGetSize(Smat,NULL,&ts->num_parameters);CHKERRQ(ierr);
1445   } else ts->num_parameters = nump;
1446   ierr = PetscObjectReference((PetscObject)Smat);CHKERRQ(ierr);
1447   ierr = MatDestroy(&ts->mat_sensip);CHKERRQ(ierr);
1448   ts->mat_sensip = Smat;
1449   PetscFunctionReturn(0);
1450 }
1451 
1452 /*@
1453   TSForwardGetSensitivities - Returns the trajectory sensitivities
1454 
1455   Not Collective, but Vec returned is parallel if TS is parallel
1456 
1457   Output Parameter:
1458 + ts - the TS context obtained from TSCreate()
1459 . nump - number of parameters
1460 - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1461 
1462   Level: intermediate
1463 
1464 .keywords: TS, forward sensitivity
1465 
1466 .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
1467 @*/
1468 PetscErrorCode TSForwardGetSensitivities(TS ts,PetscInt *nump,Mat *Smat)
1469 {
1470   PetscFunctionBegin;
1471   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1472   if (nump) *nump = ts->num_parameters;
1473   if (Smat) *Smat = ts->mat_sensip;
1474   PetscFunctionReturn(0);
1475 }
1476 
1477 /*@
1478    TSForwardCostIntegral - Evaluate the cost integral in the forward run.
1479 
1480    Collective on TS
1481 
1482    Input Arguments:
1483 .  ts - time stepping context
1484 
1485    Level: advanced
1486 
1487    Notes:
1488    This function cannot be called until TSStep() has been completed.
1489 
1490 .seealso: TSSolve(), TSAdjointCostIntegral()
1491 @*/
1492 PetscErrorCode TSForwardCostIntegral(TS ts)
1493 {
1494   PetscErrorCode ierr;
1495   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1496   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);
1497   ierr = (*ts->ops->forwardintegral)(ts);CHKERRQ(ierr);
1498   PetscFunctionReturn(0);
1499 }
1500 
1501 /*@
1502   TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities
1503 
1504   Collective on TS and Mat
1505 
1506   Input Parameter
1507 + ts - the TS context obtained from TSCreate()
1508 - didp - parametric sensitivities of the initial condition
1509 
1510   Level: intermediate
1511 
1512   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.
1513 
1514 .seealso: TSForwardSetSensitivities()
1515 @*/
1516 PetscErrorCode TSForwardSetInitialSensitivities(TS ts,Mat didp)
1517 {
1518   Vec            sp;
1519   PetscInt       lsize;
1520   PetscScalar    *xarr;
1521   PetscErrorCode ierr;
1522 
1523   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1524   if (ts->vec_dir) { /* indicates second-order adjoint caculation */
1525     Mat A;
1526     ierr = TSForwardGetSensitivities(ts,NULL,&A);CHKERRQ(ierr);
1527     if (!A) { /* create a single-column dense matrix */
1528       ierr = VecGetLocalSize(ts->vec_dir,&lsize);CHKERRQ(ierr);
1529       ierr = MatCreateDense(PETSC_COMM_WORLD,lsize,PETSC_DECIDE,PETSC_DECIDE,1,NULL,&A);CHKERRQ(ierr);
1530     }
1531     ierr = VecDuplicate(ts->vec_dir,&sp);CHKERRQ(ierr);
1532     ierr = MatDenseGetColumn(A,0,&xarr);CHKERRQ(ierr);
1533     ierr = VecPlaceArray(sp,xarr);CHKERRQ(ierr);
1534     if (didp) {
1535       ierr = MatMult(didp,ts->vec_dir,sp);CHKERRQ(ierr);
1536     } else { /* identity matrix assumed */
1537       ierr = VecCopy(ts->vec_dir,sp);CHKERRQ(ierr);
1538     }
1539     ierr = VecResetArray(sp);CHKERRQ(ierr);
1540     ierr = MatDenseRestoreColumn(A,&xarr);CHKERRQ(ierr);
1541     ierr = VecDestroy(&sp);CHKERRQ(ierr);
1542     ierr = TSForwardSetSensitivities(ts,1,A);CHKERRQ(ierr);
1543   } else {
1544     PetscValidHeaderSpecific(didp,MAT_CLASSID,2);
1545     if (!ts->mat_sensip) {
1546       ierr = TSForwardSetSensitivities(ts,PETSC_DEFAULT,didp);CHKERRQ(ierr);
1547     }
1548   }
1549   PetscFunctionReturn(0);
1550 }
1551 
1552 /*@
1553    TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages
1554 
1555    Input Parameter:
1556 .  ts - the TS context obtained from TSCreate()
1557 
1558    Output Parameters:
1559 +  ns - nu
1560 -  S - tangent linear sensitivities at the intermediate stages
1561 
1562    Level: advanced
1563 
1564 .keywords: TS, second-order adjoint, forward sensitivity
1565 @*/
1566 PetscErrorCode TSForwardGetStages(TS ts,PetscInt *ns,Mat **S)
1567 {
1568   PetscErrorCode ierr;
1569 
1570   PetscFunctionBegin;
1571   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1572 
1573   if (!ts->ops->getstages) *S=NULL;
1574   else {
1575     ierr = (*ts->ops->forwardgetstages)(ts,ns,S);CHKERRQ(ierr);
1576   }
1577   PetscFunctionReturn(0);
1578 }
1579