xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 1baa6e3354bfe224b33a0c158f482508792a8a6e)
1814e85d6SHong Zhang #include <petsc/private/tsimpl.h>        /*I "petscts.h"  I*/
2814e85d6SHong Zhang #include <petscdraw.h>
3814e85d6SHong Zhang 
433f72c5dSHong Zhang PetscLogEvent TS_AdjointStep,TS_ForwardStep,TS_JacobianPEval;
5814e85d6SHong Zhang 
67f59fb53SHong Zhang /* #define TSADJOINT_STAGE */
77f59fb53SHong Zhang 
8814e85d6SHong Zhang /* ------------------------ Sensitivity Context ---------------------------*/
9814e85d6SHong Zhang 
10814e85d6SHong Zhang /*@C
11b5b4017aSHong Zhang   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.
12814e85d6SHong Zhang 
13814e85d6SHong Zhang   Logically Collective on TS
14814e85d6SHong Zhang 
15814e85d6SHong Zhang   Input Parameters:
16b5b4017aSHong Zhang + ts - TS context obtained from TSCreate()
17b5b4017aSHong Zhang . Amat - JacobianP matrix
18b5b4017aSHong Zhang . func - function
19b5b4017aSHong Zhang - ctx - [optional] user-defined function context
20814e85d6SHong Zhang 
21814e85d6SHong Zhang   Calling sequence of func:
22814e85d6SHong Zhang $ func (TS ts,PetscReal t,Vec y,Mat A,void *ctx);
23814e85d6SHong Zhang +   t - current timestep
24c9ad9de0SHong Zhang .   U - input vector (current ODE solution)
25814e85d6SHong Zhang .   A - output matrix
26814e85d6SHong Zhang -   ctx - [optional] user-defined function context
27814e85d6SHong Zhang 
28814e85d6SHong Zhang   Level: intermediate
29814e85d6SHong Zhang 
30814e85d6SHong Zhang   Notes:
31814e85d6SHong Zhang     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
32814e85d6SHong Zhang 
33db781477SPatrick Sanan .seealso: `TSGetRHSJacobianP()`
34814e85d6SHong Zhang @*/
35814e85d6SHong Zhang PetscErrorCode TSSetRHSJacobianP(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
36814e85d6SHong Zhang {
37814e85d6SHong Zhang   PetscFunctionBegin;
38814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
39814e85d6SHong Zhang   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
40814e85d6SHong Zhang 
41814e85d6SHong Zhang   ts->rhsjacobianp    = func;
42814e85d6SHong Zhang   ts->rhsjacobianpctx = ctx;
43814e85d6SHong Zhang   if (Amat) {
449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)Amat));
459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&ts->Jacprhs));
4633f72c5dSHong Zhang     ts->Jacprhs = Amat;
47814e85d6SHong Zhang   }
48814e85d6SHong Zhang   PetscFunctionReturn(0);
49814e85d6SHong Zhang }
50814e85d6SHong Zhang 
51814e85d6SHong Zhang /*@C
52cd4cee2dSHong Zhang   TSGetRHSJacobianP - Gets the function that computes the Jacobian of G w.r.t. the parameters P where U_t = G(U,P,t), as well as the location to store the matrix.
53cd4cee2dSHong Zhang 
54cd4cee2dSHong Zhang   Logically Collective on TS
55cd4cee2dSHong Zhang 
56f899ff85SJose E. Roman   Input Parameter:
57cd4cee2dSHong Zhang . ts - TS context obtained from TSCreate()
58cd4cee2dSHong Zhang 
59cd4cee2dSHong Zhang   Output Parameters:
60cd4cee2dSHong Zhang + Amat - JacobianP matrix
61cd4cee2dSHong Zhang . func - function
62cd4cee2dSHong Zhang - ctx - [optional] user-defined function context
63cd4cee2dSHong Zhang 
64cd4cee2dSHong Zhang   Calling sequence of func:
65cd4cee2dSHong Zhang $ func (TS ts,PetscReal t,Vec y,Mat A,void *ctx);
66cd4cee2dSHong Zhang +   t - current timestep
67cd4cee2dSHong Zhang .   U - input vector (current ODE solution)
68cd4cee2dSHong Zhang .   A - output matrix
69cd4cee2dSHong Zhang -   ctx - [optional] user-defined function context
70cd4cee2dSHong Zhang 
71cd4cee2dSHong Zhang   Level: intermediate
72cd4cee2dSHong Zhang 
73cd4cee2dSHong Zhang   Notes:
74cd4cee2dSHong Zhang     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
75cd4cee2dSHong Zhang 
76db781477SPatrick Sanan .seealso: `TSSetRHSJacobianP()`
77cd4cee2dSHong Zhang @*/
78cd4cee2dSHong Zhang PetscErrorCode TSGetRHSJacobianP(TS ts,Mat *Amat,PetscErrorCode (**func)(TS,PetscReal,Vec,Mat,void*),void **ctx)
79cd4cee2dSHong Zhang {
80cd4cee2dSHong Zhang   PetscFunctionBegin;
81cd4cee2dSHong Zhang   if (func) *func = ts->rhsjacobianp;
82cd4cee2dSHong Zhang   if (ctx) *ctx  = ts->rhsjacobianpctx;
83cd4cee2dSHong Zhang   if (Amat) *Amat = ts->Jacprhs;
84cd4cee2dSHong Zhang   PetscFunctionReturn(0);
85cd4cee2dSHong Zhang }
86cd4cee2dSHong Zhang 
87cd4cee2dSHong Zhang /*@C
88814e85d6SHong Zhang   TSComputeRHSJacobianP - Runs the user-defined JacobianP function.
89814e85d6SHong Zhang 
90814e85d6SHong Zhang   Collective on TS
91814e85d6SHong Zhang 
92814e85d6SHong Zhang   Input Parameters:
93814e85d6SHong Zhang . ts   - The TS context obtained from TSCreate()
94814e85d6SHong Zhang 
95814e85d6SHong Zhang   Level: developer
96814e85d6SHong Zhang 
97db781477SPatrick Sanan .seealso: `TSSetRHSJacobianP()`
98814e85d6SHong Zhang @*/
99c9ad9de0SHong Zhang PetscErrorCode TSComputeRHSJacobianP(TS ts,PetscReal t,Vec U,Mat Amat)
100814e85d6SHong Zhang {
101814e85d6SHong Zhang   PetscFunctionBegin;
10233f72c5dSHong Zhang   if (!Amat) PetscFunctionReturn(0);
103814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
104c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
105814e85d6SHong Zhang 
106814e85d6SHong Zhang   PetscStackPush("TS user JacobianP function for sensitivity analysis");
1079566063dSJacob Faibussowitsch   PetscCall((*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx));
108814e85d6SHong Zhang   PetscStackPop;
109814e85d6SHong Zhang   PetscFunctionReturn(0);
110814e85d6SHong Zhang }
111814e85d6SHong Zhang 
112814e85d6SHong Zhang /*@C
11333f72c5dSHong Zhang   TSSetIJacobianP - Sets the function that computes the Jacobian of F w.r.t. the parameters P where F(Udot,U,t) = G(U,P,t), as well as the location to store the matrix.
11433f72c5dSHong Zhang 
11533f72c5dSHong Zhang   Logically Collective on TS
11633f72c5dSHong Zhang 
11733f72c5dSHong Zhang   Input Parameters:
11833f72c5dSHong Zhang + ts - TS context obtained from TSCreate()
11933f72c5dSHong Zhang . Amat - JacobianP matrix
12033f72c5dSHong Zhang . func - function
12133f72c5dSHong Zhang - ctx - [optional] user-defined function context
12233f72c5dSHong Zhang 
12333f72c5dSHong Zhang   Calling sequence of func:
12433f72c5dSHong Zhang $ func (TS ts,PetscReal t,Vec y,Mat A,void *ctx);
12533f72c5dSHong Zhang +   t - current timestep
12633f72c5dSHong Zhang .   U - input vector (current ODE solution)
12733f72c5dSHong Zhang .   Udot - time derivative of state vector
12833f72c5dSHong Zhang .   shift - shift to apply, see note below
12933f72c5dSHong Zhang .   A - output matrix
13033f72c5dSHong Zhang -   ctx - [optional] user-defined function context
13133f72c5dSHong Zhang 
13233f72c5dSHong Zhang   Level: intermediate
13333f72c5dSHong Zhang 
13433f72c5dSHong Zhang   Notes:
13533f72c5dSHong Zhang     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
13633f72c5dSHong Zhang 
13733f72c5dSHong Zhang .seealso:
13833f72c5dSHong Zhang @*/
13933f72c5dSHong Zhang PetscErrorCode TSSetIJacobianP(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Vec,PetscReal,Mat,void*),void *ctx)
14033f72c5dSHong Zhang {
14133f72c5dSHong Zhang   PetscFunctionBegin;
14233f72c5dSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
14333f72c5dSHong Zhang   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
14433f72c5dSHong Zhang 
14533f72c5dSHong Zhang   ts->ijacobianp    = func;
14633f72c5dSHong Zhang   ts->ijacobianpctx = ctx;
14733f72c5dSHong Zhang   if (Amat) {
1489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)Amat));
1499566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&ts->Jacp));
15033f72c5dSHong Zhang     ts->Jacp = Amat;
15133f72c5dSHong Zhang   }
15233f72c5dSHong Zhang   PetscFunctionReturn(0);
15333f72c5dSHong Zhang }
15433f72c5dSHong Zhang 
15533f72c5dSHong Zhang /*@C
15633f72c5dSHong Zhang   TSComputeIJacobianP - Runs the user-defined IJacobianP function.
15733f72c5dSHong Zhang 
15833f72c5dSHong Zhang   Collective on TS
15933f72c5dSHong Zhang 
16033f72c5dSHong Zhang   Input Parameters:
16133f72c5dSHong Zhang + ts - the TS context
16233f72c5dSHong Zhang . t - current timestep
16333f72c5dSHong Zhang . U - state vector
16433f72c5dSHong Zhang . Udot - time derivative of state vector
16533f72c5dSHong Zhang . shift - shift to apply, see note below
16633f72c5dSHong Zhang - imex - flag indicates if the method is IMEX so that the RHSJacobian should be kept separate
16733f72c5dSHong Zhang 
16833f72c5dSHong Zhang   Output Parameters:
16933f72c5dSHong Zhang . A - Jacobian matrix
17033f72c5dSHong Zhang 
17133f72c5dSHong Zhang   Level: developer
17233f72c5dSHong Zhang 
173db781477SPatrick Sanan .seealso: `TSSetIJacobianP()`
17433f72c5dSHong Zhang @*/
17533f72c5dSHong Zhang PetscErrorCode TSComputeIJacobianP(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal shift,Mat Amat,PetscBool imex)
17633f72c5dSHong Zhang {
17733f72c5dSHong Zhang   PetscFunctionBegin;
17833f72c5dSHong Zhang   if (!Amat) PetscFunctionReturn(0);
17933f72c5dSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
18033f72c5dSHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
18133f72c5dSHong Zhang   PetscValidHeaderSpecific(Udot,VEC_CLASSID,4);
18233f72c5dSHong Zhang 
1839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_JacobianPEval,ts,U,Amat,0));
18433f72c5dSHong Zhang   if (ts->ijacobianp) {
18533f72c5dSHong Zhang     PetscStackPush("TS user JacobianP function for sensitivity analysis");
1869566063dSJacob Faibussowitsch     PetscCall((*ts->ijacobianp)(ts,t,U,Udot,shift,Amat,ts->ijacobianpctx));
18733f72c5dSHong Zhang     PetscStackPop;
18833f72c5dSHong Zhang   }
18933f72c5dSHong Zhang   if (imex) {
19033f72c5dSHong Zhang     if (!ts->ijacobianp) {  /* system was written as Udot = G(t,U) */
19133f72c5dSHong Zhang       PetscBool assembled;
1929566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(Amat));
1939566063dSJacob Faibussowitsch       PetscCall(MatAssembled(Amat,&assembled));
19433f72c5dSHong Zhang       if (!assembled) {
1959566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(Amat,MAT_FINAL_ASSEMBLY));
1969566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(Amat,MAT_FINAL_ASSEMBLY));
19733f72c5dSHong Zhang       }
19833f72c5dSHong Zhang     }
19933f72c5dSHong Zhang   } else {
200*1baa6e33SBarry Smith     if (ts->rhsjacobianp) PetscCall(TSComputeRHSJacobianP(ts,t,U,ts->Jacprhs));
20133f72c5dSHong Zhang     if (ts->Jacprhs == Amat) { /* No IJacobian, so we only have the RHS matrix */
2029566063dSJacob Faibussowitsch       PetscCall(MatScale(Amat,-1));
20333f72c5dSHong Zhang     } else if (ts->Jacprhs) { /* Both IJacobian and RHSJacobian */
20433f72c5dSHong Zhang       MatStructure axpy = DIFFERENT_NONZERO_PATTERN;
20533f72c5dSHong Zhang       if (!ts->ijacobianp) { /* No IJacobianp provided, but we have a separate RHS matrix */
2069566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(Amat));
20733f72c5dSHong Zhang       }
2089566063dSJacob Faibussowitsch       PetscCall(MatAXPY(Amat,-1,ts->Jacprhs,axpy));
20933f72c5dSHong Zhang     }
21033f72c5dSHong Zhang   }
2119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_JacobianPEval,ts,U,Amat,0));
21233f72c5dSHong Zhang   PetscFunctionReturn(0);
21333f72c5dSHong Zhang }
21433f72c5dSHong Zhang 
21533f72c5dSHong Zhang /*@C
216814e85d6SHong Zhang     TSSetCostIntegrand - Sets the routine for evaluating the integral term in one or more cost functions
217814e85d6SHong Zhang 
218814e85d6SHong Zhang     Logically Collective on TS
219814e85d6SHong Zhang 
220814e85d6SHong Zhang     Input Parameters:
221814e85d6SHong Zhang +   ts - the TS context obtained from TSCreate()
222814e85d6SHong Zhang .   numcost - number of gradients to be computed, this is the number of cost functions
223814e85d6SHong Zhang .   costintegral - vector that stores the integral values
224814e85d6SHong Zhang .   rf - routine for evaluating the integrand function
225c9ad9de0SHong Zhang .   drduf - function that computes the gradients of the r's with respect to u
226814e85d6SHong Zhang .   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)
227814e85d6SHong Zhang .   fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
228814e85d6SHong Zhang -   ctx - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
229814e85d6SHong Zhang 
230814e85d6SHong Zhang     Calling sequence of rf:
231c9ad9de0SHong Zhang $   PetscErrorCode rf(TS ts,PetscReal t,Vec U,Vec F,void *ctx);
232814e85d6SHong Zhang 
233c9ad9de0SHong Zhang     Calling sequence of drduf:
234c9ad9de0SHong Zhang $   PetscErroCode drduf(TS ts,PetscReal t,Vec U,Vec *dRdU,void *ctx);
235814e85d6SHong Zhang 
236814e85d6SHong Zhang     Calling sequence of drdpf:
237c9ad9de0SHong Zhang $   PetscErroCode drdpf(TS ts,PetscReal t,Vec U,Vec *dRdP,void *ctx);
238814e85d6SHong Zhang 
239cd4cee2dSHong Zhang     Level: deprecated
240814e85d6SHong Zhang 
241814e85d6SHong Zhang     Notes:
242814e85d6SHong Zhang     For optimization there is usually a single cost function (numcost = 1). For sensitivities there may be multiple cost functions
243814e85d6SHong Zhang 
244db781477SPatrick Sanan .seealso: `TSSetRHSJacobianP()`, `TSGetCostGradients()`, `TSSetCostGradients()`
245814e85d6SHong Zhang @*/
246814e85d6SHong Zhang PetscErrorCode TSSetCostIntegrand(TS ts,PetscInt numcost,Vec costintegral,PetscErrorCode (*rf)(TS,PetscReal,Vec,Vec,void*),
247c9ad9de0SHong Zhang                                                           PetscErrorCode (*drduf)(TS,PetscReal,Vec,Vec*,void*),
248814e85d6SHong Zhang                                                           PetscErrorCode (*drdpf)(TS,PetscReal,Vec,Vec*,void*),
249814e85d6SHong Zhang                                                           PetscBool fwd,void *ctx)
250814e85d6SHong Zhang {
251814e85d6SHong Zhang   PetscFunctionBegin;
252814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
253814e85d6SHong Zhang   if (costintegral) PetscValidHeaderSpecific(costintegral,VEC_CLASSID,3);
2543c633725SBarry Smith   PetscCheck(!ts->numcost || ts->numcost == numcost,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostGradients() or TSForwardSetIntegralGradients()");
255814e85d6SHong Zhang   if (!ts->numcost) ts->numcost=numcost;
256814e85d6SHong Zhang 
257814e85d6SHong Zhang   if (costintegral) {
2589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)costintegral));
2599566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ts->vec_costintegral));
260814e85d6SHong Zhang     ts->vec_costintegral = costintegral;
261814e85d6SHong Zhang   } else {
262814e85d6SHong Zhang     if (!ts->vec_costintegral) { /* Create a seq vec if user does not provide one */
2639566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF,numcost,&ts->vec_costintegral));
264814e85d6SHong Zhang     } else {
2659566063dSJacob Faibussowitsch       PetscCall(VecSet(ts->vec_costintegral,0.0));
266814e85d6SHong Zhang     }
267814e85d6SHong Zhang   }
268814e85d6SHong Zhang   if (!ts->vec_costintegrand) {
2699566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ts->vec_costintegral,&ts->vec_costintegrand));
270814e85d6SHong Zhang   } else {
2719566063dSJacob Faibussowitsch     PetscCall(VecSet(ts->vec_costintegrand,0.0));
272814e85d6SHong Zhang   }
273814e85d6SHong Zhang   ts->costintegralfwd  = fwd; /* Evaluate the cost integral in forward run if fwd is true */
274814e85d6SHong Zhang   ts->costintegrand    = rf;
275814e85d6SHong Zhang   ts->costintegrandctx = ctx;
276c9ad9de0SHong Zhang   ts->drdufunction     = drduf;
277814e85d6SHong Zhang   ts->drdpfunction     = drdpf;
278814e85d6SHong Zhang   PetscFunctionReturn(0);
279814e85d6SHong Zhang }
280814e85d6SHong Zhang 
281b5b4017aSHong Zhang /*@C
282814e85d6SHong Zhang    TSGetCostIntegral - Returns the values of the integral term in the cost functions.
283814e85d6SHong Zhang    It is valid to call the routine after a backward run.
284814e85d6SHong Zhang 
285814e85d6SHong Zhang    Not Collective
286814e85d6SHong Zhang 
287814e85d6SHong Zhang    Input Parameter:
288814e85d6SHong Zhang .  ts - the TS context obtained from TSCreate()
289814e85d6SHong Zhang 
290814e85d6SHong Zhang    Output Parameter:
291814e85d6SHong Zhang .  v - the vector containing the integrals for each cost function
292814e85d6SHong Zhang 
293814e85d6SHong Zhang    Level: intermediate
294814e85d6SHong Zhang 
295db781477SPatrick Sanan .seealso: `TSSetCostIntegrand()`
296814e85d6SHong Zhang 
297814e85d6SHong Zhang @*/
298814e85d6SHong Zhang PetscErrorCode  TSGetCostIntegral(TS ts,Vec *v)
299814e85d6SHong Zhang {
300cd4cee2dSHong Zhang   TS             quadts;
301cd4cee2dSHong Zhang 
302814e85d6SHong Zhang   PetscFunctionBegin;
303814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
304814e85d6SHong Zhang   PetscValidPointer(v,2);
3059566063dSJacob Faibussowitsch   PetscCall(TSGetQuadratureTS(ts,NULL,&quadts));
306cd4cee2dSHong Zhang   *v = quadts->vec_sol;
307814e85d6SHong Zhang   PetscFunctionReturn(0);
308814e85d6SHong Zhang }
309814e85d6SHong Zhang 
310b5b4017aSHong Zhang /*@C
311814e85d6SHong Zhang    TSComputeCostIntegrand - Evaluates the integral function in the cost functions.
312814e85d6SHong Zhang 
313814e85d6SHong Zhang    Input Parameters:
314814e85d6SHong Zhang +  ts - the TS context
315814e85d6SHong Zhang .  t - current time
316c9ad9de0SHong Zhang -  U - state vector, i.e. current solution
317814e85d6SHong Zhang 
318814e85d6SHong Zhang    Output Parameter:
319c9ad9de0SHong Zhang .  Q - vector of size numcost to hold the outputs
320814e85d6SHong Zhang 
321369cf35fSHong Zhang    Notes:
322814e85d6SHong Zhang    Most users should not need to explicitly call this routine, as it
323814e85d6SHong Zhang    is used internally within the sensitivity analysis context.
324814e85d6SHong Zhang 
325cd4cee2dSHong Zhang    Level: deprecated
326814e85d6SHong Zhang 
327db781477SPatrick Sanan .seealso: `TSSetCostIntegrand()`
328814e85d6SHong Zhang @*/
329c9ad9de0SHong Zhang PetscErrorCode TSComputeCostIntegrand(TS ts,PetscReal t,Vec U,Vec Q)
330814e85d6SHong Zhang {
331814e85d6SHong Zhang   PetscFunctionBegin;
332814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
333c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
334c9ad9de0SHong Zhang   PetscValidHeaderSpecific(Q,VEC_CLASSID,4);
335814e85d6SHong Zhang 
3369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_FunctionEval,ts,U,Q,0));
337814e85d6SHong Zhang   if (ts->costintegrand) {
338814e85d6SHong Zhang     PetscStackPush("TS user integrand in the cost function");
3399566063dSJacob Faibussowitsch     PetscCall((*ts->costintegrand)(ts,t,U,Q,ts->costintegrandctx));
340814e85d6SHong Zhang     PetscStackPop;
341814e85d6SHong Zhang   } else {
3429566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(Q));
343814e85d6SHong Zhang   }
344814e85d6SHong Zhang 
3459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_FunctionEval,ts,U,Q,0));
346814e85d6SHong Zhang   PetscFunctionReturn(0);
347814e85d6SHong Zhang }
348814e85d6SHong Zhang 
349b5b4017aSHong Zhang /*@C
350d76be551SHong Zhang   TSComputeDRDUFunction - Deprecated, use TSGetQuadratureTS() then TSComputeRHSJacobian()
351814e85d6SHong Zhang 
352d76be551SHong Zhang   Level: deprecated
353814e85d6SHong Zhang 
354814e85d6SHong Zhang @*/
355c9ad9de0SHong Zhang PetscErrorCode TSComputeDRDUFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
356814e85d6SHong Zhang {
357814e85d6SHong Zhang   PetscFunctionBegin;
35833f72c5dSHong Zhang   if (!DRDU) PetscFunctionReturn(0);
359814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
360c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
361814e85d6SHong Zhang 
362c9ad9de0SHong Zhang   PetscStackPush("TS user DRDU function for sensitivity analysis");
3639566063dSJacob Faibussowitsch   PetscCall((*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx));
364814e85d6SHong Zhang   PetscStackPop;
365814e85d6SHong Zhang   PetscFunctionReturn(0);
366814e85d6SHong Zhang }
367814e85d6SHong Zhang 
368b5b4017aSHong Zhang /*@C
369d76be551SHong Zhang   TSComputeDRDPFunction - Deprecated, use TSGetQuadratureTS() then TSComputeRHSJacobianP()
370814e85d6SHong Zhang 
371d76be551SHong Zhang   Level: deprecated
372814e85d6SHong Zhang 
373814e85d6SHong Zhang @*/
374c9ad9de0SHong Zhang PetscErrorCode TSComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
375814e85d6SHong Zhang {
376814e85d6SHong Zhang   PetscFunctionBegin;
37733f72c5dSHong Zhang   if (!DRDP) PetscFunctionReturn(0);
378814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
379c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
380814e85d6SHong Zhang 
381814e85d6SHong Zhang   PetscStackPush("TS user DRDP function for sensitivity analysis");
3829566063dSJacob Faibussowitsch   PetscCall((*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx));
383814e85d6SHong Zhang   PetscStackPop;
384814e85d6SHong Zhang   PetscFunctionReturn(0);
385814e85d6SHong Zhang }
386814e85d6SHong Zhang 
387b5b4017aSHong Zhang /*@C
388b5b4017aSHong Zhang   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.
389b5b4017aSHong Zhang 
390b5b4017aSHong Zhang   Logically Collective on TS
391b5b4017aSHong Zhang 
392b5b4017aSHong Zhang   Input Parameters:
393b5b4017aSHong Zhang + ts - TS context obtained from TSCreate()
394b5b4017aSHong Zhang . ihp1 - an array of vectors storing the result of vector-Hessian-vector product for F_UU
395b5b4017aSHong Zhang . hessianproductfunc1 - vector-Hessian-vector product function for F_UU
396b5b4017aSHong Zhang . ihp2 - an array of vectors storing the result of vector-Hessian-vector product for F_UP
397b5b4017aSHong Zhang . hessianproductfunc2 - vector-Hessian-vector product function for F_UP
398b5b4017aSHong Zhang . ihp3 - an array of vectors storing the result of vector-Hessian-vector product for F_PU
399b5b4017aSHong Zhang . hessianproductfunc3 - vector-Hessian-vector product function for F_PU
400b5b4017aSHong Zhang . ihp4 - an array of vectors storing the result of vector-Hessian-vector product for F_PP
401f0fc11ceSJed Brown - hessianproductfunc4 - vector-Hessian-vector product function for F_PP
402b5b4017aSHong Zhang 
403b5b4017aSHong Zhang   Calling sequence of ihessianproductfunc:
404369cf35fSHong Zhang $ ihessianproductfunc (TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx);
405b5b4017aSHong Zhang +   t - current timestep
406b5b4017aSHong Zhang .   U - input vector (current ODE solution)
407369cf35fSHong Zhang .   Vl - an array of input vectors to be left-multiplied with the Hessian
408b5b4017aSHong Zhang .   Vr - input vector to be right-multiplied with the Hessian
409369cf35fSHong Zhang .   VHV - an array of output vectors for vector-Hessian-vector product
410b5b4017aSHong Zhang -   ctx - [optional] user-defined function context
411b5b4017aSHong Zhang 
412b5b4017aSHong Zhang   Level: intermediate
413b5b4017aSHong Zhang 
414369cf35fSHong Zhang   Notes:
415369cf35fSHong Zhang   The first Hessian function and the working array are required.
416369cf35fSHong Zhang   As an example to implement the callback functions, the second callback function calculates the vector-Hessian-vector product
417369cf35fSHong Zhang   $ Vl_n^T*F_UP*Vr
418369cf35fSHong Zhang   where the vector Vl_n (n-th element in the array Vl) and Vr are of size N and M respectively, and the Hessian F_UP is of size N x N x M.
419369cf35fSHong Zhang   Each entry of F_UP corresponds to the derivative
420369cf35fSHong Zhang   $ F_UP[i][j][k] = \frac{\partial^2 F[i]}{\partial U[j] \partial P[k]}.
421369cf35fSHong Zhang   The result of the vector-Hessian-vector product for Vl_n needs to be stored in vector VHV_n with the j-th entry being
422369cf35fSHong Zhang   $ VHV_n[j] = \sum_i \sum_k {Vl_n[i] * F_UP[i][j][k] * Vr[k]}
423369cf35fSHong Zhang   If the cost function is a scalar, there will be only one vector in Vl and VHV.
424b5b4017aSHong Zhang 
425b5b4017aSHong Zhang .seealso:
426b5b4017aSHong Zhang @*/
427b5b4017aSHong Zhang PetscErrorCode TSSetIHessianProduct(TS ts,Vec *ihp1,PetscErrorCode (*ihessianproductfunc1)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
428b5b4017aSHong Zhang                                           Vec *ihp2,PetscErrorCode (*ihessianproductfunc2)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
429b5b4017aSHong Zhang                                           Vec *ihp3,PetscErrorCode (*ihessianproductfunc3)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
430b5b4017aSHong Zhang                                           Vec *ihp4,PetscErrorCode (*ihessianproductfunc4)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
431b5b4017aSHong Zhang                                     void *ctx)
432b5b4017aSHong Zhang {
433b5b4017aSHong Zhang   PetscFunctionBegin;
434b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
435b5b4017aSHong Zhang   PetscValidPointer(ihp1,2);
436b5b4017aSHong Zhang 
437b5b4017aSHong Zhang   ts->ihessianproductctx = ctx;
438b5b4017aSHong Zhang   if (ihp1) ts->vecs_fuu = ihp1;
439b5b4017aSHong Zhang   if (ihp2) ts->vecs_fup = ihp2;
440b5b4017aSHong Zhang   if (ihp3) ts->vecs_fpu = ihp3;
441b5b4017aSHong Zhang   if (ihp4) ts->vecs_fpp = ihp4;
442b5b4017aSHong Zhang   ts->ihessianproduct_fuu = ihessianproductfunc1;
443b5b4017aSHong Zhang   ts->ihessianproduct_fup = ihessianproductfunc2;
444b5b4017aSHong Zhang   ts->ihessianproduct_fpu = ihessianproductfunc3;
445b5b4017aSHong Zhang   ts->ihessianproduct_fpp = ihessianproductfunc4;
446b5b4017aSHong Zhang   PetscFunctionReturn(0);
447b5b4017aSHong Zhang }
448b5b4017aSHong Zhang 
449b5b4017aSHong Zhang /*@C
450b1e111ebSHong Zhang   TSComputeIHessianProductFunctionUU - Runs the user-defined vector-Hessian-vector product function for Fuu.
451b5b4017aSHong Zhang 
452b5b4017aSHong Zhang   Collective on TS
453b5b4017aSHong Zhang 
454b5b4017aSHong Zhang   Input Parameters:
455b5b4017aSHong Zhang . ts   - The TS context obtained from TSCreate()
456b5b4017aSHong Zhang 
457b5b4017aSHong Zhang   Notes:
458b1e111ebSHong Zhang   TSComputeIHessianProductFunctionUU() is typically used for sensitivity implementation,
459b5b4017aSHong Zhang   so most users would not generally call this routine themselves.
460b5b4017aSHong Zhang 
461b5b4017aSHong Zhang   Level: developer
462b5b4017aSHong Zhang 
463db781477SPatrick Sanan .seealso: `TSSetIHessianProduct()`
464b5b4017aSHong Zhang @*/
465b1e111ebSHong Zhang PetscErrorCode TSComputeIHessianProductFunctionUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
466b5b4017aSHong Zhang {
467b5b4017aSHong Zhang   PetscFunctionBegin;
46833f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
469b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
470b5b4017aSHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
471b5b4017aSHong Zhang 
47267633408SHong Zhang   if (ts->ihessianproduct_fuu) {
473b5b4017aSHong Zhang     PetscStackPush("TS user IHessianProduct function 1 for sensitivity analysis");
4749566063dSJacob Faibussowitsch     PetscCall((*ts->ihessianproduct_fuu)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx));
475b5b4017aSHong Zhang     PetscStackPop;
47667633408SHong Zhang   }
47767633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
47867633408SHong Zhang   if (ts->rhshessianproduct_guu) {
47967633408SHong Zhang     PetscInt nadj;
4809566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionUU(ts,t,U,Vl,Vr,VHV));
48167633408SHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
4829566063dSJacob Faibussowitsch       PetscCall(VecScale(VHV[nadj],-1));
48367633408SHong Zhang     }
48467633408SHong Zhang   }
485b5b4017aSHong Zhang   PetscFunctionReturn(0);
486b5b4017aSHong Zhang }
487b5b4017aSHong Zhang 
488b5b4017aSHong Zhang /*@C
489b1e111ebSHong Zhang   TSComputeIHessianProductFunctionUP - Runs the user-defined vector-Hessian-vector product function for Fup.
490b5b4017aSHong Zhang 
491b5b4017aSHong Zhang   Collective on TS
492b5b4017aSHong Zhang 
493b5b4017aSHong Zhang   Input Parameters:
494b5b4017aSHong Zhang . ts   - The TS context obtained from TSCreate()
495b5b4017aSHong Zhang 
496b5b4017aSHong Zhang   Notes:
497b1e111ebSHong Zhang   TSComputeIHessianProductFunctionUP() is typically used for sensitivity implementation,
498b5b4017aSHong Zhang   so most users would not generally call this routine themselves.
499b5b4017aSHong Zhang 
500b5b4017aSHong Zhang   Level: developer
501b5b4017aSHong Zhang 
502db781477SPatrick Sanan .seealso: `TSSetIHessianProduct()`
503b5b4017aSHong Zhang @*/
504b1e111ebSHong Zhang PetscErrorCode TSComputeIHessianProductFunctionUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
505b5b4017aSHong Zhang {
506b5b4017aSHong Zhang   PetscFunctionBegin;
50733f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
508b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
509b5b4017aSHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
510b5b4017aSHong Zhang 
51167633408SHong Zhang   if (ts->ihessianproduct_fup) {
512b5b4017aSHong Zhang     PetscStackPush("TS user IHessianProduct function 2 for sensitivity analysis");
5139566063dSJacob Faibussowitsch     PetscCall((*ts->ihessianproduct_fup)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx));
514b5b4017aSHong Zhang     PetscStackPop;
51567633408SHong Zhang   }
51667633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
51767633408SHong Zhang   if (ts->rhshessianproduct_gup) {
51867633408SHong Zhang     PetscInt nadj;
5199566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionUP(ts,t,U,Vl,Vr,VHV));
52067633408SHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
5219566063dSJacob Faibussowitsch       PetscCall(VecScale(VHV[nadj],-1));
52267633408SHong Zhang     }
52367633408SHong Zhang   }
524b5b4017aSHong Zhang   PetscFunctionReturn(0);
525b5b4017aSHong Zhang }
526b5b4017aSHong Zhang 
527b5b4017aSHong Zhang /*@C
528b1e111ebSHong Zhang   TSComputeIHessianProductFunctionPU - Runs the user-defined vector-Hessian-vector product function for Fpu.
529b5b4017aSHong Zhang 
530b5b4017aSHong Zhang   Collective on TS
531b5b4017aSHong Zhang 
532b5b4017aSHong Zhang   Input Parameters:
533b5b4017aSHong Zhang . ts   - The TS context obtained from TSCreate()
534b5b4017aSHong Zhang 
535b5b4017aSHong Zhang   Notes:
536b1e111ebSHong Zhang   TSComputeIHessianProductFunctionPU() is typically used for sensitivity implementation,
537b5b4017aSHong Zhang   so most users would not generally call this routine themselves.
538b5b4017aSHong Zhang 
539b5b4017aSHong Zhang   Level: developer
540b5b4017aSHong Zhang 
541db781477SPatrick Sanan .seealso: `TSSetIHessianProduct()`
542b5b4017aSHong Zhang @*/
543b1e111ebSHong Zhang PetscErrorCode TSComputeIHessianProductFunctionPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
544b5b4017aSHong Zhang {
545b5b4017aSHong Zhang   PetscFunctionBegin;
54633f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
547b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
548b5b4017aSHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
549b5b4017aSHong Zhang 
55067633408SHong Zhang   if (ts->ihessianproduct_fpu) {
551b5b4017aSHong Zhang     PetscStackPush("TS user IHessianProduct function 3 for sensitivity analysis");
5529566063dSJacob Faibussowitsch     PetscCall((*ts->ihessianproduct_fpu)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx));
553b5b4017aSHong Zhang     PetscStackPop;
55467633408SHong Zhang   }
55567633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
55667633408SHong Zhang   if (ts->rhshessianproduct_gpu) {
55767633408SHong Zhang     PetscInt nadj;
5589566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionPU(ts,t,U,Vl,Vr,VHV));
55967633408SHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
5609566063dSJacob Faibussowitsch       PetscCall(VecScale(VHV[nadj],-1));
56167633408SHong Zhang     }
56267633408SHong Zhang   }
563b5b4017aSHong Zhang   PetscFunctionReturn(0);
564b5b4017aSHong Zhang }
565b5b4017aSHong Zhang 
566b5b4017aSHong Zhang /*@C
567b1e111ebSHong Zhang   TSComputeIHessianProductFunctionPP - Runs the user-defined vector-Hessian-vector product function for Fpp.
568b5b4017aSHong Zhang 
569b5b4017aSHong Zhang   Collective on TS
570b5b4017aSHong Zhang 
571b5b4017aSHong Zhang   Input Parameters:
572b5b4017aSHong Zhang . ts   - The TS context obtained from TSCreate()
573b5b4017aSHong Zhang 
574b5b4017aSHong Zhang   Notes:
575b1e111ebSHong Zhang   TSComputeIHessianProductFunctionPP() is typically used for sensitivity implementation,
576b5b4017aSHong Zhang   so most users would not generally call this routine themselves.
577b5b4017aSHong Zhang 
578b5b4017aSHong Zhang   Level: developer
579b5b4017aSHong Zhang 
580db781477SPatrick Sanan .seealso: `TSSetIHessianProduct()`
581b5b4017aSHong Zhang @*/
582b1e111ebSHong Zhang PetscErrorCode TSComputeIHessianProductFunctionPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
583b5b4017aSHong Zhang {
584b5b4017aSHong Zhang   PetscFunctionBegin;
58533f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
586b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
587b5b4017aSHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
588b5b4017aSHong Zhang 
58967633408SHong Zhang   if (ts->ihessianproduct_fpp) {
590b5b4017aSHong Zhang     PetscStackPush("TS user IHessianProduct function 3 for sensitivity analysis");
5919566063dSJacob Faibussowitsch     PetscCall((*ts->ihessianproduct_fpp)(ts,t,U,Vl,Vr,VHV,ts->ihessianproductctx));
592b5b4017aSHong Zhang     PetscStackPop;
59367633408SHong Zhang   }
59467633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
59567633408SHong Zhang   if (ts->rhshessianproduct_gpp) {
59667633408SHong Zhang     PetscInt nadj;
5979566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionPP(ts,t,U,Vl,Vr,VHV));
59867633408SHong Zhang     for (nadj=0; nadj<ts->numcost; nadj++) {
5999566063dSJacob Faibussowitsch       PetscCall(VecScale(VHV[nadj],-1));
60067633408SHong Zhang     }
60167633408SHong Zhang   }
602b5b4017aSHong Zhang   PetscFunctionReturn(0);
603b5b4017aSHong Zhang }
604b5b4017aSHong Zhang 
60513af1a74SHong Zhang /*@C
6064c500f23SPierre Jolivet   TSSetRHSHessianProduct - Sets the function that computes the vector-Hessian-vector product. The Hessian is the second-order derivative of G (RHSFunction) w.r.t. the state variable.
60713af1a74SHong Zhang 
60813af1a74SHong Zhang   Logically Collective on TS
60913af1a74SHong Zhang 
61013af1a74SHong Zhang   Input Parameters:
61113af1a74SHong Zhang + ts - TS context obtained from TSCreate()
61213af1a74SHong Zhang . rhshp1 - an array of vectors storing the result of vector-Hessian-vector product for G_UU
61313af1a74SHong Zhang . hessianproductfunc1 - vector-Hessian-vector product function for G_UU
61413af1a74SHong Zhang . rhshp2 - an array of vectors storing the result of vector-Hessian-vector product for G_UP
61513af1a74SHong Zhang . hessianproductfunc2 - vector-Hessian-vector product function for G_UP
61613af1a74SHong Zhang . rhshp3 - an array of vectors storing the result of vector-Hessian-vector product for G_PU
61713af1a74SHong Zhang . hessianproductfunc3 - vector-Hessian-vector product function for G_PU
61813af1a74SHong Zhang . rhshp4 - an array of vectors storing the result of vector-Hessian-vector product for G_PP
619f0fc11ceSJed Brown - hessianproductfunc4 - vector-Hessian-vector product function for G_PP
62013af1a74SHong Zhang 
62113af1a74SHong Zhang   Calling sequence of ihessianproductfunc:
622369cf35fSHong Zhang $ rhshessianproductfunc (TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx);
62313af1a74SHong Zhang +   t - current timestep
62413af1a74SHong Zhang .   U - input vector (current ODE solution)
625369cf35fSHong Zhang .   Vl - an array of input vectors to be left-multiplied with the Hessian
62613af1a74SHong Zhang .   Vr - input vector to be right-multiplied with the Hessian
627369cf35fSHong Zhang .   VHV - an array of output vectors for vector-Hessian-vector product
62813af1a74SHong Zhang -   ctx - [optional] user-defined function context
62913af1a74SHong Zhang 
63013af1a74SHong Zhang   Level: intermediate
63113af1a74SHong Zhang 
632369cf35fSHong Zhang   Notes:
633369cf35fSHong Zhang   The first Hessian function and the working array are required.
634369cf35fSHong Zhang   As an example to implement the callback functions, the second callback function calculates the vector-Hessian-vector product
635369cf35fSHong Zhang   $ Vl_n^T*G_UP*Vr
636369cf35fSHong Zhang   where the vector Vl_n (n-th element in the array Vl) and Vr are of size N and M respectively, and the Hessian G_UP is of size N x N x M.
637369cf35fSHong Zhang   Each entry of G_UP corresponds to the derivative
638369cf35fSHong Zhang   $ G_UP[i][j][k] = \frac{\partial^2 G[i]}{\partial U[j] \partial P[k]}.
639369cf35fSHong Zhang   The result of the vector-Hessian-vector product for Vl_n needs to be stored in vector VHV_n with j-th entry being
640369cf35fSHong Zhang   $ VHV_n[j] = \sum_i \sum_k {Vl_n[i] * G_UP[i][j][k] * Vr[k]}
641369cf35fSHong Zhang   If the cost function is a scalar, there will be only one vector in Vl and VHV.
64213af1a74SHong Zhang 
64313af1a74SHong Zhang .seealso:
64413af1a74SHong Zhang @*/
64513af1a74SHong Zhang PetscErrorCode TSSetRHSHessianProduct(TS ts,Vec *rhshp1,PetscErrorCode (*rhshessianproductfunc1)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
64613af1a74SHong Zhang                                           Vec *rhshp2,PetscErrorCode (*rhshessianproductfunc2)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
64713af1a74SHong Zhang                                           Vec *rhshp3,PetscErrorCode (*rhshessianproductfunc3)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
64813af1a74SHong Zhang                                           Vec *rhshp4,PetscErrorCode (*rhshessianproductfunc4)(TS,PetscReal,Vec,Vec*,Vec,Vec*,void*),
64913af1a74SHong Zhang                                     void *ctx)
65013af1a74SHong Zhang {
65113af1a74SHong Zhang   PetscFunctionBegin;
65213af1a74SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
65313af1a74SHong Zhang   PetscValidPointer(rhshp1,2);
65413af1a74SHong Zhang 
65513af1a74SHong Zhang   ts->rhshessianproductctx = ctx;
65613af1a74SHong Zhang   if (rhshp1) ts->vecs_guu = rhshp1;
65713af1a74SHong Zhang   if (rhshp2) ts->vecs_gup = rhshp2;
65813af1a74SHong Zhang   if (rhshp3) ts->vecs_gpu = rhshp3;
65913af1a74SHong Zhang   if (rhshp4) ts->vecs_gpp = rhshp4;
66013af1a74SHong Zhang   ts->rhshessianproduct_guu = rhshessianproductfunc1;
66113af1a74SHong Zhang   ts->rhshessianproduct_gup = rhshessianproductfunc2;
66213af1a74SHong Zhang   ts->rhshessianproduct_gpu = rhshessianproductfunc3;
66313af1a74SHong Zhang   ts->rhshessianproduct_gpp = rhshessianproductfunc4;
66413af1a74SHong Zhang   PetscFunctionReturn(0);
66513af1a74SHong Zhang }
66613af1a74SHong Zhang 
66713af1a74SHong Zhang /*@C
668b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionUU - Runs the user-defined vector-Hessian-vector product function for Guu.
66913af1a74SHong Zhang 
67013af1a74SHong Zhang   Collective on TS
67113af1a74SHong Zhang 
67213af1a74SHong Zhang   Input Parameters:
67313af1a74SHong Zhang . ts   - The TS context obtained from TSCreate()
67413af1a74SHong Zhang 
67513af1a74SHong Zhang   Notes:
676b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionUU() is typically used for sensitivity implementation,
67713af1a74SHong Zhang   so most users would not generally call this routine themselves.
67813af1a74SHong Zhang 
67913af1a74SHong Zhang   Level: developer
68013af1a74SHong Zhang 
681db781477SPatrick Sanan .seealso: `TSSetRHSHessianProduct()`
68213af1a74SHong Zhang @*/
683b1e111ebSHong Zhang PetscErrorCode TSComputeRHSHessianProductFunctionUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
68413af1a74SHong Zhang {
68513af1a74SHong Zhang   PetscFunctionBegin;
68613af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
68713af1a74SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
68813af1a74SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
68913af1a74SHong Zhang 
69013af1a74SHong Zhang   PetscStackPush("TS user RHSHessianProduct function 1 for sensitivity analysis");
6919566063dSJacob Faibussowitsch   PetscCall((*ts->rhshessianproduct_guu)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx));
69213af1a74SHong Zhang   PetscStackPop;
69313af1a74SHong Zhang   PetscFunctionReturn(0);
69413af1a74SHong Zhang }
69513af1a74SHong Zhang 
69613af1a74SHong Zhang /*@C
697b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionUP - Runs the user-defined vector-Hessian-vector product function for Gup.
69813af1a74SHong Zhang 
69913af1a74SHong Zhang   Collective on TS
70013af1a74SHong Zhang 
70113af1a74SHong Zhang   Input Parameters:
70213af1a74SHong Zhang . ts   - The TS context obtained from TSCreate()
70313af1a74SHong Zhang 
70413af1a74SHong Zhang   Notes:
705b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionUP() is typically used for sensitivity implementation,
70613af1a74SHong Zhang   so most users would not generally call this routine themselves.
70713af1a74SHong Zhang 
70813af1a74SHong Zhang   Level: developer
70913af1a74SHong Zhang 
710db781477SPatrick Sanan .seealso: `TSSetRHSHessianProduct()`
71113af1a74SHong Zhang @*/
712b1e111ebSHong Zhang PetscErrorCode TSComputeRHSHessianProductFunctionUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
71313af1a74SHong Zhang {
71413af1a74SHong Zhang   PetscFunctionBegin;
71513af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
71613af1a74SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
71713af1a74SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
71813af1a74SHong Zhang 
71913af1a74SHong Zhang   PetscStackPush("TS user RHSHessianProduct function 2 for sensitivity analysis");
7209566063dSJacob Faibussowitsch   PetscCall((*ts->rhshessianproduct_gup)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx));
72113af1a74SHong Zhang   PetscStackPop;
72213af1a74SHong Zhang   PetscFunctionReturn(0);
72313af1a74SHong Zhang }
72413af1a74SHong Zhang 
72513af1a74SHong Zhang /*@C
726b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionPU - Runs the user-defined vector-Hessian-vector product function for Gpu.
72713af1a74SHong Zhang 
72813af1a74SHong Zhang   Collective on TS
72913af1a74SHong Zhang 
73013af1a74SHong Zhang   Input Parameters:
73113af1a74SHong Zhang . ts   - The TS context obtained from TSCreate()
73213af1a74SHong Zhang 
73313af1a74SHong Zhang   Notes:
734b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionPU() is typically used for sensitivity implementation,
73513af1a74SHong Zhang   so most users would not generally call this routine themselves.
73613af1a74SHong Zhang 
73713af1a74SHong Zhang   Level: developer
73813af1a74SHong Zhang 
739db781477SPatrick Sanan .seealso: `TSSetRHSHessianProduct()`
74013af1a74SHong Zhang @*/
741b1e111ebSHong Zhang PetscErrorCode TSComputeRHSHessianProductFunctionPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
74213af1a74SHong Zhang {
74313af1a74SHong Zhang   PetscFunctionBegin;
74413af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
74513af1a74SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
74613af1a74SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
74713af1a74SHong Zhang 
74813af1a74SHong Zhang   PetscStackPush("TS user RHSHessianProduct function 3 for sensitivity analysis");
7499566063dSJacob Faibussowitsch   PetscCall((*ts->rhshessianproduct_gpu)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx));
75013af1a74SHong Zhang   PetscStackPop;
75113af1a74SHong Zhang   PetscFunctionReturn(0);
75213af1a74SHong Zhang }
75313af1a74SHong Zhang 
75413af1a74SHong Zhang /*@C
755b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionPP - Runs the user-defined vector-Hessian-vector product function for Gpp.
75613af1a74SHong Zhang 
75713af1a74SHong Zhang   Collective on TS
75813af1a74SHong Zhang 
75913af1a74SHong Zhang   Input Parameters:
76013af1a74SHong Zhang . ts   - The TS context obtained from TSCreate()
76113af1a74SHong Zhang 
76213af1a74SHong Zhang   Notes:
763b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionPP() is typically used for sensitivity implementation,
76413af1a74SHong Zhang   so most users would not generally call this routine themselves.
76513af1a74SHong Zhang 
76613af1a74SHong Zhang   Level: developer
76713af1a74SHong Zhang 
768db781477SPatrick Sanan .seealso: `TSSetRHSHessianProduct()`
76913af1a74SHong Zhang @*/
770b1e111ebSHong Zhang PetscErrorCode TSComputeRHSHessianProductFunctionPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV)
77113af1a74SHong Zhang {
77213af1a74SHong Zhang   PetscFunctionBegin;
77313af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
77413af1a74SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
77513af1a74SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
77613af1a74SHong Zhang 
77713af1a74SHong Zhang   PetscStackPush("TS user RHSHessianProduct function 3 for sensitivity analysis");
7789566063dSJacob Faibussowitsch   PetscCall((*ts->rhshessianproduct_gpp)(ts,t,U,Vl,Vr,VHV,ts->rhshessianproductctx));
77913af1a74SHong Zhang   PetscStackPop;
78013af1a74SHong Zhang   PetscFunctionReturn(0);
78113af1a74SHong Zhang }
78213af1a74SHong Zhang 
783814e85d6SHong Zhang /* --------------------------- Adjoint sensitivity ---------------------------*/
784814e85d6SHong Zhang 
785814e85d6SHong Zhang /*@
786814e85d6SHong Zhang    TSSetCostGradients - Sets the initial value of the gradients of the cost function w.r.t. initial values and w.r.t. the problem parameters
787814e85d6SHong Zhang       for use by the TSAdjoint routines.
788814e85d6SHong Zhang 
789d083f849SBarry Smith    Logically Collective on TS
790814e85d6SHong Zhang 
791814e85d6SHong Zhang    Input Parameters:
792814e85d6SHong Zhang +  ts - the TS context obtained from TSCreate()
793d2fd7bfcSHong Zhang .  numcost - number of gradients to be computed, this is the number of cost functions
794814e85d6SHong Zhang .  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
795814e85d6SHong Zhang -  mu - gradients with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
796814e85d6SHong Zhang 
797814e85d6SHong Zhang    Level: beginner
798814e85d6SHong Zhang 
799814e85d6SHong Zhang    Notes:
800814e85d6SHong Zhang     the entries in these vectors must be correctly initialized with the values lamda_i = df/dy|finaltime  mu_i = df/dp|finaltime
801814e85d6SHong Zhang 
802814e85d6SHong Zhang    After TSAdjointSolve() is called the lamba and the mu contain the computed sensitivities
803814e85d6SHong Zhang 
804db781477SPatrick Sanan .seealso `TSGetCostGradients()`
805814e85d6SHong Zhang @*/
806814e85d6SHong Zhang PetscErrorCode TSSetCostGradients(TS ts,PetscInt numcost,Vec *lambda,Vec *mu)
807814e85d6SHong Zhang {
808814e85d6SHong Zhang   PetscFunctionBegin;
809814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
810064a246eSJacob Faibussowitsch   PetscValidPointer(lambda,3);
811814e85d6SHong Zhang   ts->vecs_sensi  = lambda;
812814e85d6SHong Zhang   ts->vecs_sensip = mu;
8133c633725SBarry Smith   PetscCheck(!ts->numcost || ts->numcost == numcost,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand");
814814e85d6SHong Zhang   ts->numcost  = numcost;
815814e85d6SHong Zhang   PetscFunctionReturn(0);
816814e85d6SHong Zhang }
817814e85d6SHong Zhang 
818814e85d6SHong Zhang /*@
819814e85d6SHong Zhang    TSGetCostGradients - Returns the gradients from the TSAdjointSolve()
820814e85d6SHong Zhang 
821814e85d6SHong Zhang    Not Collective, but Vec returned is parallel if TS is parallel
822814e85d6SHong Zhang 
823814e85d6SHong Zhang    Input Parameter:
824814e85d6SHong Zhang .  ts - the TS context obtained from TSCreate()
825814e85d6SHong Zhang 
826d8d19677SJose E. Roman    Output Parameters:
8276b867d5aSJose E. Roman +  numcost - size of returned arrays
8286b867d5aSJose E. Roman .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
829814e85d6SHong Zhang -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
830814e85d6SHong Zhang 
831814e85d6SHong Zhang    Level: intermediate
832814e85d6SHong Zhang 
833db781477SPatrick Sanan .seealso: `TSSetCostGradients()`
834814e85d6SHong Zhang @*/
835814e85d6SHong Zhang PetscErrorCode TSGetCostGradients(TS ts,PetscInt *numcost,Vec **lambda,Vec **mu)
836814e85d6SHong Zhang {
837814e85d6SHong Zhang   PetscFunctionBegin;
838814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
839814e85d6SHong Zhang   if (numcost) *numcost = ts->numcost;
840814e85d6SHong Zhang   if (lambda)  *lambda  = ts->vecs_sensi;
841814e85d6SHong Zhang   if (mu)      *mu      = ts->vecs_sensip;
842814e85d6SHong Zhang   PetscFunctionReturn(0);
843814e85d6SHong Zhang }
844814e85d6SHong Zhang 
845814e85d6SHong Zhang /*@
846b5b4017aSHong Zhang    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
847b5b4017aSHong Zhang       for use by the TSAdjoint routines.
848b5b4017aSHong Zhang 
849d083f849SBarry Smith    Logically Collective on TS
850b5b4017aSHong Zhang 
851b5b4017aSHong Zhang    Input Parameters:
852b5b4017aSHong Zhang +  ts - the TS context obtained from TSCreate()
853b5b4017aSHong Zhang .  numcost - number of cost functions
854b5b4017aSHong Zhang .  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
855b5b4017aSHong Zhang .  mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
856b5b4017aSHong Zhang -  dir - the direction vector that are multiplied with the Hessian of the cost functions
857b5b4017aSHong Zhang 
858b5b4017aSHong Zhang    Level: beginner
859b5b4017aSHong Zhang 
860b5b4017aSHong Zhang    Notes: Hessian of the cost function is completely different from Hessian of the ODE/DAE system
861b5b4017aSHong Zhang 
862ecf68647SHong Zhang    For second-order adjoint, one needs to call this function and then TSAdjointSetForward() before TSSolve().
863b5b4017aSHong Zhang 
864b5b4017aSHong Zhang    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.
865b5b4017aSHong Zhang 
8663fca9621SHong Zhang    Passing NULL for lambda2 disables the second-order calculation.
867db781477SPatrick Sanan .seealso: `TSAdjointSetForward()`
868b5b4017aSHong Zhang @*/
869b5b4017aSHong Zhang PetscErrorCode TSSetCostHessianProducts(TS ts,PetscInt numcost,Vec *lambda2,Vec *mu2,Vec dir)
870b5b4017aSHong Zhang {
871b5b4017aSHong Zhang   PetscFunctionBegin;
872b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
8733c633725SBarry Smith   PetscCheck(!ts->numcost || ts->numcost == numcost,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand");
874b5b4017aSHong Zhang   ts->numcost       = numcost;
875b5b4017aSHong Zhang   ts->vecs_sensi2   = lambda2;
87633f72c5dSHong Zhang   ts->vecs_sensi2p  = mu2;
877b5b4017aSHong Zhang   ts->vec_dir       = dir;
878b5b4017aSHong Zhang   PetscFunctionReturn(0);
879b5b4017aSHong Zhang }
880b5b4017aSHong Zhang 
881b5b4017aSHong Zhang /*@
882b5b4017aSHong Zhang    TSGetCostHessianProducts - Returns the gradients from the TSAdjointSolve()
883b5b4017aSHong Zhang 
884b5b4017aSHong Zhang    Not Collective, but Vec returned is parallel if TS is parallel
885b5b4017aSHong Zhang 
886b5b4017aSHong Zhang    Input Parameter:
887b5b4017aSHong Zhang .  ts - the TS context obtained from TSCreate()
888b5b4017aSHong Zhang 
889d8d19677SJose E. Roman    Output Parameters:
890b5b4017aSHong Zhang +  numcost - number of cost functions
891b5b4017aSHong Zhang .  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
892b5b4017aSHong Zhang .  mu2 - Hessian-vector product with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
893b5b4017aSHong Zhang -  dir - the direction vector that are multiplied with the Hessian of the cost functions
894b5b4017aSHong Zhang 
895b5b4017aSHong Zhang    Level: intermediate
896b5b4017aSHong Zhang 
897db781477SPatrick Sanan .seealso: `TSSetCostHessianProducts()`
898b5b4017aSHong Zhang @*/
899b5b4017aSHong Zhang PetscErrorCode TSGetCostHessianProducts(TS ts,PetscInt *numcost,Vec **lambda2,Vec **mu2, Vec *dir)
900b5b4017aSHong Zhang {
901b5b4017aSHong Zhang   PetscFunctionBegin;
902b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
903b5b4017aSHong Zhang   if (numcost) *numcost = ts->numcost;
904b5b4017aSHong Zhang   if (lambda2) *lambda2 = ts->vecs_sensi2;
90533f72c5dSHong Zhang   if (mu2)     *mu2     = ts->vecs_sensi2p;
906b5b4017aSHong Zhang   if (dir)     *dir     = ts->vec_dir;
907b5b4017aSHong Zhang   PetscFunctionReturn(0);
908b5b4017aSHong Zhang }
909b5b4017aSHong Zhang 
910b5b4017aSHong Zhang /*@
911ecf68647SHong Zhang   TSAdjointSetForward - Trigger the tangent linear solver and initialize the forward sensitivities
912b5b4017aSHong Zhang 
913d083f849SBarry Smith   Logically Collective on TS
914b5b4017aSHong Zhang 
915b5b4017aSHong Zhang   Input Parameters:
916b5b4017aSHong Zhang +  ts - the TS context obtained from TSCreate()
917b5b4017aSHong Zhang -  didp - the derivative of initial values w.r.t. parameters
918b5b4017aSHong Zhang 
919b5b4017aSHong Zhang   Level: intermediate
920b5b4017aSHong Zhang 
921ecf68647SHong Zhang   Notes: When computing sensitivies w.r.t. initial condition, set didp to NULL so that the solver will take it as an identity matrix mathematically. TSAdjoint does not reset the tangent linear solver automatically, TSAdjointResetForward() should be called to reset the tangent linear solver.
922b5b4017aSHong Zhang 
923db781477SPatrick Sanan .seealso: `TSSetCostHessianProducts()`, `TSAdjointResetForward()`
924b5b4017aSHong Zhang @*/
925ecf68647SHong Zhang PetscErrorCode TSAdjointSetForward(TS ts,Mat didp)
926b5b4017aSHong Zhang {
92733f72c5dSHong Zhang   Mat            A;
92833f72c5dSHong Zhang   Vec            sp;
92933f72c5dSHong Zhang   PetscScalar    *xarr;
93033f72c5dSHong Zhang   PetscInt       lsize;
931b5b4017aSHong Zhang 
932b5b4017aSHong Zhang   PetscFunctionBegin;
933b5b4017aSHong Zhang   ts->forward_solve = PETSC_TRUE; /* turn on tangent linear mode */
9343c633725SBarry Smith   PetscCheck(ts->vecs_sensi2,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Must call TSSetCostHessianProducts() first");
9353c633725SBarry Smith   PetscCheck(ts->vec_dir,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Directional vector is missing. Call TSSetCostHessianProducts() to set it.");
93633f72c5dSHong Zhang   /* create a single-column dense matrix */
9379566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(ts->vec_sol,&lsize));
9389566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)ts),lsize,PETSC_DECIDE,PETSC_DECIDE,1,NULL,&A));
93933f72c5dSHong Zhang 
9409566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol,&sp));
9419566063dSJacob Faibussowitsch   PetscCall(MatDenseGetColumn(A,0,&xarr));
9429566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(sp,xarr));
943ecf68647SHong Zhang   if (ts->vecs_sensi2p) { /* tangent linear variable initialized as 2*dIdP*dir */
94433f72c5dSHong Zhang     if (didp) {
9459566063dSJacob Faibussowitsch       PetscCall(MatMult(didp,ts->vec_dir,sp));
9469566063dSJacob Faibussowitsch       PetscCall(VecScale(sp,2.));
94733f72c5dSHong Zhang     } else {
9489566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(sp));
94933f72c5dSHong Zhang     }
950ecf68647SHong Zhang   } else { /* tangent linear variable initialized as dir */
9519566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_dir,sp));
95233f72c5dSHong Zhang   }
9539566063dSJacob Faibussowitsch   PetscCall(VecResetArray(sp));
9549566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreColumn(A,&xarr));
9559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sp));
95633f72c5dSHong Zhang 
9579566063dSJacob Faibussowitsch   PetscCall(TSForwardSetInitialSensitivities(ts,A)); /* if didp is NULL, identity matrix is assumed */
95833f72c5dSHong Zhang 
9599566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
960b5b4017aSHong Zhang   PetscFunctionReturn(0);
961b5b4017aSHong Zhang }
962b5b4017aSHong Zhang 
963b5b4017aSHong Zhang /*@
964ecf68647SHong Zhang   TSAdjointResetForward - Reset the tangent linear solver and destroy the tangent linear context
965ecf68647SHong Zhang 
966d083f849SBarry Smith   Logically Collective on TS
967ecf68647SHong Zhang 
968ecf68647SHong Zhang   Input Parameters:
969ecf68647SHong Zhang .  ts - the TS context obtained from TSCreate()
970ecf68647SHong Zhang 
971ecf68647SHong Zhang   Level: intermediate
972ecf68647SHong Zhang 
973db781477SPatrick Sanan .seealso: `TSAdjointSetForward()`
974ecf68647SHong Zhang @*/
975ecf68647SHong Zhang PetscErrorCode TSAdjointResetForward(TS ts)
976ecf68647SHong Zhang {
977ecf68647SHong Zhang   PetscFunctionBegin;
978ecf68647SHong Zhang   ts->forward_solve = PETSC_FALSE; /* turn off tangent linear mode */
9799566063dSJacob Faibussowitsch   PetscCall(TSForwardReset(ts));
980ecf68647SHong Zhang   PetscFunctionReturn(0);
981ecf68647SHong Zhang }
982ecf68647SHong Zhang 
983ecf68647SHong Zhang /*@
984814e85d6SHong Zhang    TSAdjointSetUp - Sets up the internal data structures for the later use
985814e85d6SHong Zhang    of an adjoint solver
986814e85d6SHong Zhang 
987814e85d6SHong Zhang    Collective on TS
988814e85d6SHong Zhang 
989814e85d6SHong Zhang    Input Parameter:
990814e85d6SHong Zhang .  ts - the TS context obtained from TSCreate()
991814e85d6SHong Zhang 
992814e85d6SHong Zhang    Level: advanced
993814e85d6SHong Zhang 
994db781477SPatrick Sanan .seealso: `TSCreate()`, `TSAdjointStep()`, `TSSetCostGradients()`
995814e85d6SHong Zhang @*/
996814e85d6SHong Zhang PetscErrorCode TSAdjointSetUp(TS ts)
997814e85d6SHong Zhang {
998881c1a9bSHong Zhang   TSTrajectory     tj;
999881c1a9bSHong Zhang   PetscBool        match;
1000814e85d6SHong Zhang 
1001814e85d6SHong Zhang   PetscFunctionBegin;
1002814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1003814e85d6SHong Zhang   if (ts->adjointsetupcalled) PetscFunctionReturn(0);
10043c633725SBarry Smith   PetscCheck(ts->vecs_sensi,PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetCostGradients() first");
10053c633725SBarry Smith   PetscCheck(!ts->vecs_sensip || ts->Jacp || ts->Jacprhs,PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetRHSJacobianP() or TSSetIJacobianP() first");
10069566063dSJacob Faibussowitsch   PetscCall(TSGetTrajectory(ts,&tj));
10079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)tj,TSTRAJECTORYBASIC,&match));
1008881c1a9bSHong Zhang   if (match) {
1009881c1a9bSHong Zhang     PetscBool solution_only;
10109566063dSJacob Faibussowitsch     PetscCall(TSTrajectoryGetSolutionOnly(tj,&solution_only));
10113c633725SBarry Smith     PetscCheck(!solution_only,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"TSAdjoint cannot use the solution-only mode when choosing the Basic TSTrajectory type. Turn it off with -ts_trajectory_solution_only 0");
1012881c1a9bSHong Zhang   }
10139566063dSJacob Faibussowitsch   PetscCall(TSTrajectorySetUseHistory(tj,PETSC_FALSE)); /* not use TSHistory */
101433f72c5dSHong Zhang 
1015cd4cee2dSHong Zhang   if (ts->quadraturets) { /* if there is integral in the cost function */
10169566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ts->vecs_sensi[0],&ts->vec_drdu_col));
1017814e85d6SHong Zhang     if (ts->vecs_sensip) {
10189566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(ts->vecs_sensip[0],&ts->vec_drdp_col));
1019814e85d6SHong Zhang     }
1020814e85d6SHong Zhang   }
1021814e85d6SHong Zhang 
1022*1baa6e33SBarry Smith   if (ts->ops->adjointsetup) PetscCall((*ts->ops->adjointsetup)(ts));
1023814e85d6SHong Zhang   ts->adjointsetupcalled = PETSC_TRUE;
1024814e85d6SHong Zhang   PetscFunctionReturn(0);
1025814e85d6SHong Zhang }
1026814e85d6SHong Zhang 
1027814e85d6SHong Zhang /*@
1028ece46509SHong Zhang    TSAdjointReset - Resets a TSAdjoint context and removes any allocated Vecs and Mats.
1029ece46509SHong Zhang 
1030ece46509SHong Zhang    Collective on TS
1031ece46509SHong Zhang 
1032ece46509SHong Zhang    Input Parameter:
1033ece46509SHong Zhang .  ts - the TS context obtained from TSCreate()
1034ece46509SHong Zhang 
1035ece46509SHong Zhang    Level: beginner
1036ece46509SHong Zhang 
1037db781477SPatrick Sanan .seealso: `TSCreate()`, `TSAdjointSetUp()`, `TSADestroy()`
1038ece46509SHong Zhang @*/
1039ece46509SHong Zhang PetscErrorCode TSAdjointReset(TS ts)
1040ece46509SHong Zhang {
1041ece46509SHong Zhang   PetscFunctionBegin;
1042ece46509SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1043*1baa6e33SBarry Smith   if (ts->ops->adjointreset) PetscCall((*ts->ops->adjointreset)(ts));
10447207e0fdSHong Zhang   if (ts->quadraturets) { /* if there is integral in the cost function */
10459566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ts->vec_drdu_col));
10467207e0fdSHong Zhang     if (ts->vecs_sensip) {
10479566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&ts->vec_drdp_col));
10487207e0fdSHong Zhang     }
10497207e0fdSHong Zhang   }
1050ece46509SHong Zhang   ts->vecs_sensi         = NULL;
1051ece46509SHong Zhang   ts->vecs_sensip        = NULL;
1052ece46509SHong Zhang   ts->vecs_sensi2        = NULL;
105333f72c5dSHong Zhang   ts->vecs_sensi2p       = NULL;
1054ece46509SHong Zhang   ts->vec_dir            = NULL;
1055ece46509SHong Zhang   ts->adjointsetupcalled = PETSC_FALSE;
1056ece46509SHong Zhang   PetscFunctionReturn(0);
1057ece46509SHong Zhang }
1058ece46509SHong Zhang 
1059ece46509SHong Zhang /*@
1060814e85d6SHong Zhang    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time
1061814e85d6SHong Zhang 
1062814e85d6SHong Zhang    Logically Collective on TS
1063814e85d6SHong Zhang 
1064814e85d6SHong Zhang    Input Parameters:
1065814e85d6SHong Zhang +  ts - the TS context obtained from TSCreate()
1066a2b725a8SWilliam Gropp -  steps - number of steps to use
1067814e85d6SHong Zhang 
1068814e85d6SHong Zhang    Level: intermediate
1069814e85d6SHong Zhang 
1070814e85d6SHong Zhang    Notes:
1071814e85d6SHong Zhang     Normally one does not call this and TSAdjointSolve() integrates back to the original timestep. One can call this
1072814e85d6SHong Zhang           so as to integrate back to less than the original timestep
1073814e85d6SHong Zhang 
1074db781477SPatrick Sanan .seealso: `TSSetExactFinalTime()`
1075814e85d6SHong Zhang @*/
1076814e85d6SHong Zhang PetscErrorCode TSAdjointSetSteps(TS ts,PetscInt steps)
1077814e85d6SHong Zhang {
1078814e85d6SHong Zhang   PetscFunctionBegin;
1079814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1080814e85d6SHong Zhang   PetscValidLogicalCollectiveInt(ts,steps,2);
10813c633725SBarry Smith   PetscCheck(steps >= 0,PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back a negative number of steps");
10823c633725SBarry Smith   PetscCheck(steps <= ts->steps,PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back more than the total number of forward steps");
1083814e85d6SHong Zhang   ts->adjoint_max_steps = steps;
1084814e85d6SHong Zhang   PetscFunctionReturn(0);
1085814e85d6SHong Zhang }
1086814e85d6SHong Zhang 
1087814e85d6SHong Zhang /*@C
1088814e85d6SHong Zhang   TSAdjointSetRHSJacobian - Deprecated, use TSSetRHSJacobianP()
1089814e85d6SHong Zhang 
1090814e85d6SHong Zhang   Level: deprecated
1091814e85d6SHong Zhang 
1092814e85d6SHong Zhang @*/
1093814e85d6SHong Zhang PetscErrorCode TSAdjointSetRHSJacobian(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
1094814e85d6SHong Zhang {
1095814e85d6SHong Zhang   PetscFunctionBegin;
1096814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
1097814e85d6SHong Zhang   PetscValidHeaderSpecific(Amat,MAT_CLASSID,2);
1098814e85d6SHong Zhang 
1099814e85d6SHong Zhang   ts->rhsjacobianp    = func;
1100814e85d6SHong Zhang   ts->rhsjacobianpctx = ctx;
1101814e85d6SHong Zhang   if (Amat) {
11029566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)Amat));
11039566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&ts->Jacp));
1104814e85d6SHong Zhang     ts->Jacp = Amat;
1105814e85d6SHong Zhang   }
1106814e85d6SHong Zhang   PetscFunctionReturn(0);
1107814e85d6SHong Zhang }
1108814e85d6SHong Zhang 
1109814e85d6SHong Zhang /*@C
1110814e85d6SHong Zhang   TSAdjointComputeRHSJacobian - Deprecated, use TSComputeRHSJacobianP()
1111814e85d6SHong Zhang 
1112814e85d6SHong Zhang   Level: deprecated
1113814e85d6SHong Zhang 
1114814e85d6SHong Zhang @*/
1115c9ad9de0SHong Zhang PetscErrorCode TSAdjointComputeRHSJacobian(TS ts,PetscReal t,Vec U,Mat Amat)
1116814e85d6SHong Zhang {
1117814e85d6SHong Zhang   PetscFunctionBegin;
1118814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1119c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1120814e85d6SHong Zhang   PetscValidPointer(Amat,4);
1121814e85d6SHong Zhang 
1122814e85d6SHong Zhang   PetscStackPush("TS user JacobianP function for sensitivity analysis");
11239566063dSJacob Faibussowitsch   PetscCall((*ts->rhsjacobianp)(ts,t,U,Amat,ts->rhsjacobianpctx));
1124814e85d6SHong Zhang   PetscStackPop;
1125814e85d6SHong Zhang   PetscFunctionReturn(0);
1126814e85d6SHong Zhang }
1127814e85d6SHong Zhang 
1128814e85d6SHong Zhang /*@
1129d76be551SHong Zhang   TSAdjointComputeDRDYFunction - Deprecated, use TSGetQuadratureTS() then TSComputeRHSJacobian()
1130814e85d6SHong Zhang 
1131814e85d6SHong Zhang   Level: deprecated
1132814e85d6SHong Zhang 
1133814e85d6SHong Zhang @*/
1134c9ad9de0SHong Zhang PetscErrorCode TSAdjointComputeDRDYFunction(TS ts,PetscReal t,Vec U,Vec *DRDU)
1135814e85d6SHong Zhang {
1136814e85d6SHong Zhang   PetscFunctionBegin;
1137814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1138c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1139814e85d6SHong Zhang 
1140814e85d6SHong Zhang   PetscStackPush("TS user DRDY function for sensitivity analysis");
11419566063dSJacob Faibussowitsch   PetscCall((*ts->drdufunction)(ts,t,U,DRDU,ts->costintegrandctx));
1142814e85d6SHong Zhang   PetscStackPop;
1143814e85d6SHong Zhang   PetscFunctionReturn(0);
1144814e85d6SHong Zhang }
1145814e85d6SHong Zhang 
1146814e85d6SHong Zhang /*@
1147d76be551SHong Zhang   TSAdjointComputeDRDPFunction - Deprecated, use TSGetQuadratureTS() then TSComputeRHSJacobianP()
1148814e85d6SHong Zhang 
1149814e85d6SHong Zhang   Level: deprecated
1150814e85d6SHong Zhang 
1151814e85d6SHong Zhang @*/
1152c9ad9de0SHong Zhang PetscErrorCode TSAdjointComputeDRDPFunction(TS ts,PetscReal t,Vec U,Vec *DRDP)
1153814e85d6SHong Zhang {
1154814e85d6SHong Zhang   PetscFunctionBegin;
1155814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1156c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U,VEC_CLASSID,3);
1157814e85d6SHong Zhang 
1158814e85d6SHong Zhang   PetscStackPush("TS user DRDP function for sensitivity analysis");
11599566063dSJacob Faibussowitsch   PetscCall((*ts->drdpfunction)(ts,t,U,DRDP,ts->costintegrandctx));
1160814e85d6SHong Zhang   PetscStackPop;
1161814e85d6SHong Zhang   PetscFunctionReturn(0);
1162814e85d6SHong Zhang }
1163814e85d6SHong Zhang 
1164814e85d6SHong Zhang /*@C
1165814e85d6SHong Zhang    TSAdjointMonitorSensi - monitors the first lambda sensitivity
1166814e85d6SHong Zhang 
1167814e85d6SHong Zhang    Level: intermediate
1168814e85d6SHong Zhang 
1169db781477SPatrick Sanan .seealso: `TSAdjointMonitorSet()`
1170814e85d6SHong Zhang @*/
1171814e85d6SHong Zhang PetscErrorCode TSAdjointMonitorSensi(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
1172814e85d6SHong Zhang {
1173814e85d6SHong Zhang   PetscViewer    viewer = vf->viewer;
1174814e85d6SHong Zhang 
1175814e85d6SHong Zhang   PetscFunctionBegin;
1176064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,8);
11779566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer,vf->format));
11789566063dSJacob Faibussowitsch   PetscCall(VecView(lambda[0],viewer));
11799566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
1180814e85d6SHong Zhang   PetscFunctionReturn(0);
1181814e85d6SHong Zhang }
1182814e85d6SHong Zhang 
1183814e85d6SHong Zhang /*@C
1184814e85d6SHong Zhang    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
1185814e85d6SHong Zhang 
1186814e85d6SHong Zhang    Collective on TS
1187814e85d6SHong Zhang 
1188814e85d6SHong Zhang    Input Parameters:
1189814e85d6SHong Zhang +  ts - TS object you wish to monitor
1190814e85d6SHong Zhang .  name - the monitor type one is seeking
1191814e85d6SHong Zhang .  help - message indicating what monitoring is done
1192814e85d6SHong Zhang .  manual - manual page for the monitor
1193814e85d6SHong Zhang .  monitor - the monitor function
1194814e85d6SHong Zhang -  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
1195814e85d6SHong Zhang 
1196814e85d6SHong Zhang    Level: developer
1197814e85d6SHong Zhang 
1198db781477SPatrick Sanan .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
1199db781477SPatrick Sanan           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
1200db781477SPatrick Sanan           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
1201db781477SPatrick Sanan           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1202c2e3fba1SPatrick Sanan           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1203db781477SPatrick Sanan           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1204db781477SPatrick Sanan           `PetscOptionsFList()`, `PetscOptionsEList()`
1205814e85d6SHong Zhang @*/
1206814e85d6SHong Zhang 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*))
1207814e85d6SHong Zhang {
1208814e85d6SHong Zhang   PetscViewer       viewer;
1209814e85d6SHong Zhang   PetscViewerFormat format;
1210814e85d6SHong Zhang   PetscBool         flg;
1211814e85d6SHong Zhang 
1212814e85d6SHong Zhang   PetscFunctionBegin;
12139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts),((PetscObject) ts)->options,((PetscObject)ts)->prefix,name,&viewer,&format,&flg));
1214814e85d6SHong Zhang   if (flg) {
1215814e85d6SHong Zhang     PetscViewerAndFormat *vf;
12169566063dSJacob Faibussowitsch     PetscCall(PetscViewerAndFormatCreate(viewer,format,&vf));
12179566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)viewer));
1218*1baa6e33SBarry Smith     if (monitorsetup) PetscCall((*monitorsetup)(ts,vf));
12199566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitorSet(ts,(PetscErrorCode (*)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*))monitor,vf,(PetscErrorCode (*)(void**))PetscViewerAndFormatDestroy));
1220814e85d6SHong Zhang   }
1221814e85d6SHong Zhang   PetscFunctionReturn(0);
1222814e85d6SHong Zhang }
1223814e85d6SHong Zhang 
1224814e85d6SHong Zhang /*@C
1225814e85d6SHong Zhang    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
1226814e85d6SHong Zhang    timestep to display the iteration's  progress.
1227814e85d6SHong Zhang 
1228814e85d6SHong Zhang    Logically Collective on TS
1229814e85d6SHong Zhang 
1230814e85d6SHong Zhang    Input Parameters:
1231814e85d6SHong Zhang +  ts - the TS context obtained from TSCreate()
1232814e85d6SHong Zhang .  adjointmonitor - monitoring routine
1233814e85d6SHong Zhang .  adjointmctx - [optional] user-defined context for private data for the
1234814e85d6SHong Zhang              monitor routine (use NULL if no context is desired)
1235814e85d6SHong Zhang -  adjointmonitordestroy - [optional] routine that frees monitor context
1236814e85d6SHong Zhang           (may be NULL)
1237814e85d6SHong Zhang 
1238814e85d6SHong Zhang    Calling sequence of monitor:
1239814e85d6SHong Zhang $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)
1240814e85d6SHong Zhang 
1241814e85d6SHong Zhang +    ts - the TS context
1242814e85d6SHong Zhang .    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
1243814e85d6SHong Zhang                                been interpolated to)
1244814e85d6SHong Zhang .    time - current time
1245814e85d6SHong Zhang .    u - current iterate
1246814e85d6SHong Zhang .    numcost - number of cost functionos
1247814e85d6SHong Zhang .    lambda - sensitivities to initial conditions
1248814e85d6SHong Zhang .    mu - sensitivities to parameters
1249814e85d6SHong Zhang -    adjointmctx - [optional] adjoint monitoring context
1250814e85d6SHong Zhang 
1251814e85d6SHong Zhang    Notes:
1252814e85d6SHong Zhang    This routine adds an additional monitor to the list of monitors that
1253814e85d6SHong Zhang    already has been loaded.
1254814e85d6SHong Zhang 
1255814e85d6SHong Zhang    Fortran Notes:
1256814e85d6SHong Zhang     Only a single monitor function can be set for each TS object
1257814e85d6SHong Zhang 
1258814e85d6SHong Zhang    Level: intermediate
1259814e85d6SHong Zhang 
1260db781477SPatrick Sanan .seealso: `TSAdjointMonitorCancel()`
1261814e85d6SHong Zhang @*/
1262814e85d6SHong Zhang PetscErrorCode TSAdjointMonitorSet(TS ts,PetscErrorCode (*adjointmonitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*),void *adjointmctx,PetscErrorCode (*adjointmdestroy)(void**))
1263814e85d6SHong Zhang {
1264814e85d6SHong Zhang   PetscInt       i;
1265814e85d6SHong Zhang   PetscBool      identical;
1266814e85d6SHong Zhang 
1267814e85d6SHong Zhang   PetscFunctionBegin;
1268814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1269814e85d6SHong Zhang   for (i=0; i<ts->numbermonitors;i++) {
12709566063dSJacob Faibussowitsch     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor,adjointmctx,adjointmdestroy,(PetscErrorCode (*)(void))ts->adjointmonitor[i],ts->adjointmonitorcontext[i],ts->adjointmonitordestroy[i],&identical));
1271814e85d6SHong Zhang     if (identical) PetscFunctionReturn(0);
1272814e85d6SHong Zhang   }
12733c633725SBarry Smith   PetscCheck(ts->numberadjointmonitors < MAXTSMONITORS,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many adjoint monitors set");
1274814e85d6SHong Zhang   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
1275814e85d6SHong Zhang   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
1276814e85d6SHong Zhang   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void*)adjointmctx;
1277814e85d6SHong Zhang   PetscFunctionReturn(0);
1278814e85d6SHong Zhang }
1279814e85d6SHong Zhang 
1280814e85d6SHong Zhang /*@C
1281814e85d6SHong Zhang    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.
1282814e85d6SHong Zhang 
1283814e85d6SHong Zhang    Logically Collective on TS
1284814e85d6SHong Zhang 
1285814e85d6SHong Zhang    Input Parameters:
1286814e85d6SHong Zhang .  ts - the TS context obtained from TSCreate()
1287814e85d6SHong Zhang 
1288814e85d6SHong Zhang    Notes:
1289814e85d6SHong Zhang    There is no way to remove a single, specific monitor.
1290814e85d6SHong Zhang 
1291814e85d6SHong Zhang    Level: intermediate
1292814e85d6SHong Zhang 
1293db781477SPatrick Sanan .seealso: `TSAdjointMonitorSet()`
1294814e85d6SHong Zhang @*/
1295814e85d6SHong Zhang PetscErrorCode TSAdjointMonitorCancel(TS ts)
1296814e85d6SHong Zhang {
1297814e85d6SHong Zhang   PetscInt       i;
1298814e85d6SHong Zhang 
1299814e85d6SHong Zhang   PetscFunctionBegin;
1300814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1301814e85d6SHong Zhang   for (i=0; i<ts->numberadjointmonitors; i++) {
1302814e85d6SHong Zhang     if (ts->adjointmonitordestroy[i]) {
13039566063dSJacob Faibussowitsch       PetscCall((*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]));
1304814e85d6SHong Zhang     }
1305814e85d6SHong Zhang   }
1306814e85d6SHong Zhang   ts->numberadjointmonitors = 0;
1307814e85d6SHong Zhang   PetscFunctionReturn(0);
1308814e85d6SHong Zhang }
1309814e85d6SHong Zhang 
1310814e85d6SHong Zhang /*@C
1311814e85d6SHong Zhang    TSAdjointMonitorDefault - the default monitor of adjoint computations
1312814e85d6SHong Zhang 
1313814e85d6SHong Zhang    Level: intermediate
1314814e85d6SHong Zhang 
1315db781477SPatrick Sanan .seealso: `TSAdjointMonitorSet()`
1316814e85d6SHong Zhang @*/
1317814e85d6SHong Zhang PetscErrorCode TSAdjointMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
1318814e85d6SHong Zhang {
1319814e85d6SHong Zhang   PetscViewer    viewer = vf->viewer;
1320814e85d6SHong Zhang 
1321814e85d6SHong Zhang   PetscFunctionBegin;
1322064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,8);
13239566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer,vf->format));
13249566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel));
132563a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " TS dt %g time %g%s",step,(double)ts->time_step,(double)ptime,ts->steprollback ? " (r)\n" : "\n"));
13269566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel));
13279566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
1328814e85d6SHong Zhang   PetscFunctionReturn(0);
1329814e85d6SHong Zhang }
1330814e85d6SHong Zhang 
1331814e85d6SHong Zhang /*@C
1332814e85d6SHong Zhang    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint TS solvers by calling
1333814e85d6SHong Zhang    VecView() for the sensitivities to initial states at each timestep
1334814e85d6SHong Zhang 
1335814e85d6SHong Zhang    Collective on TS
1336814e85d6SHong Zhang 
1337814e85d6SHong Zhang    Input Parameters:
1338814e85d6SHong Zhang +  ts - the TS context
1339814e85d6SHong Zhang .  step - current time-step
1340814e85d6SHong Zhang .  ptime - current time
1341814e85d6SHong Zhang .  u - current state
1342814e85d6SHong Zhang .  numcost - number of cost functions
1343814e85d6SHong Zhang .  lambda - sensitivities to initial conditions
1344814e85d6SHong Zhang .  mu - sensitivities to parameters
1345814e85d6SHong Zhang -  dummy - either a viewer or NULL
1346814e85d6SHong Zhang 
1347814e85d6SHong Zhang    Level: intermediate
1348814e85d6SHong Zhang 
1349db781477SPatrick Sanan .seealso: `TSAdjointMonitorSet()`, `TSAdjointMonitorDefault()`, `VecView()`
1350814e85d6SHong Zhang @*/
1351814e85d6SHong Zhang PetscErrorCode TSAdjointMonitorDrawSensi(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda,Vec *mu,void *dummy)
1352814e85d6SHong Zhang {
1353814e85d6SHong Zhang   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
1354814e85d6SHong Zhang   PetscDraw        draw;
1355814e85d6SHong Zhang   PetscReal        xl,yl,xr,yr,h;
1356814e85d6SHong Zhang   char             time[32];
1357814e85d6SHong Zhang 
1358814e85d6SHong Zhang   PetscFunctionBegin;
1359814e85d6SHong Zhang   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
1360814e85d6SHong Zhang 
13619566063dSJacob Faibussowitsch   PetscCall(VecView(lambda[0],ictx->viewer));
13629566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(ictx->viewer,0,&draw));
13639566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(time,32,"Timestep %d Time %g",(int)step,(double)ptime));
13649566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr));
1365814e85d6SHong Zhang   h    = yl + .95*(yr - yl);
13669566063dSJacob Faibussowitsch   PetscCall(PetscDrawStringCentered(draw,.5*(xl+xr),h,PETSC_DRAW_BLACK,time));
13679566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
1368814e85d6SHong Zhang   PetscFunctionReturn(0);
1369814e85d6SHong Zhang }
1370814e85d6SHong Zhang 
1371814e85d6SHong Zhang /*
1372814e85d6SHong Zhang    TSAdjointSetFromOptions - Sets various TSAdjoint parameters from user options.
1373814e85d6SHong Zhang 
1374814e85d6SHong Zhang    Collective on TSAdjoint
1375814e85d6SHong Zhang 
1376814e85d6SHong Zhang    Input Parameter:
1377814e85d6SHong Zhang .  ts - the TS context
1378814e85d6SHong Zhang 
1379814e85d6SHong Zhang    Options Database Keys:
1380814e85d6SHong Zhang +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
1381814e85d6SHong Zhang .  -ts_adjoint_monitor - print information at each adjoint time step
1382814e85d6SHong Zhang -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically
1383814e85d6SHong Zhang 
1384814e85d6SHong Zhang    Level: developer
1385814e85d6SHong Zhang 
1386814e85d6SHong Zhang    Notes:
1387814e85d6SHong Zhang     This is not normally called directly by users
1388814e85d6SHong Zhang 
1389db781477SPatrick Sanan .seealso: `TSSetSaveTrajectory()`, `TSTrajectorySetUp()`
1390814e85d6SHong Zhang */
1391814e85d6SHong Zhang PetscErrorCode TSAdjointSetFromOptions(PetscOptionItems *PetscOptionsObject,TS ts)
1392814e85d6SHong Zhang {
1393814e85d6SHong Zhang   PetscBool      tflg,opt;
1394814e85d6SHong Zhang 
1395814e85d6SHong Zhang   PetscFunctionBegin;
1396814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
1397d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"TS Adjoint options");
1398814e85d6SHong Zhang   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
13999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-ts_adjoint_solve","Solve the adjoint problem immediately after solving the forward problem","",tflg,&tflg,&opt));
1400814e85d6SHong Zhang   if (opt) {
14019566063dSJacob Faibussowitsch     PetscCall(TSSetSaveTrajectory(ts));
1402814e85d6SHong Zhang     ts->adjoint_solve = tflg;
1403814e85d6SHong Zhang   }
14049566063dSJacob Faibussowitsch   PetscCall(TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor","Monitor adjoint timestep size","TSAdjointMonitorDefault",TSAdjointMonitorDefault,NULL));
14059566063dSJacob Faibussowitsch   PetscCall(TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor_sensi","Monitor sensitivity in the adjoint computation","TSAdjointMonitorSensi",TSAdjointMonitorSensi,NULL));
1406814e85d6SHong Zhang   opt  = PETSC_FALSE;
14079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsName("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",&opt));
1408814e85d6SHong Zhang   if (opt) {
1409814e85d6SHong Zhang     TSMonitorDrawCtx ctx;
1410814e85d6SHong Zhang     PetscInt         howoften = 1;
1411814e85d6SHong Zhang 
14129566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",howoften,&howoften,NULL));
14139566063dSJacob Faibussowitsch     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts),NULL,NULL,PETSC_DECIDE,PETSC_DECIDE,300,300,howoften,&ctx));
14149566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitorSet(ts,TSAdjointMonitorDrawSensi,ctx,(PetscErrorCode (*)(void**))TSMonitorDrawCtxDestroy));
1415814e85d6SHong Zhang   }
1416814e85d6SHong Zhang   PetscFunctionReturn(0);
1417814e85d6SHong Zhang }
1418814e85d6SHong Zhang 
1419814e85d6SHong Zhang /*@
1420814e85d6SHong Zhang    TSAdjointStep - Steps one time step backward in the adjoint run
1421814e85d6SHong Zhang 
1422814e85d6SHong Zhang    Collective on TS
1423814e85d6SHong Zhang 
1424814e85d6SHong Zhang    Input Parameter:
1425814e85d6SHong Zhang .  ts - the TS context obtained from TSCreate()
1426814e85d6SHong Zhang 
1427814e85d6SHong Zhang    Level: intermediate
1428814e85d6SHong Zhang 
1429db781477SPatrick Sanan .seealso: `TSAdjointSetUp()`, `TSAdjointSolve()`
1430814e85d6SHong Zhang @*/
1431814e85d6SHong Zhang PetscErrorCode TSAdjointStep(TS ts)
1432814e85d6SHong Zhang {
1433814e85d6SHong Zhang   DM               dm;
1434814e85d6SHong Zhang 
1435814e85d6SHong Zhang   PetscFunctionBegin;
1436814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
14379566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts,&dm));
14389566063dSJacob Faibussowitsch   PetscCall(TSAdjointSetUp(ts));
14397b0e2f17SHong Zhang   ts->steps--; /* must decrease the step index before the adjoint step is taken. */
1440814e85d6SHong Zhang 
1441814e85d6SHong Zhang   ts->reason = TS_CONVERGED_ITERATING;
1442814e85d6SHong Zhang   ts->ptime_prev = ts->ptime;
14433c633725SBarry Smith   PetscCheck(ts->ops->adjointstep,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);
14449566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_AdjointStep,ts,0,0,0));
14459566063dSJacob Faibussowitsch   PetscCall((*ts->ops->adjointstep)(ts));
14469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_AdjointStep,ts,0,0,0));
14477b0e2f17SHong Zhang   ts->adjoint_steps++;
1448814e85d6SHong Zhang 
1449814e85d6SHong Zhang   if (ts->reason < 0) {
14503c633725SBarry Smith     PetscCheck(!ts->errorifstepfailed,PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSAdjointStep has failed due to %s",TSConvergedReasons[ts->reason]);
1451814e85d6SHong Zhang   } else if (!ts->reason) {
1452814e85d6SHong Zhang     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1453814e85d6SHong Zhang   }
1454814e85d6SHong Zhang   PetscFunctionReturn(0);
1455814e85d6SHong Zhang }
1456814e85d6SHong Zhang 
1457814e85d6SHong Zhang /*@
1458814e85d6SHong Zhang    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE
1459814e85d6SHong Zhang 
1460814e85d6SHong Zhang    Collective on TS
1461814e85d6SHong Zhang 
1462814e85d6SHong Zhang    Input Parameter:
1463814e85d6SHong Zhang .  ts - the TS context obtained from TSCreate()
1464814e85d6SHong Zhang 
1465814e85d6SHong Zhang    Options Database:
1466814e85d6SHong Zhang . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values
1467814e85d6SHong Zhang 
1468814e85d6SHong Zhang    Level: intermediate
1469814e85d6SHong Zhang 
1470814e85d6SHong Zhang    Notes:
1471814e85d6SHong Zhang    This must be called after a call to TSSolve() that solves the forward problem
1472814e85d6SHong Zhang 
1473814e85d6SHong Zhang    By default this will integrate back to the initial time, one can use TSAdjointSetSteps() to step back to a later time
1474814e85d6SHong Zhang 
1475db781477SPatrick Sanan .seealso: `TSCreate()`, `TSSetCostGradients()`, `TSSetSolution()`, `TSAdjointStep()`
1476814e85d6SHong Zhang @*/
1477814e85d6SHong Zhang PetscErrorCode TSAdjointSolve(TS ts)
1478814e85d6SHong Zhang {
1479f1d62c27SHong Zhang   static PetscBool cite = PETSC_FALSE;
14807f59fb53SHong Zhang #if defined(TSADJOINT_STAGE)
14817f59fb53SHong Zhang   PetscLogStage  adjoint_stage;
14827f59fb53SHong Zhang #endif
1483814e85d6SHong Zhang 
1484814e85d6SHong Zhang   PetscFunctionBegin;
1485814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1486421b783aSHong Zhang   PetscCall(PetscCitationsRegister("@article{Zhang2022tsadjoint,\n"
1487421b783aSHong Zhang                                  "  title         = {{PETSc TSAdjoint: A Discrete Adjoint ODE Solver for First-Order and Second-Order Sensitivity Analysis}},\n"
1488f1d62c27SHong Zhang                                  "  author        = {Zhang, Hong and Constantinescu, Emil M.  and Smith, Barry F.},\n"
1489421b783aSHong Zhang                                  "  journal       = {SIAM Journal on Scientific Computing},\n"
1490421b783aSHong Zhang                                  "  volume        = {44},\n"
1491421b783aSHong Zhang                                  "  number        = {1},\n"
1492421b783aSHong Zhang                                  "  pages         = {C1-C24},\n"
1493421b783aSHong Zhang                                  "  doi           = {10.1137/21M140078X},\n"
1494421b783aSHong Zhang                                  "  year          = {2022}\n}\n",&cite));
14957f59fb53SHong Zhang #if defined(TSADJOINT_STAGE)
14969566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("TSAdjoint",&adjoint_stage));
14979566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(adjoint_stage));
14987f59fb53SHong Zhang #endif
14999566063dSJacob Faibussowitsch   PetscCall(TSAdjointSetUp(ts));
1500814e85d6SHong Zhang 
1501814e85d6SHong Zhang   /* reset time step and iteration counters */
1502814e85d6SHong Zhang   ts->adjoint_steps     = 0;
1503814e85d6SHong Zhang   ts->ksp_its           = 0;
1504814e85d6SHong Zhang   ts->snes_its          = 0;
1505814e85d6SHong Zhang   ts->num_snes_failures = 0;
1506814e85d6SHong Zhang   ts->reject            = 0;
1507814e85d6SHong Zhang   ts->reason            = TS_CONVERGED_ITERATING;
1508814e85d6SHong Zhang 
1509814e85d6SHong Zhang   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
1510814e85d6SHong Zhang   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1511814e85d6SHong Zhang 
1512814e85d6SHong Zhang   while (!ts->reason) {
15139566063dSJacob Faibussowitsch     PetscCall(TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime));
15149566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip));
15159566063dSJacob Faibussowitsch     PetscCall(TSAdjointEventHandler(ts));
15169566063dSJacob Faibussowitsch     PetscCall(TSAdjointStep(ts));
1517cd4cee2dSHong Zhang     if ((ts->vec_costintegral || ts->quadraturets) && !ts->costintegralfwd) {
15189566063dSJacob Faibussowitsch       PetscCall(TSAdjointCostIntegral(ts));
1519814e85d6SHong Zhang     }
1520814e85d6SHong Zhang   }
1521bdbff044SHong Zhang   if (!ts->steps) {
15229566063dSJacob Faibussowitsch     PetscCall(TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime));
15239566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip));
1524bdbff044SHong Zhang   }
1525814e85d6SHong Zhang   ts->solvetime = ts->ptime;
15269566063dSJacob Faibussowitsch   PetscCall(TSTrajectoryViewFromOptions(ts->trajectory,NULL,"-ts_trajectory_view"));
15279566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(ts->vecs_sensi[0],(PetscObject) ts, "-ts_adjoint_view_solution"));
1528814e85d6SHong Zhang   ts->adjoint_max_steps = 0;
15297f59fb53SHong Zhang #if defined(TSADJOINT_STAGE)
15309566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
15317f59fb53SHong Zhang #endif
1532814e85d6SHong Zhang   PetscFunctionReturn(0);
1533814e85d6SHong Zhang }
1534814e85d6SHong Zhang 
1535814e85d6SHong Zhang /*@C
1536814e85d6SHong Zhang    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using TSAdjointMonitorSet()
1537814e85d6SHong Zhang 
1538814e85d6SHong Zhang    Collective on TS
1539814e85d6SHong Zhang 
1540814e85d6SHong Zhang    Input Parameters:
1541814e85d6SHong Zhang +  ts - time stepping context obtained from TSCreate()
1542814e85d6SHong Zhang .  step - step number that has just completed
1543814e85d6SHong Zhang .  ptime - model time of the state
1544814e85d6SHong Zhang .  u - state at the current model time
1545814e85d6SHong Zhang .  numcost - number of cost functions (dimension of lambda  or mu)
1546814e85d6SHong Zhang .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
1547814e85d6SHong Zhang -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
1548814e85d6SHong Zhang 
1549814e85d6SHong Zhang    Notes:
1550814e85d6SHong Zhang    TSAdjointMonitor() is typically used automatically within the time stepping implementations.
1551814e85d6SHong Zhang    Users would almost never call this routine directly.
1552814e85d6SHong Zhang 
1553814e85d6SHong Zhang    Level: developer
1554814e85d6SHong Zhang 
1555814e85d6SHong Zhang @*/
1556814e85d6SHong Zhang PetscErrorCode TSAdjointMonitor(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda, Vec *mu)
1557814e85d6SHong Zhang {
1558814e85d6SHong Zhang   PetscInt       i,n = ts->numberadjointmonitors;
1559814e85d6SHong Zhang 
1560814e85d6SHong Zhang   PetscFunctionBegin;
1561814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1562814e85d6SHong Zhang   PetscValidHeaderSpecific(u,VEC_CLASSID,4);
15639566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(u));
1564814e85d6SHong Zhang   for (i=0; i<n; i++) {
15659566063dSJacob Faibussowitsch     PetscCall((*ts->adjointmonitor[i])(ts,step,ptime,u,numcost,lambda,mu,ts->adjointmonitorcontext[i]));
1566814e85d6SHong Zhang   }
15679566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(u));
1568814e85d6SHong Zhang   PetscFunctionReturn(0);
1569814e85d6SHong Zhang }
1570814e85d6SHong Zhang 
1571814e85d6SHong Zhang /*@
1572814e85d6SHong Zhang  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.
1573814e85d6SHong Zhang 
1574814e85d6SHong Zhang  Collective on TS
1575814e85d6SHong Zhang 
15764165533cSJose E. Roman  Input Parameter:
1577814e85d6SHong Zhang  .  ts - time stepping context
1578814e85d6SHong Zhang 
1579814e85d6SHong Zhang  Level: advanced
1580814e85d6SHong Zhang 
1581814e85d6SHong Zhang  Notes:
1582814e85d6SHong Zhang  This function cannot be called until TSAdjointStep() has been completed.
1583814e85d6SHong Zhang 
1584db781477SPatrick Sanan  .seealso: `TSAdjointSolve()`, `TSAdjointStep`
1585814e85d6SHong Zhang  @*/
1586814e85d6SHong Zhang PetscErrorCode TSAdjointCostIntegral(TS ts)
1587814e85d6SHong Zhang {
1588362febeeSStefano Zampini   PetscFunctionBegin;
1589814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
15903c633725SBarry Smith   PetscCheck(ts->ops->adjointintegral,PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide integral evaluation in the adjoint run",((PetscObject)ts)->type_name);
15919566063dSJacob Faibussowitsch   PetscCall((*ts->ops->adjointintegral)(ts));
1592814e85d6SHong Zhang   PetscFunctionReturn(0);
1593814e85d6SHong Zhang }
1594814e85d6SHong Zhang 
1595814e85d6SHong Zhang /* ------------------ Forward (tangent linear) sensitivity  ------------------*/
1596814e85d6SHong Zhang 
1597814e85d6SHong Zhang /*@
1598814e85d6SHong Zhang   TSForwardSetUp - Sets up the internal data structures for the later use
1599814e85d6SHong Zhang   of forward sensitivity analysis
1600814e85d6SHong Zhang 
1601814e85d6SHong Zhang   Collective on TS
1602814e85d6SHong Zhang 
1603814e85d6SHong Zhang   Input Parameter:
1604814e85d6SHong Zhang . ts - the TS context obtained from TSCreate()
1605814e85d6SHong Zhang 
1606814e85d6SHong Zhang   Level: advanced
1607814e85d6SHong Zhang 
1608db781477SPatrick Sanan .seealso: `TSCreate()`, `TSDestroy()`, `TSSetUp()`
1609814e85d6SHong Zhang @*/
1610814e85d6SHong Zhang PetscErrorCode TSForwardSetUp(TS ts)
1611814e85d6SHong Zhang {
1612814e85d6SHong Zhang   PetscFunctionBegin;
1613814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1614814e85d6SHong Zhang   if (ts->forwardsetupcalled) PetscFunctionReturn(0);
1615*1baa6e33SBarry Smith   if (ts->ops->forwardsetup) PetscCall((*ts->ops->forwardsetup)(ts));
16169566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol,&ts->vec_sensip_col));
1617814e85d6SHong Zhang   ts->forwardsetupcalled = PETSC_TRUE;
1618814e85d6SHong Zhang   PetscFunctionReturn(0);
1619814e85d6SHong Zhang }
1620814e85d6SHong Zhang 
1621814e85d6SHong Zhang /*@
16227adebddeSHong Zhang   TSForwardReset - Reset the internal data structures used by forward sensitivity analysis
16237adebddeSHong Zhang 
16247adebddeSHong Zhang   Collective on TS
16257adebddeSHong Zhang 
16267adebddeSHong Zhang   Input Parameter:
16277adebddeSHong Zhang . ts - the TS context obtained from TSCreate()
16287adebddeSHong Zhang 
16297adebddeSHong Zhang   Level: advanced
16307adebddeSHong Zhang 
1631db781477SPatrick Sanan .seealso: `TSCreate()`, `TSDestroy()`, `TSForwardSetUp()`
16327adebddeSHong Zhang @*/
16337adebddeSHong Zhang PetscErrorCode TSForwardReset(TS ts)
16347adebddeSHong Zhang {
16357207e0fdSHong Zhang   TS             quadts = ts->quadraturets;
16367adebddeSHong Zhang 
16377adebddeSHong Zhang   PetscFunctionBegin;
16387adebddeSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1639*1baa6e33SBarry Smith   if (ts->ops->forwardreset) PetscCall((*ts->ops->forwardreset)(ts));
16409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ts->mat_sensip));
16417207e0fdSHong Zhang   if (quadts) {
16429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&quadts->mat_sensip));
16437207e0fdSHong Zhang   }
16449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ts->vec_sensip_col));
16457adebddeSHong Zhang   ts->forward_solve      = PETSC_FALSE;
16467adebddeSHong Zhang   ts->forwardsetupcalled = PETSC_FALSE;
16477adebddeSHong Zhang   PetscFunctionReturn(0);
16487adebddeSHong Zhang }
16497adebddeSHong Zhang 
16507adebddeSHong Zhang /*@
1651814e85d6SHong Zhang   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.
1652814e85d6SHong Zhang 
1653d8d19677SJose E. Roman   Input Parameters:
1654a2b725a8SWilliam Gropp + ts - the TS context obtained from TSCreate()
1655814e85d6SHong Zhang . numfwdint - number of integrals
165667b8a455SSatish Balay - vp - the vectors containing the gradients for each integral w.r.t. parameters
1657814e85d6SHong Zhang 
16587207e0fdSHong Zhang   Level: deprecated
1659814e85d6SHong Zhang 
1660db781477SPatrick Sanan .seealso: `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1661814e85d6SHong Zhang @*/
1662814e85d6SHong Zhang PetscErrorCode TSForwardSetIntegralGradients(TS ts,PetscInt numfwdint,Vec *vp)
1663814e85d6SHong Zhang {
1664814e85d6SHong Zhang   PetscFunctionBegin;
1665814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
16663c633725SBarry Smith   PetscCheck(!ts->numcost || ts->numcost == numfwdint,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2nd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand()");
1667814e85d6SHong Zhang   if (!ts->numcost) ts->numcost = numfwdint;
1668814e85d6SHong Zhang 
1669814e85d6SHong Zhang   ts->vecs_integral_sensip = vp;
1670814e85d6SHong Zhang   PetscFunctionReturn(0);
1671814e85d6SHong Zhang }
1672814e85d6SHong Zhang 
1673814e85d6SHong Zhang /*@
1674814e85d6SHong Zhang   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.
1675814e85d6SHong Zhang 
1676814e85d6SHong Zhang   Input Parameter:
1677814e85d6SHong Zhang . ts - the TS context obtained from TSCreate()
1678814e85d6SHong Zhang 
1679814e85d6SHong Zhang   Output Parameter:
168067b8a455SSatish Balay . vp - the vectors containing the gradients for each integral w.r.t. parameters
1681814e85d6SHong Zhang 
16827207e0fdSHong Zhang   Level: deprecated
1683814e85d6SHong Zhang 
1684db781477SPatrick Sanan .seealso: `TSForwardSetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1685814e85d6SHong Zhang @*/
1686814e85d6SHong Zhang PetscErrorCode TSForwardGetIntegralGradients(TS ts,PetscInt *numfwdint,Vec **vp)
1687814e85d6SHong Zhang {
1688814e85d6SHong Zhang   PetscFunctionBegin;
1689814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1690814e85d6SHong Zhang   PetscValidPointer(vp,3);
1691814e85d6SHong Zhang   if (numfwdint) *numfwdint = ts->numcost;
1692814e85d6SHong Zhang   if (vp) *vp = ts->vecs_integral_sensip;
1693814e85d6SHong Zhang   PetscFunctionReturn(0);
1694814e85d6SHong Zhang }
1695814e85d6SHong Zhang 
1696814e85d6SHong Zhang /*@
1697814e85d6SHong Zhang   TSForwardStep - Compute the forward sensitivity for one time step.
1698814e85d6SHong Zhang 
1699814e85d6SHong Zhang   Collective on TS
1700814e85d6SHong Zhang 
17014165533cSJose E. Roman   Input Parameter:
1702814e85d6SHong Zhang . ts - time stepping context
1703814e85d6SHong Zhang 
1704814e85d6SHong Zhang   Level: advanced
1705814e85d6SHong Zhang 
1706814e85d6SHong Zhang   Notes:
1707814e85d6SHong Zhang   This function cannot be called until TSStep() has been completed.
1708814e85d6SHong Zhang 
1709db781477SPatrick Sanan .seealso: `TSForwardSetSensitivities()`, `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardSetUp()`
1710814e85d6SHong Zhang @*/
1711814e85d6SHong Zhang PetscErrorCode TSForwardStep(TS ts)
1712814e85d6SHong Zhang {
1713362febeeSStefano Zampini   PetscFunctionBegin;
1714814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
17153c633725SBarry Smith   PetscCheck(ts->ops->forwardstep,PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide forward sensitivity analysis",((PetscObject)ts)->type_name);
17169566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_ForwardStep,ts,0,0,0));
17179566063dSJacob Faibussowitsch   PetscCall((*ts->ops->forwardstep)(ts));
17189566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_ForwardStep,ts,0,0,0));
17193c633725SBarry Smith   PetscCheck(ts->reason >= 0 || !ts->errorifstepfailed,PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSFowardStep has failed due to %s",TSConvergedReasons[ts->reason]);
1720814e85d6SHong Zhang   PetscFunctionReturn(0);
1721814e85d6SHong Zhang }
1722814e85d6SHong Zhang 
1723814e85d6SHong Zhang /*@
1724814e85d6SHong Zhang   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.
1725814e85d6SHong Zhang 
1726d083f849SBarry Smith   Logically Collective on TS
1727814e85d6SHong Zhang 
1728814e85d6SHong Zhang   Input Parameters:
1729814e85d6SHong Zhang + ts - the TS context obtained from TSCreate()
1730814e85d6SHong Zhang . nump - number of parameters
1731814e85d6SHong Zhang - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1732814e85d6SHong Zhang 
1733814e85d6SHong Zhang   Level: beginner
1734814e85d6SHong Zhang 
1735814e85d6SHong Zhang   Notes:
1736814e85d6SHong Zhang   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
1737814e85d6SHong Zhang   This function turns on a flag to trigger TSSolve() to compute forward sensitivities automatically.
1738814e85d6SHong Zhang   You must call this function before TSSolve().
1739814e85d6SHong Zhang   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.
1740814e85d6SHong Zhang 
1741db781477SPatrick Sanan .seealso: `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1742814e85d6SHong Zhang @*/
1743814e85d6SHong Zhang PetscErrorCode TSForwardSetSensitivities(TS ts,PetscInt nump,Mat Smat)
1744814e85d6SHong Zhang {
1745814e85d6SHong Zhang   PetscFunctionBegin;
1746814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1747814e85d6SHong Zhang   PetscValidHeaderSpecific(Smat,MAT_CLASSID,3);
1748814e85d6SHong Zhang   ts->forward_solve  = PETSC_TRUE;
1749b5b4017aSHong Zhang   if (nump == PETSC_DEFAULT) {
17509566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Smat,NULL,&ts->num_parameters));
1751b5b4017aSHong Zhang   } else ts->num_parameters = nump;
17529566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)Smat));
17539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ts->mat_sensip));
1754814e85d6SHong Zhang   ts->mat_sensip = Smat;
1755814e85d6SHong Zhang   PetscFunctionReturn(0);
1756814e85d6SHong Zhang }
1757814e85d6SHong Zhang 
1758814e85d6SHong Zhang /*@
1759814e85d6SHong Zhang   TSForwardGetSensitivities - Returns the trajectory sensitivities
1760814e85d6SHong Zhang 
1761814e85d6SHong Zhang   Not Collective, but Vec returned is parallel if TS is parallel
1762814e85d6SHong Zhang 
1763d8d19677SJose E. Roman   Output Parameters:
1764814e85d6SHong Zhang + ts - the TS context obtained from TSCreate()
1765814e85d6SHong Zhang . nump - number of parameters
1766814e85d6SHong Zhang - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1767814e85d6SHong Zhang 
1768814e85d6SHong Zhang   Level: intermediate
1769814e85d6SHong Zhang 
1770db781477SPatrick Sanan .seealso: `TSForwardSetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1771814e85d6SHong Zhang @*/
1772814e85d6SHong Zhang PetscErrorCode TSForwardGetSensitivities(TS ts,PetscInt *nump,Mat *Smat)
1773814e85d6SHong Zhang {
1774814e85d6SHong Zhang   PetscFunctionBegin;
1775814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1776814e85d6SHong Zhang   if (nump) *nump = ts->num_parameters;
1777814e85d6SHong Zhang   if (Smat) *Smat = ts->mat_sensip;
1778814e85d6SHong Zhang   PetscFunctionReturn(0);
1779814e85d6SHong Zhang }
1780814e85d6SHong Zhang 
1781814e85d6SHong Zhang /*@
1782814e85d6SHong Zhang    TSForwardCostIntegral - Evaluate the cost integral in the forward run.
1783814e85d6SHong Zhang 
1784814e85d6SHong Zhang    Collective on TS
1785814e85d6SHong Zhang 
17864165533cSJose E. Roman    Input Parameter:
1787814e85d6SHong Zhang .  ts - time stepping context
1788814e85d6SHong Zhang 
1789814e85d6SHong Zhang    Level: advanced
1790814e85d6SHong Zhang 
1791814e85d6SHong Zhang    Notes:
1792814e85d6SHong Zhang    This function cannot be called until TSStep() has been completed.
1793814e85d6SHong Zhang 
1794db781477SPatrick Sanan .seealso: `TSSolve()`, `TSAdjointCostIntegral()`
1795814e85d6SHong Zhang @*/
1796814e85d6SHong Zhang PetscErrorCode TSForwardCostIntegral(TS ts)
1797814e85d6SHong Zhang {
1798362febeeSStefano Zampini   PetscFunctionBegin;
1799814e85d6SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
18003c633725SBarry Smith   PetscCheck(ts->ops->forwardintegral,PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide integral evaluation in the forward run",((PetscObject)ts)->type_name);
18019566063dSJacob Faibussowitsch   PetscCall((*ts->ops->forwardintegral)(ts));
1802814e85d6SHong Zhang   PetscFunctionReturn(0);
1803814e85d6SHong Zhang }
1804b5b4017aSHong Zhang 
1805b5b4017aSHong Zhang /*@
1806b5b4017aSHong Zhang   TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities
1807b5b4017aSHong Zhang 
1808d083f849SBarry Smith   Collective on TS
1809b5b4017aSHong Zhang 
1810d8d19677SJose E. Roman   Input Parameters:
1811b5b4017aSHong Zhang + ts - the TS context obtained from TSCreate()
1812b5b4017aSHong Zhang - didp - parametric sensitivities of the initial condition
1813b5b4017aSHong Zhang 
1814b5b4017aSHong Zhang   Level: intermediate
1815b5b4017aSHong Zhang 
1816b5b4017aSHong Zhang   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.
1817b5b4017aSHong Zhang 
1818db781477SPatrick Sanan .seealso: `TSForwardSetSensitivities()`
1819b5b4017aSHong Zhang @*/
1820b5b4017aSHong Zhang PetscErrorCode TSForwardSetInitialSensitivities(TS ts,Mat didp)
1821b5b4017aSHong Zhang {
1822362febeeSStefano Zampini   PetscFunctionBegin;
1823b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1824b5b4017aSHong Zhang   PetscValidHeaderSpecific(didp,MAT_CLASSID,2);
1825b5b4017aSHong Zhang   if (!ts->mat_sensip) {
18269566063dSJacob Faibussowitsch     PetscCall(TSForwardSetSensitivities(ts,PETSC_DEFAULT,didp));
1827b5b4017aSHong Zhang   }
1828b5b4017aSHong Zhang   PetscFunctionReturn(0);
1829b5b4017aSHong Zhang }
18306affb6f8SHong Zhang 
18316affb6f8SHong Zhang /*@
18326affb6f8SHong Zhang    TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages
18336affb6f8SHong Zhang 
18346affb6f8SHong Zhang    Input Parameter:
18356affb6f8SHong Zhang .  ts - the TS context obtained from TSCreate()
18366affb6f8SHong Zhang 
18376affb6f8SHong Zhang    Output Parameters:
1838cd4cee2dSHong Zhang +  ns - number of stages
18396affb6f8SHong Zhang -  S - tangent linear sensitivities at the intermediate stages
18406affb6f8SHong Zhang 
18416affb6f8SHong Zhang    Level: advanced
18426affb6f8SHong Zhang 
18436affb6f8SHong Zhang @*/
18446affb6f8SHong Zhang PetscErrorCode TSForwardGetStages(TS ts,PetscInt *ns,Mat **S)
18456affb6f8SHong Zhang {
18466affb6f8SHong Zhang   PetscFunctionBegin;
18476affb6f8SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID,1);
18486affb6f8SHong Zhang 
18496affb6f8SHong Zhang   if (!ts->ops->getstages) *S=NULL;
18506affb6f8SHong Zhang   else {
18519566063dSJacob Faibussowitsch     PetscCall((*ts->ops->forwardgetstages)(ts,ns,S));
18526affb6f8SHong Zhang   }
18536affb6f8SHong Zhang   PetscFunctionReturn(0);
18546affb6f8SHong Zhang }
1855cd4cee2dSHong Zhang 
1856cd4cee2dSHong Zhang /*@
1857cd4cee2dSHong Zhang    TSCreateQuadratureTS - Create a sub-TS that evaluates integrals over time
1858cd4cee2dSHong Zhang 
1859d8d19677SJose E. Roman    Input Parameters:
1860cd4cee2dSHong Zhang +  ts - the TS context obtained from TSCreate()
1861cd4cee2dSHong Zhang -  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
1862cd4cee2dSHong Zhang 
1863cd4cee2dSHong Zhang    Output Parameters:
1864cd4cee2dSHong Zhang .  quadts - the child TS context
1865cd4cee2dSHong Zhang 
1866cd4cee2dSHong Zhang    Level: intermediate
1867cd4cee2dSHong Zhang 
1868db781477SPatrick Sanan .seealso: `TSGetQuadratureTS()`
1869cd4cee2dSHong Zhang @*/
1870cd4cee2dSHong Zhang PetscErrorCode TSCreateQuadratureTS(TS ts,PetscBool fwd,TS *quadts)
1871cd4cee2dSHong Zhang {
1872cd4cee2dSHong Zhang   char prefix[128];
1873cd4cee2dSHong Zhang 
1874cd4cee2dSHong Zhang   PetscFunctionBegin;
1875cd4cee2dSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1876064a246eSJacob Faibussowitsch   PetscValidPointer(quadts,3);
18779566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts->quadraturets));
18789566063dSJacob Faibussowitsch   PetscCall(TSCreate(PetscObjectComm((PetscObject)ts),&ts->quadraturets));
18799566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->quadraturets,(PetscObject)ts,1));
18809566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)ts,(PetscObject)ts->quadraturets));
18819566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix,sizeof(prefix),"%squad_",((PetscObject)ts)->prefix ? ((PetscObject)ts)->prefix : ""));
18829566063dSJacob Faibussowitsch   PetscCall(TSSetOptionsPrefix(ts->quadraturets,prefix));
1883cd4cee2dSHong Zhang   *quadts = ts->quadraturets;
1884cd4cee2dSHong Zhang 
1885cd4cee2dSHong Zhang   if (ts->numcost) {
18869566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF,ts->numcost,&(*quadts)->vec_sol));
1887cd4cee2dSHong Zhang   } else {
18889566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF,1,&(*quadts)->vec_sol));
1889cd4cee2dSHong Zhang   }
1890cd4cee2dSHong Zhang   ts->costintegralfwd = fwd;
1891cd4cee2dSHong Zhang   PetscFunctionReturn(0);
1892cd4cee2dSHong Zhang }
1893cd4cee2dSHong Zhang 
1894cd4cee2dSHong Zhang /*@
1895cd4cee2dSHong Zhang    TSGetQuadratureTS - Return the sub-TS that evaluates integrals over time
1896cd4cee2dSHong Zhang 
1897cd4cee2dSHong Zhang    Input Parameter:
1898cd4cee2dSHong Zhang .  ts - the TS context obtained from TSCreate()
1899cd4cee2dSHong Zhang 
1900cd4cee2dSHong Zhang    Output Parameters:
1901cd4cee2dSHong Zhang +  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
1902cd4cee2dSHong Zhang -  quadts - the child TS context
1903cd4cee2dSHong Zhang 
1904cd4cee2dSHong Zhang    Level: intermediate
1905cd4cee2dSHong Zhang 
1906db781477SPatrick Sanan .seealso: `TSCreateQuadratureTS()`
1907cd4cee2dSHong Zhang @*/
1908cd4cee2dSHong Zhang PetscErrorCode TSGetQuadratureTS(TS ts,PetscBool *fwd,TS *quadts)
1909cd4cee2dSHong Zhang {
1910cd4cee2dSHong Zhang   PetscFunctionBegin;
1911cd4cee2dSHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1912cd4cee2dSHong Zhang   if (fwd) *fwd = ts->costintegralfwd;
1913cd4cee2dSHong Zhang   if (quadts) *quadts = ts->quadraturets;
1914cd4cee2dSHong Zhang   PetscFunctionReturn(0);
1915cd4cee2dSHong Zhang }
1916ba0675f6SHong Zhang 
1917ba0675f6SHong Zhang /*@
1918ba0675f6SHong Zhang    TSComputeSNESJacobian - Compute the SNESJacobian
1919ba0675f6SHong Zhang 
1920ba0675f6SHong Zhang    Input Parameters:
1921ba0675f6SHong Zhang +  ts - the TS context obtained from TSCreate()
1922ba0675f6SHong Zhang -  x - state vector
1923ba0675f6SHong Zhang 
1924ba0675f6SHong Zhang    Output Parameters:
1925ba0675f6SHong Zhang +  J - Jacobian matrix
1926ba0675f6SHong Zhang -  Jpre - preconditioning matrix for J (may be same as J)
1927ba0675f6SHong Zhang 
1928ba0675f6SHong Zhang    Level: developer
1929ba0675f6SHong Zhang 
1930ba0675f6SHong Zhang    Notes:
1931ba0675f6SHong Zhang    Using SNES to compute the Jacobian enables finite differencing when TS Jacobian is not available.
1932ba0675f6SHong Zhang @*/
1933ba0675f6SHong Zhang PetscErrorCode TSComputeSNESJacobian(TS ts,Vec x,Mat J,Mat Jpre)
1934ba0675f6SHong Zhang {
1935ba0675f6SHong Zhang   SNES           snes = ts->snes;
1936ba0675f6SHong Zhang   PetscErrorCode (*jac)(SNES,Vec,Mat,Mat,void*) = NULL;
1937ba0675f6SHong Zhang 
1938ba0675f6SHong Zhang   PetscFunctionBegin;
1939ba0675f6SHong Zhang   /*
1940ba0675f6SHong Zhang     Unlike implicit methods, explicit methods do not have SNESMatFDColoring in the snes object
1941ba0675f6SHong Zhang     because SNESSolve() has not been called yet; so querying SNESMatFDColoring does not work for
1942ba0675f6SHong Zhang     explicit methods. Instead, we check the Jacobian compute function directly to determin if FD
1943ba0675f6SHong Zhang     coloring is used.
1944ba0675f6SHong Zhang   */
19459566063dSJacob Faibussowitsch   PetscCall(SNESGetJacobian(snes,NULL,NULL,&jac,NULL));
1946ba0675f6SHong Zhang   if (jac == SNESComputeJacobianDefaultColor) {
1947ba0675f6SHong Zhang     Vec f;
19489566063dSJacob Faibussowitsch     PetscCall(SNESSetSolution(snes,x));
19499566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes,&f,NULL,NULL));
1950ba0675f6SHong Zhang     /* Force MatFDColoringApply to evaluate the SNES residual function for the base vector */
19519566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes,x,f));
1952ba0675f6SHong Zhang   }
19539566063dSJacob Faibussowitsch   PetscCall(SNESComputeJacobian(snes,x,J,Jpre));
1954ba0675f6SHong Zhang   PetscFunctionReturn(0);
1955ba0675f6SHong Zhang }
1956