xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision 35cb6cd333087cc89d8d5031932d4f38af02614d)
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 
13c3339decSBarry Smith   Logically Collective
14814e85d6SHong Zhang 
15814e85d6SHong Zhang   Input Parameters:
16bcf0153eSBarry Smith + 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 
30bcf0153eSBarry Smith   Note:
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 
33bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSGetRHSJacobianP()`
34814e85d6SHong Zhang @*/
35d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetRHSJacobianP(TS ts, Mat Amat, PetscErrorCode (*func)(TS, PetscReal, Vec, Mat, void *), void *ctx)
36d71ae5a4SJacob Faibussowitsch {
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 
54c3339decSBarry Smith   Logically Collective
55cd4cee2dSHong Zhang 
56f899ff85SJose E. Roman   Input Parameter:
57bcf0153eSBarry Smith . 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 
73bcf0153eSBarry Smith   Note:
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 
76bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetRHSJacobianP()`, `TS`, `TSGetRHSJacobianP()`
77cd4cee2dSHong Zhang @*/
78d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGetRHSJacobianP(TS ts, Mat *Amat, PetscErrorCode (**func)(TS, PetscReal, Vec, Mat, void *), void **ctx)
79d71ae5a4SJacob Faibussowitsch {
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 
90c3339decSBarry Smith   Collective
91814e85d6SHong Zhang 
92814e85d6SHong Zhang   Input Parameters:
93bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
94814e85d6SHong Zhang 
95814e85d6SHong Zhang   Level: developer
96814e85d6SHong Zhang 
97bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetRHSJacobianP()`, `TS`
98814e85d6SHong Zhang @*/
99d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeRHSJacobianP(TS ts, PetscReal t, Vec U, Mat Amat)
100d71ae5a4SJacob Faibussowitsch {
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 
106792fecdfSBarry Smith   PetscCallBack("TS callback JacobianP for sensitivity analysis", (*ts->rhsjacobianp)(ts, t, U, Amat, ts->rhsjacobianpctx));
107814e85d6SHong Zhang   PetscFunctionReturn(0);
108814e85d6SHong Zhang }
109814e85d6SHong Zhang 
110814e85d6SHong Zhang /*@C
11133f72c5dSHong 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.
11233f72c5dSHong Zhang 
113c3339decSBarry Smith   Logically Collective
11433f72c5dSHong Zhang 
11533f72c5dSHong Zhang   Input Parameters:
116bcf0153eSBarry Smith + ts - `TS` context obtained from `TSCreate()`
11733f72c5dSHong Zhang . Amat - JacobianP matrix
11833f72c5dSHong Zhang . func - function
11933f72c5dSHong Zhang - ctx - [optional] user-defined function context
12033f72c5dSHong Zhang 
12133f72c5dSHong Zhang   Calling sequence of func:
12233f72c5dSHong Zhang $ func (TS ts,PetscReal t,Vec y,Mat A,void *ctx);
12333f72c5dSHong Zhang +   t - current timestep
12433f72c5dSHong Zhang .   U - input vector (current ODE solution)
12533f72c5dSHong Zhang .   Udot - time derivative of state vector
12633f72c5dSHong Zhang .   shift - shift to apply, see note below
12733f72c5dSHong Zhang .   A - output matrix
12833f72c5dSHong Zhang -   ctx - [optional] user-defined function context
12933f72c5dSHong Zhang 
13033f72c5dSHong Zhang   Level: intermediate
13133f72c5dSHong Zhang 
132bcf0153eSBarry Smith   Note:
13333f72c5dSHong 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
13433f72c5dSHong Zhang 
135bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetRHSJacobianP()`, `TS`
13633f72c5dSHong Zhang @*/
137d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetIJacobianP(TS ts, Mat Amat, PetscErrorCode (*func)(TS, PetscReal, Vec, Vec, PetscReal, Mat, void *), void *ctx)
138d71ae5a4SJacob Faibussowitsch {
13933f72c5dSHong Zhang   PetscFunctionBegin;
14033f72c5dSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
14133f72c5dSHong Zhang   PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2);
14233f72c5dSHong Zhang 
14333f72c5dSHong Zhang   ts->ijacobianp    = func;
14433f72c5dSHong Zhang   ts->ijacobianpctx = ctx;
14533f72c5dSHong Zhang   if (Amat) {
1469566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)Amat));
1479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&ts->Jacp));
14833f72c5dSHong Zhang     ts->Jacp = Amat;
14933f72c5dSHong Zhang   }
15033f72c5dSHong Zhang   PetscFunctionReturn(0);
15133f72c5dSHong Zhang }
15233f72c5dSHong Zhang 
15333f72c5dSHong Zhang /*@C
15433f72c5dSHong Zhang   TSComputeIJacobianP - Runs the user-defined IJacobianP function.
15533f72c5dSHong Zhang 
156c3339decSBarry Smith   Collective
15733f72c5dSHong Zhang 
15833f72c5dSHong Zhang   Input Parameters:
159bcf0153eSBarry Smith + ts - the `TS` context
16033f72c5dSHong Zhang . t - current timestep
16133f72c5dSHong Zhang . U - state vector
16233f72c5dSHong Zhang . Udot - time derivative of state vector
16333f72c5dSHong Zhang . shift - shift to apply, see note below
16433f72c5dSHong Zhang - imex - flag indicates if the method is IMEX so that the RHSJacobian should be kept separate
16533f72c5dSHong Zhang 
16633f72c5dSHong Zhang   Output Parameters:
16733f72c5dSHong Zhang . A - Jacobian matrix
16833f72c5dSHong Zhang 
16933f72c5dSHong Zhang   Level: developer
17033f72c5dSHong Zhang 
171bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSSetIJacobianP()`
17233f72c5dSHong Zhang @*/
173d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeIJacobianP(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat Amat, PetscBool imex)
174d71ae5a4SJacob Faibussowitsch {
17533f72c5dSHong Zhang   PetscFunctionBegin;
17633f72c5dSHong Zhang   if (!Amat) PetscFunctionReturn(0);
17733f72c5dSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
17833f72c5dSHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
17933f72c5dSHong Zhang   PetscValidHeaderSpecific(Udot, VEC_CLASSID, 4);
18033f72c5dSHong Zhang 
1819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_JacobianPEval, ts, U, Amat, 0));
18248a46eb9SPierre Jolivet   if (ts->ijacobianp) PetscCallBack("TS callback JacobianP for sensitivity analysis", (*ts->ijacobianp)(ts, t, U, Udot, shift, Amat, ts->ijacobianpctx));
18333f72c5dSHong Zhang   if (imex) {
18433f72c5dSHong Zhang     if (!ts->ijacobianp) { /* system was written as Udot = G(t,U) */
18533f72c5dSHong Zhang       PetscBool assembled;
1869566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(Amat));
1879566063dSJacob Faibussowitsch       PetscCall(MatAssembled(Amat, &assembled));
18833f72c5dSHong Zhang       if (!assembled) {
1899566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(Amat, MAT_FINAL_ASSEMBLY));
1909566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(Amat, MAT_FINAL_ASSEMBLY));
19133f72c5dSHong Zhang       }
19233f72c5dSHong Zhang     }
19333f72c5dSHong Zhang   } else {
1941baa6e33SBarry Smith     if (ts->rhsjacobianp) PetscCall(TSComputeRHSJacobianP(ts, t, U, ts->Jacprhs));
19533f72c5dSHong Zhang     if (ts->Jacprhs == Amat) { /* No IJacobian, so we only have the RHS matrix */
1969566063dSJacob Faibussowitsch       PetscCall(MatScale(Amat, -1));
19733f72c5dSHong Zhang     } else if (ts->Jacprhs) { /* Both IJacobian and RHSJacobian */
19833f72c5dSHong Zhang       MatStructure axpy = DIFFERENT_NONZERO_PATTERN;
19933f72c5dSHong Zhang       if (!ts->ijacobianp) { /* No IJacobianp provided, but we have a separate RHS matrix */
2009566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(Amat));
20133f72c5dSHong Zhang       }
2029566063dSJacob Faibussowitsch       PetscCall(MatAXPY(Amat, -1, ts->Jacprhs, axpy));
20333f72c5dSHong Zhang     }
20433f72c5dSHong Zhang   }
2059566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_JacobianPEval, ts, U, Amat, 0));
20633f72c5dSHong Zhang   PetscFunctionReturn(0);
20733f72c5dSHong Zhang }
20833f72c5dSHong Zhang 
20933f72c5dSHong Zhang /*@C
210814e85d6SHong Zhang     TSSetCostIntegrand - Sets the routine for evaluating the integral term in one or more cost functions
211814e85d6SHong Zhang 
212c3339decSBarry Smith     Logically Collective
213814e85d6SHong Zhang 
214814e85d6SHong Zhang     Input Parameters:
215bcf0153eSBarry Smith +   ts - the `TS` context obtained from `TSCreate()`
216814e85d6SHong Zhang .   numcost - number of gradients to be computed, this is the number of cost functions
217814e85d6SHong Zhang .   costintegral - vector that stores the integral values
218814e85d6SHong Zhang .   rf - routine for evaluating the integrand function
219c9ad9de0SHong Zhang .   drduf - function that computes the gradients of the r's with respect to u
220814e85d6SHong 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)
221814e85d6SHong Zhang .   fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
222814e85d6SHong Zhang -   ctx - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
223814e85d6SHong Zhang 
224814e85d6SHong Zhang     Calling sequence of rf:
225c9ad9de0SHong Zhang $   PetscErrorCode rf(TS ts,PetscReal t,Vec U,Vec F,void *ctx);
226814e85d6SHong Zhang 
227c9ad9de0SHong Zhang     Calling sequence of drduf:
228c9ad9de0SHong Zhang $   PetscErroCode drduf(TS ts,PetscReal t,Vec U,Vec *dRdU,void *ctx);
229814e85d6SHong Zhang 
230814e85d6SHong Zhang     Calling sequence of drdpf:
231c9ad9de0SHong Zhang $   PetscErroCode drdpf(TS ts,PetscReal t,Vec U,Vec *dRdP,void *ctx);
232814e85d6SHong Zhang 
233cd4cee2dSHong Zhang     Level: deprecated
234814e85d6SHong Zhang 
235bcf0153eSBarry Smith     Note:
236814e85d6SHong Zhang     For optimization there is usually a single cost function (numcost = 1). For sensitivities there may be multiple cost functions
237814e85d6SHong Zhang 
238bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSSetRHSJacobianP()`, `TSGetCostGradients()`, `TSSetCostGradients()`
239814e85d6SHong Zhang @*/
240d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetCostIntegrand(TS ts, PetscInt numcost, Vec costintegral, PetscErrorCode (*rf)(TS, PetscReal, Vec, Vec, void *), PetscErrorCode (*drduf)(TS, PetscReal, Vec, Vec *, void *), PetscErrorCode (*drdpf)(TS, PetscReal, Vec, Vec *, void *), PetscBool fwd, void *ctx)
241d71ae5a4SJacob Faibussowitsch {
242814e85d6SHong Zhang   PetscFunctionBegin;
243814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
244814e85d6SHong Zhang   if (costintegral) PetscValidHeaderSpecific(costintegral, VEC_CLASSID, 3);
2453c633725SBarry 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()");
246814e85d6SHong Zhang   if (!ts->numcost) ts->numcost = numcost;
247814e85d6SHong Zhang 
248814e85d6SHong Zhang   if (costintegral) {
2499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)costintegral));
2509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ts->vec_costintegral));
251814e85d6SHong Zhang     ts->vec_costintegral = costintegral;
252814e85d6SHong Zhang   } else {
253814e85d6SHong Zhang     if (!ts->vec_costintegral) { /* Create a seq vec if user does not provide one */
2549566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, numcost, &ts->vec_costintegral));
255814e85d6SHong Zhang     } else {
2569566063dSJacob Faibussowitsch       PetscCall(VecSet(ts->vec_costintegral, 0.0));
257814e85d6SHong Zhang     }
258814e85d6SHong Zhang   }
259814e85d6SHong Zhang   if (!ts->vec_costintegrand) {
2609566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ts->vec_costintegral, &ts->vec_costintegrand));
261814e85d6SHong Zhang   } else {
2629566063dSJacob Faibussowitsch     PetscCall(VecSet(ts->vec_costintegrand, 0.0));
263814e85d6SHong Zhang   }
264814e85d6SHong Zhang   ts->costintegralfwd  = fwd; /* Evaluate the cost integral in forward run if fwd is true */
265814e85d6SHong Zhang   ts->costintegrand    = rf;
266814e85d6SHong Zhang   ts->costintegrandctx = ctx;
267c9ad9de0SHong Zhang   ts->drdufunction     = drduf;
268814e85d6SHong Zhang   ts->drdpfunction     = drdpf;
269814e85d6SHong Zhang   PetscFunctionReturn(0);
270814e85d6SHong Zhang }
271814e85d6SHong Zhang 
272b5b4017aSHong Zhang /*@C
273814e85d6SHong Zhang    TSGetCostIntegral - Returns the values of the integral term in the cost functions.
274814e85d6SHong Zhang    It is valid to call the routine after a backward run.
275814e85d6SHong Zhang 
276814e85d6SHong Zhang    Not Collective
277814e85d6SHong Zhang 
278814e85d6SHong Zhang    Input Parameter:
279bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
280814e85d6SHong Zhang 
281814e85d6SHong Zhang    Output Parameter:
282814e85d6SHong Zhang .  v - the vector containing the integrals for each cost function
283814e85d6SHong Zhang 
284814e85d6SHong Zhang    Level: intermediate
285814e85d6SHong Zhang 
286bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, ``TSSetCostIntegrand()`
287814e85d6SHong Zhang @*/
288d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGetCostIntegral(TS ts, Vec *v)
289d71ae5a4SJacob Faibussowitsch {
290cd4cee2dSHong Zhang   TS quadts;
291cd4cee2dSHong Zhang 
292814e85d6SHong Zhang   PetscFunctionBegin;
293814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
294814e85d6SHong Zhang   PetscValidPointer(v, 2);
2959566063dSJacob Faibussowitsch   PetscCall(TSGetQuadratureTS(ts, NULL, &quadts));
296cd4cee2dSHong Zhang   *v = quadts->vec_sol;
297814e85d6SHong Zhang   PetscFunctionReturn(0);
298814e85d6SHong Zhang }
299814e85d6SHong Zhang 
300b5b4017aSHong Zhang /*@C
301814e85d6SHong Zhang    TSComputeCostIntegrand - Evaluates the integral function in the cost functions.
302814e85d6SHong Zhang 
303814e85d6SHong Zhang    Input Parameters:
304bcf0153eSBarry Smith +  ts - the `TS` context
305814e85d6SHong Zhang .  t - current time
306c9ad9de0SHong Zhang -  U - state vector, i.e. current solution
307814e85d6SHong Zhang 
308814e85d6SHong Zhang    Output Parameter:
309c9ad9de0SHong Zhang .  Q - vector of size numcost to hold the outputs
310814e85d6SHong Zhang 
311bcf0153eSBarry Smith    Level: deprecated
312bcf0153eSBarry Smith 
313bcf0153eSBarry Smith    Note:
314814e85d6SHong Zhang    Most users should not need to explicitly call this routine, as it
315814e85d6SHong Zhang    is used internally within the sensitivity analysis context.
316814e85d6SHong Zhang 
317bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, `TSSetCostIntegrand()`
318814e85d6SHong Zhang @*/
319d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeCostIntegrand(TS ts, PetscReal t, Vec U, Vec Q)
320d71ae5a4SJacob Faibussowitsch {
321814e85d6SHong Zhang   PetscFunctionBegin;
322814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
323c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
324c9ad9de0SHong Zhang   PetscValidHeaderSpecific(Q, VEC_CLASSID, 4);
325814e85d6SHong Zhang 
3269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_FunctionEval, ts, U, Q, 0));
327792fecdfSBarry Smith   if (ts->costintegrand) PetscCallBack("TS callback integrand in the cost function", (*ts->costintegrand)(ts, t, U, Q, ts->costintegrandctx));
328ef1023bdSBarry Smith   else PetscCall(VecZeroEntries(Q));
3299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_FunctionEval, ts, U, Q, 0));
330814e85d6SHong Zhang   PetscFunctionReturn(0);
331814e85d6SHong Zhang }
332814e85d6SHong Zhang 
333b5b4017aSHong Zhang /*@C
334bcf0153eSBarry Smith   TSComputeDRDUFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobian()`
335814e85d6SHong Zhang 
336d76be551SHong Zhang   Level: deprecated
337814e85d6SHong Zhang 
338814e85d6SHong Zhang @*/
339d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeDRDUFunction(TS ts, PetscReal t, Vec U, Vec *DRDU)
340d71ae5a4SJacob Faibussowitsch {
341814e85d6SHong Zhang   PetscFunctionBegin;
34233f72c5dSHong Zhang   if (!DRDU) PetscFunctionReturn(0);
343814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
344c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
345814e85d6SHong Zhang 
346792fecdfSBarry Smith   PetscCallBack("TS callback DRDU for sensitivity analysis", (*ts->drdufunction)(ts, t, U, DRDU, ts->costintegrandctx));
347814e85d6SHong Zhang   PetscFunctionReturn(0);
348814e85d6SHong Zhang }
349814e85d6SHong Zhang 
350b5b4017aSHong Zhang /*@C
351bcf0153eSBarry Smith   TSComputeDRDPFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobianP()`
352814e85d6SHong Zhang 
353d76be551SHong Zhang   Level: deprecated
354814e85d6SHong Zhang 
355814e85d6SHong Zhang @*/
356d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeDRDPFunction(TS ts, PetscReal t, Vec U, Vec *DRDP)
357d71ae5a4SJacob Faibussowitsch {
358814e85d6SHong Zhang   PetscFunctionBegin;
35933f72c5dSHong Zhang   if (!DRDP) PetscFunctionReturn(0);
360814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
361c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
362814e85d6SHong Zhang 
363792fecdfSBarry Smith   PetscCallBack("TS callback DRDP for sensitivity analysis", (*ts->drdpfunction)(ts, t, U, DRDP, ts->costintegrandctx));
364814e85d6SHong Zhang   PetscFunctionReturn(0);
365814e85d6SHong Zhang }
366814e85d6SHong Zhang 
367b5b4017aSHong Zhang /*@C
368b5b4017aSHong 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.
369b5b4017aSHong Zhang 
370c3339decSBarry Smith   Logically Collective
371b5b4017aSHong Zhang 
372b5b4017aSHong Zhang   Input Parameters:
373bcf0153eSBarry Smith + ts - `TS` context obtained from `TSCreate()`
374b5b4017aSHong Zhang . ihp1 - an array of vectors storing the result of vector-Hessian-vector product for F_UU
375b5b4017aSHong Zhang . hessianproductfunc1 - vector-Hessian-vector product function for F_UU
376b5b4017aSHong Zhang . ihp2 - an array of vectors storing the result of vector-Hessian-vector product for F_UP
377b5b4017aSHong Zhang . hessianproductfunc2 - vector-Hessian-vector product function for F_UP
378b5b4017aSHong Zhang . ihp3 - an array of vectors storing the result of vector-Hessian-vector product for F_PU
379b5b4017aSHong Zhang . hessianproductfunc3 - vector-Hessian-vector product function for F_PU
380b5b4017aSHong Zhang . ihp4 - an array of vectors storing the result of vector-Hessian-vector product for F_PP
381f0fc11ceSJed Brown - hessianproductfunc4 - vector-Hessian-vector product function for F_PP
382b5b4017aSHong Zhang 
383b5b4017aSHong Zhang   Calling sequence of ihessianproductfunc:
384369cf35fSHong Zhang $ ihessianproductfunc (TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx);
385b5b4017aSHong Zhang +   t - current timestep
386b5b4017aSHong Zhang .   U - input vector (current ODE solution)
387369cf35fSHong Zhang .   Vl - an array of input vectors to be left-multiplied with the Hessian
388b5b4017aSHong Zhang .   Vr - input vector to be right-multiplied with the Hessian
389369cf35fSHong Zhang .   VHV - an array of output vectors for vector-Hessian-vector product
390b5b4017aSHong Zhang -   ctx - [optional] user-defined function context
391b5b4017aSHong Zhang 
392b5b4017aSHong Zhang   Level: intermediate
393b5b4017aSHong Zhang 
394369cf35fSHong Zhang   Notes:
395369cf35fSHong Zhang   The first Hessian function and the working array are required.
396369cf35fSHong Zhang   As an example to implement the callback functions, the second callback function calculates the vector-Hessian-vector product
397369cf35fSHong Zhang   $ Vl_n^T*F_UP*Vr
398369cf35fSHong 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.
399369cf35fSHong Zhang   Each entry of F_UP corresponds to the derivative
400369cf35fSHong Zhang   $ F_UP[i][j][k] = \frac{\partial^2 F[i]}{\partial U[j] \partial P[k]}.
401369cf35fSHong 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
402369cf35fSHong Zhang   $ VHV_n[j] = \sum_i \sum_k {Vl_n[i] * F_UP[i][j][k] * Vr[k]}
403369cf35fSHong Zhang   If the cost function is a scalar, there will be only one vector in Vl and VHV.
404b5b4017aSHong Zhang 
405bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`
406b5b4017aSHong Zhang @*/
407d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetIHessianProduct(TS ts, Vec *ihp1, PetscErrorCode (*ihessianproductfunc1)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *ihp2, PetscErrorCode (*ihessianproductfunc2)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *ihp3, PetscErrorCode (*ihessianproductfunc3)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *ihp4, PetscErrorCode (*ihessianproductfunc4)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), void *ctx)
408d71ae5a4SJacob Faibussowitsch {
409b5b4017aSHong Zhang   PetscFunctionBegin;
410b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
411b5b4017aSHong Zhang   PetscValidPointer(ihp1, 2);
412b5b4017aSHong Zhang 
413b5b4017aSHong Zhang   ts->ihessianproductctx = ctx;
414b5b4017aSHong Zhang   if (ihp1) ts->vecs_fuu = ihp1;
415b5b4017aSHong Zhang   if (ihp2) ts->vecs_fup = ihp2;
416b5b4017aSHong Zhang   if (ihp3) ts->vecs_fpu = ihp3;
417b5b4017aSHong Zhang   if (ihp4) ts->vecs_fpp = ihp4;
418b5b4017aSHong Zhang   ts->ihessianproduct_fuu = ihessianproductfunc1;
419b5b4017aSHong Zhang   ts->ihessianproduct_fup = ihessianproductfunc2;
420b5b4017aSHong Zhang   ts->ihessianproduct_fpu = ihessianproductfunc3;
421b5b4017aSHong Zhang   ts->ihessianproduct_fpp = ihessianproductfunc4;
422b5b4017aSHong Zhang   PetscFunctionReturn(0);
423b5b4017aSHong Zhang }
424b5b4017aSHong Zhang 
425b5b4017aSHong Zhang /*@C
426b1e111ebSHong Zhang   TSComputeIHessianProductFunctionUU - Runs the user-defined vector-Hessian-vector product function for Fuu.
427b5b4017aSHong Zhang 
428c3339decSBarry Smith   Collective
429b5b4017aSHong Zhang 
430b5b4017aSHong Zhang   Input Parameters:
431bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
432b5b4017aSHong Zhang 
433b5b4017aSHong Zhang   Level: developer
434b5b4017aSHong Zhang 
435bcf0153eSBarry Smith   Note:
436bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionUU()` is typically used for sensitivity implementation,
437bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
438bcf0153eSBarry Smith 
439bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetIHessianProduct()`
440b5b4017aSHong Zhang @*/
441d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeIHessianProductFunctionUU(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
442d71ae5a4SJacob Faibussowitsch {
443b5b4017aSHong Zhang   PetscFunctionBegin;
44433f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
445b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
446b5b4017aSHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
447b5b4017aSHong Zhang 
448792fecdfSBarry Smith   if (ts->ihessianproduct_fuu) PetscCallBack("TS callback IHessianProduct 1 for sensitivity analysis", (*ts->ihessianproduct_fuu)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx));
449ef1023bdSBarry Smith 
45067633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
45167633408SHong Zhang   if (ts->rhshessianproduct_guu) {
45267633408SHong Zhang     PetscInt nadj;
4539566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionUU(ts, t, U, Vl, Vr, VHV));
45448a46eb9SPierre Jolivet     for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1));
45567633408SHong Zhang   }
456b5b4017aSHong Zhang   PetscFunctionReturn(0);
457b5b4017aSHong Zhang }
458b5b4017aSHong Zhang 
459b5b4017aSHong Zhang /*@C
460b1e111ebSHong Zhang   TSComputeIHessianProductFunctionUP - Runs the user-defined vector-Hessian-vector product function for Fup.
461b5b4017aSHong Zhang 
462c3339decSBarry Smith   Collective
463b5b4017aSHong Zhang 
464b5b4017aSHong Zhang   Input Parameters:
465bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
466b5b4017aSHong Zhang 
467b5b4017aSHong Zhang   Level: developer
468b5b4017aSHong Zhang 
469bcf0153eSBarry Smith   Note:
470bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionUP()` is typically used for sensitivity implementation,
471bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
472bcf0153eSBarry Smith 
473bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetIHessianProduct()`
474b5b4017aSHong Zhang @*/
475d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeIHessianProductFunctionUP(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
476d71ae5a4SJacob Faibussowitsch {
477b5b4017aSHong Zhang   PetscFunctionBegin;
47833f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
479b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
480b5b4017aSHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
481b5b4017aSHong Zhang 
482792fecdfSBarry Smith   if (ts->ihessianproduct_fup) PetscCallBack("TS callback IHessianProduct 2 for sensitivity analysis", (*ts->ihessianproduct_fup)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx));
483ef1023bdSBarry Smith 
48467633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
48567633408SHong Zhang   if (ts->rhshessianproduct_gup) {
48667633408SHong Zhang     PetscInt nadj;
4879566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionUP(ts, t, U, Vl, Vr, VHV));
48848a46eb9SPierre Jolivet     for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1));
48967633408SHong Zhang   }
490b5b4017aSHong Zhang   PetscFunctionReturn(0);
491b5b4017aSHong Zhang }
492b5b4017aSHong Zhang 
493b5b4017aSHong Zhang /*@C
494b1e111ebSHong Zhang   TSComputeIHessianProductFunctionPU - Runs the user-defined vector-Hessian-vector product function for Fpu.
495b5b4017aSHong Zhang 
496c3339decSBarry Smith   Collective
497b5b4017aSHong Zhang 
498b5b4017aSHong Zhang   Input Parameters:
499bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
500b5b4017aSHong Zhang 
501b5b4017aSHong Zhang   Level: developer
502b5b4017aSHong Zhang 
503bcf0153eSBarry Smith   Note:
504bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionPU()` is typically used for sensitivity implementation,
505bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
506bcf0153eSBarry Smith 
507bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetIHessianProduct()`
508b5b4017aSHong Zhang @*/
509d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeIHessianProductFunctionPU(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
510d71ae5a4SJacob Faibussowitsch {
511b5b4017aSHong Zhang   PetscFunctionBegin;
51233f72c5dSHong Zhang   if (!VHV) PetscFunctionReturn(0);
513b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
514b5b4017aSHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
515b5b4017aSHong Zhang 
516792fecdfSBarry Smith   if (ts->ihessianproduct_fpu) PetscCallBack("TS callback IHessianProduct 3 for sensitivity analysis", (*ts->ihessianproduct_fpu)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx));
517ef1023bdSBarry Smith 
51867633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
51967633408SHong Zhang   if (ts->rhshessianproduct_gpu) {
52067633408SHong Zhang     PetscInt nadj;
5219566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionPU(ts, t, U, Vl, Vr, VHV));
52248a46eb9SPierre Jolivet     for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1));
52367633408SHong Zhang   }
524b5b4017aSHong Zhang   PetscFunctionReturn(0);
525b5b4017aSHong Zhang }
526b5b4017aSHong Zhang 
527b5b4017aSHong Zhang /*@C
528b1e111ebSHong Zhang   TSComputeIHessianProductFunctionPP - Runs the user-defined vector-Hessian-vector product function for Fpp.
529b5b4017aSHong Zhang 
530c3339decSBarry Smith   Collective
531b5b4017aSHong Zhang 
532b5b4017aSHong Zhang   Input Parameters:
533bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
534b5b4017aSHong Zhang 
535b5b4017aSHong Zhang   Level: developer
536b5b4017aSHong Zhang 
537bcf0153eSBarry Smith   Note:
538bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionPP()` is typically used for sensitivity implementation,
539bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
540bcf0153eSBarry Smith 
541bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetIHessianProduct()`
542b5b4017aSHong Zhang @*/
543d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeIHessianProductFunctionPP(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
544d71ae5a4SJacob Faibussowitsch {
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 
550792fecdfSBarry Smith   if (ts->ihessianproduct_fpp) PetscCallBack("TS callback IHessianProduct 3 for sensitivity analysis", (*ts->ihessianproduct_fpp)(ts, t, U, Vl, Vr, VHV, ts->ihessianproductctx));
551ef1023bdSBarry Smith 
55267633408SHong Zhang   /* does not consider IMEX for now, so either IHessian or RHSHessian will be calculated, using the same output VHV */
55367633408SHong Zhang   if (ts->rhshessianproduct_gpp) {
55467633408SHong Zhang     PetscInt nadj;
5559566063dSJacob Faibussowitsch     PetscCall(TSComputeRHSHessianProductFunctionPP(ts, t, U, Vl, Vr, VHV));
55648a46eb9SPierre Jolivet     for (nadj = 0; nadj < ts->numcost; nadj++) PetscCall(VecScale(VHV[nadj], -1));
55767633408SHong Zhang   }
558b5b4017aSHong Zhang   PetscFunctionReturn(0);
559b5b4017aSHong Zhang }
560b5b4017aSHong Zhang 
56113af1a74SHong Zhang /*@C
5624c500f23SPierre 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.
56313af1a74SHong Zhang 
564c3339decSBarry Smith   Logically Collective
56513af1a74SHong Zhang 
56613af1a74SHong Zhang   Input Parameters:
567bcf0153eSBarry Smith + ts - `TS` context obtained from `TSCreate()`
56813af1a74SHong Zhang . rhshp1 - an array of vectors storing the result of vector-Hessian-vector product for G_UU
56913af1a74SHong Zhang . hessianproductfunc1 - vector-Hessian-vector product function for G_UU
57013af1a74SHong Zhang . rhshp2 - an array of vectors storing the result of vector-Hessian-vector product for G_UP
57113af1a74SHong Zhang . hessianproductfunc2 - vector-Hessian-vector product function for G_UP
57213af1a74SHong Zhang . rhshp3 - an array of vectors storing the result of vector-Hessian-vector product for G_PU
57313af1a74SHong Zhang . hessianproductfunc3 - vector-Hessian-vector product function for G_PU
57413af1a74SHong Zhang . rhshp4 - an array of vectors storing the result of vector-Hessian-vector product for G_PP
575f0fc11ceSJed Brown - hessianproductfunc4 - vector-Hessian-vector product function for G_PP
57613af1a74SHong Zhang 
57713af1a74SHong Zhang   Calling sequence of ihessianproductfunc:
578369cf35fSHong Zhang $ rhshessianproductfunc (TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx);
57913af1a74SHong Zhang +   t - current timestep
58013af1a74SHong Zhang .   U - input vector (current ODE solution)
581369cf35fSHong Zhang .   Vl - an array of input vectors to be left-multiplied with the Hessian
58213af1a74SHong Zhang .   Vr - input vector to be right-multiplied with the Hessian
583369cf35fSHong Zhang .   VHV - an array of output vectors for vector-Hessian-vector product
58413af1a74SHong Zhang -   ctx - [optional] user-defined function context
58513af1a74SHong Zhang 
58613af1a74SHong Zhang   Level: intermediate
58713af1a74SHong Zhang 
588369cf35fSHong Zhang   Notes:
589369cf35fSHong Zhang   The first Hessian function and the working array are required.
590369cf35fSHong Zhang   As an example to implement the callback functions, the second callback function calculates the vector-Hessian-vector product
591369cf35fSHong Zhang   $ Vl_n^T*G_UP*Vr
592369cf35fSHong 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.
593369cf35fSHong Zhang   Each entry of G_UP corresponds to the derivative
594369cf35fSHong Zhang   $ G_UP[i][j][k] = \frac{\partial^2 G[i]}{\partial U[j] \partial P[k]}.
595369cf35fSHong 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
596369cf35fSHong Zhang   $ VHV_n[j] = \sum_i \sum_k {Vl_n[i] * G_UP[i][j][k] * Vr[k]}
597369cf35fSHong Zhang   If the cost function is a scalar, there will be only one vector in Vl and VHV.
59813af1a74SHong Zhang 
599bcf0153eSBarry Smith .seealso: `TS`
60013af1a74SHong Zhang @*/
601d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetRHSHessianProduct(TS ts, Vec *rhshp1, PetscErrorCode (*rhshessianproductfunc1)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *rhshp2, PetscErrorCode (*rhshessianproductfunc2)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *rhshp3, PetscErrorCode (*rhshessianproductfunc3)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), Vec *rhshp4, PetscErrorCode (*rhshessianproductfunc4)(TS, PetscReal, Vec, Vec *, Vec, Vec *, void *), void *ctx)
602d71ae5a4SJacob Faibussowitsch {
60313af1a74SHong Zhang   PetscFunctionBegin;
60413af1a74SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
60513af1a74SHong Zhang   PetscValidPointer(rhshp1, 2);
60613af1a74SHong Zhang 
60713af1a74SHong Zhang   ts->rhshessianproductctx = ctx;
60813af1a74SHong Zhang   if (rhshp1) ts->vecs_guu = rhshp1;
60913af1a74SHong Zhang   if (rhshp2) ts->vecs_gup = rhshp2;
61013af1a74SHong Zhang   if (rhshp3) ts->vecs_gpu = rhshp3;
61113af1a74SHong Zhang   if (rhshp4) ts->vecs_gpp = rhshp4;
61213af1a74SHong Zhang   ts->rhshessianproduct_guu = rhshessianproductfunc1;
61313af1a74SHong Zhang   ts->rhshessianproduct_gup = rhshessianproductfunc2;
61413af1a74SHong Zhang   ts->rhshessianproduct_gpu = rhshessianproductfunc3;
61513af1a74SHong Zhang   ts->rhshessianproduct_gpp = rhshessianproductfunc4;
61613af1a74SHong Zhang   PetscFunctionReturn(0);
61713af1a74SHong Zhang }
61813af1a74SHong Zhang 
61913af1a74SHong Zhang /*@C
620b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionUU - Runs the user-defined vector-Hessian-vector product function for Guu.
62113af1a74SHong Zhang 
622c3339decSBarry Smith   Collective
62313af1a74SHong Zhang 
62413af1a74SHong Zhang   Input Parameters:
625bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
62613af1a74SHong Zhang 
62713af1a74SHong Zhang   Level: developer
62813af1a74SHong Zhang 
629bcf0153eSBarry Smith   Note:
630bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionUU()` is typically used for sensitivity implementation,
631bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
632bcf0153eSBarry Smith 
633bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSSetRHSHessianProduct()`
63413af1a74SHong Zhang @*/
635d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeRHSHessianProductFunctionUU(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
636d71ae5a4SJacob Faibussowitsch {
63713af1a74SHong Zhang   PetscFunctionBegin;
63813af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
63913af1a74SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
64013af1a74SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
64113af1a74SHong Zhang 
642792fecdfSBarry Smith   PetscCallBack("TS callback RHSHessianProduct 1 for sensitivity analysis", (*ts->rhshessianproduct_guu)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx));
64313af1a74SHong Zhang   PetscFunctionReturn(0);
64413af1a74SHong Zhang }
64513af1a74SHong Zhang 
64613af1a74SHong Zhang /*@C
647b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionUP - Runs the user-defined vector-Hessian-vector product function for Gup.
64813af1a74SHong Zhang 
649c3339decSBarry Smith   Collective
65013af1a74SHong Zhang 
65113af1a74SHong Zhang   Input Parameters:
652bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
65313af1a74SHong Zhang 
65413af1a74SHong Zhang   Level: developer
65513af1a74SHong Zhang 
656bcf0153eSBarry Smith   Note:
657bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionUP()` is typically used for sensitivity implementation,
658bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
659bcf0153eSBarry Smith 
660bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSSetRHSHessianProduct()`
66113af1a74SHong Zhang @*/
662d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeRHSHessianProductFunctionUP(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
663d71ae5a4SJacob Faibussowitsch {
66413af1a74SHong Zhang   PetscFunctionBegin;
66513af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
66613af1a74SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
66713af1a74SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
66813af1a74SHong Zhang 
669792fecdfSBarry Smith   PetscCallBack("TS callback RHSHessianProduct 2 for sensitivity analysis", (*ts->rhshessianproduct_gup)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx));
67013af1a74SHong Zhang   PetscFunctionReturn(0);
67113af1a74SHong Zhang }
67213af1a74SHong Zhang 
67313af1a74SHong Zhang /*@C
674b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionPU - Runs the user-defined vector-Hessian-vector product function for Gpu.
67513af1a74SHong Zhang 
676c3339decSBarry Smith   Collective
67713af1a74SHong Zhang 
67813af1a74SHong Zhang   Input Parameters:
679bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
68013af1a74SHong Zhang 
68113af1a74SHong Zhang   Level: developer
68213af1a74SHong Zhang 
683bcf0153eSBarry Smith   Note:
684bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionPU()` is typically used for sensitivity implementation,
685bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
686bcf0153eSBarry Smith 
687bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetRHSHessianProduct()`
68813af1a74SHong Zhang @*/
689d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeRHSHessianProductFunctionPU(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
690d71ae5a4SJacob Faibussowitsch {
69113af1a74SHong Zhang   PetscFunctionBegin;
69213af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
69313af1a74SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
69413af1a74SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
69513af1a74SHong Zhang 
696792fecdfSBarry Smith   PetscCallBack("TS callback RHSHessianProduct 3 for sensitivity analysis", (*ts->rhshessianproduct_gpu)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx));
69713af1a74SHong Zhang   PetscFunctionReturn(0);
69813af1a74SHong Zhang }
69913af1a74SHong Zhang 
70013af1a74SHong Zhang /*@C
701b1e111ebSHong Zhang   TSComputeRHSHessianProductFunctionPP - Runs the user-defined vector-Hessian-vector product function for Gpp.
70213af1a74SHong Zhang 
703c3339decSBarry Smith   Collective
70413af1a74SHong Zhang 
70513af1a74SHong Zhang   Input Parameters:
706bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
70713af1a74SHong Zhang 
70813af1a74SHong Zhang   Level: developer
70913af1a74SHong Zhang 
710bcf0153eSBarry Smith   Note:
711bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionPP()` is typically used for sensitivity implementation,
712bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
713bcf0153eSBarry Smith 
714bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetRHSHessianProduct()`
71513af1a74SHong Zhang @*/
716d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeRHSHessianProductFunctionPP(TS ts, PetscReal t, Vec U, Vec *Vl, Vec Vr, Vec *VHV)
717d71ae5a4SJacob Faibussowitsch {
71813af1a74SHong Zhang   PetscFunctionBegin;
71913af1a74SHong Zhang   if (!VHV) PetscFunctionReturn(0);
72013af1a74SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
72113af1a74SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
72213af1a74SHong Zhang 
723792fecdfSBarry Smith   PetscCallBack("TS callback RHSHessianProduct 3 for sensitivity analysis", (*ts->rhshessianproduct_gpp)(ts, t, U, Vl, Vr, VHV, ts->rhshessianproductctx));
72413af1a74SHong Zhang   PetscFunctionReturn(0);
72513af1a74SHong Zhang }
72613af1a74SHong Zhang 
727814e85d6SHong Zhang /* --------------------------- Adjoint sensitivity ---------------------------*/
728814e85d6SHong Zhang 
729814e85d6SHong Zhang /*@
730814e85d6SHong 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
731bcf0153eSBarry Smith       for use by the `TS` adjoint routines.
732814e85d6SHong Zhang 
733c3339decSBarry Smith    Logically Collective
734814e85d6SHong Zhang 
735814e85d6SHong Zhang    Input Parameters:
736bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
737d2fd7bfcSHong Zhang .  numcost - number of gradients to be computed, this is the number of cost functions
738814e85d6SHong 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
739814e85d6SHong Zhang -  mu - gradients with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
740814e85d6SHong Zhang 
741814e85d6SHong Zhang    Level: beginner
742814e85d6SHong Zhang 
743814e85d6SHong Zhang    Notes:
744*35cb6cd3SPierre Jolivet     the entries in these vectors must be correctly initialized with the values lambda_i = df/dy|finaltime  mu_i = df/dp|finaltime
745814e85d6SHong Zhang 
746*35cb6cd3SPierre Jolivet    After `TSAdjointSolve()` is called the lambda and the mu contain the computed sensitivities
747814e85d6SHong Zhang 
748bcf0153eSBarry Smith .seealso: `TS`, `TSAdjointSolve()`, `TSGetCostGradients()`
749814e85d6SHong Zhang @*/
750d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetCostGradients(TS ts, PetscInt numcost, Vec *lambda, Vec *mu)
751d71ae5a4SJacob Faibussowitsch {
752814e85d6SHong Zhang   PetscFunctionBegin;
753814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
754064a246eSJacob Faibussowitsch   PetscValidPointer(lambda, 3);
755814e85d6SHong Zhang   ts->vecs_sensi  = lambda;
756814e85d6SHong Zhang   ts->vecs_sensip = mu;
7573c633725SBarry 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");
758814e85d6SHong Zhang   ts->numcost = numcost;
759814e85d6SHong Zhang   PetscFunctionReturn(0);
760814e85d6SHong Zhang }
761814e85d6SHong Zhang 
762814e85d6SHong Zhang /*@
763bcf0153eSBarry Smith    TSGetCostGradients - Returns the gradients from the `TSAdjointSolve()`
764814e85d6SHong Zhang 
765bcf0153eSBarry Smith    Not Collective, but the vectors returned are parallel if `TS` is parallel
766814e85d6SHong Zhang 
767814e85d6SHong Zhang    Input Parameter:
768bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
769814e85d6SHong Zhang 
770d8d19677SJose E. Roman    Output Parameters:
7716b867d5aSJose E. Roman +  numcost - size of returned arrays
7726b867d5aSJose E. Roman .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
773814e85d6SHong Zhang -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
774814e85d6SHong Zhang 
775814e85d6SHong Zhang    Level: intermediate
776814e85d6SHong Zhang 
777bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, `TSSetCostGradients()`
778814e85d6SHong Zhang @*/
779d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGetCostGradients(TS ts, PetscInt *numcost, Vec **lambda, Vec **mu)
780d71ae5a4SJacob Faibussowitsch {
781814e85d6SHong Zhang   PetscFunctionBegin;
782814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
783814e85d6SHong Zhang   if (numcost) *numcost = ts->numcost;
784814e85d6SHong Zhang   if (lambda) *lambda = ts->vecs_sensi;
785814e85d6SHong Zhang   if (mu) *mu = ts->vecs_sensip;
786814e85d6SHong Zhang   PetscFunctionReturn(0);
787814e85d6SHong Zhang }
788814e85d6SHong Zhang 
789814e85d6SHong Zhang /*@
790b5b4017aSHong 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
791bcf0153eSBarry Smith    for use by the `TS` adjoint routines.
792b5b4017aSHong Zhang 
793c3339decSBarry Smith    Logically Collective
794b5b4017aSHong Zhang 
795b5b4017aSHong Zhang    Input Parameters:
796bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
797b5b4017aSHong Zhang .  numcost - number of cost functions
798b5b4017aSHong 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
799b5b4017aSHong 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
800b5b4017aSHong Zhang -  dir - the direction vector that are multiplied with the Hessian of the cost functions
801b5b4017aSHong Zhang 
802b5b4017aSHong Zhang    Level: beginner
803b5b4017aSHong Zhang 
804bcf0153eSBarry Smith    Notes:
805bcf0153eSBarry Smith    Hessian of the cost function is completely different from Hessian of the ODE/DAE system
806b5b4017aSHong Zhang 
807bcf0153eSBarry Smith    For second-order adjoint, one needs to call this function and then `TSAdjointSetForward()` before `TSSolve()`.
808b5b4017aSHong Zhang 
809*35cb6cd3SPierre Jolivet    After `TSAdjointSolve()` is called, the lambda2 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.
810b5b4017aSHong Zhang 
8113fca9621SHong Zhang    Passing NULL for lambda2 disables the second-order calculation.
812bcf0153eSBarry Smith 
813bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, `TSAdjointSetForward()`
814b5b4017aSHong Zhang @*/
815d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetCostHessianProducts(TS ts, PetscInt numcost, Vec *lambda2, Vec *mu2, Vec dir)
816d71ae5a4SJacob Faibussowitsch {
817b5b4017aSHong Zhang   PetscFunctionBegin;
818b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
8193c633725SBarry 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");
820b5b4017aSHong Zhang   ts->numcost      = numcost;
821b5b4017aSHong Zhang   ts->vecs_sensi2  = lambda2;
82233f72c5dSHong Zhang   ts->vecs_sensi2p = mu2;
823b5b4017aSHong Zhang   ts->vec_dir      = dir;
824b5b4017aSHong Zhang   PetscFunctionReturn(0);
825b5b4017aSHong Zhang }
826b5b4017aSHong Zhang 
827b5b4017aSHong Zhang /*@
828bcf0153eSBarry Smith    TSGetCostHessianProducts - Returns the gradients from the `TSAdjointSolve()`
829b5b4017aSHong Zhang 
830bcf0153eSBarry Smith    Not Collective, but vectors returned are parallel if `TS` is parallel
831b5b4017aSHong Zhang 
832b5b4017aSHong Zhang    Input Parameter:
833bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
834b5b4017aSHong Zhang 
835d8d19677SJose E. Roman    Output Parameters:
836b5b4017aSHong Zhang +  numcost - number of cost functions
837b5b4017aSHong 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
838b5b4017aSHong 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
839b5b4017aSHong Zhang -  dir - the direction vector that are multiplied with the Hessian of the cost functions
840b5b4017aSHong Zhang 
841b5b4017aSHong Zhang    Level: intermediate
842b5b4017aSHong Zhang 
843bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSolve()`, `TSSetCostHessianProducts()`
844b5b4017aSHong Zhang @*/
845d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGetCostHessianProducts(TS ts, PetscInt *numcost, Vec **lambda2, Vec **mu2, Vec *dir)
846d71ae5a4SJacob Faibussowitsch {
847b5b4017aSHong Zhang   PetscFunctionBegin;
848b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
849b5b4017aSHong Zhang   if (numcost) *numcost = ts->numcost;
850b5b4017aSHong Zhang   if (lambda2) *lambda2 = ts->vecs_sensi2;
85133f72c5dSHong Zhang   if (mu2) *mu2 = ts->vecs_sensi2p;
852b5b4017aSHong Zhang   if (dir) *dir = ts->vec_dir;
853b5b4017aSHong Zhang   PetscFunctionReturn(0);
854b5b4017aSHong Zhang }
855b5b4017aSHong Zhang 
856b5b4017aSHong Zhang /*@
857ecf68647SHong Zhang   TSAdjointSetForward - Trigger the tangent linear solver and initialize the forward sensitivities
858b5b4017aSHong Zhang 
859c3339decSBarry Smith   Logically Collective
860b5b4017aSHong Zhang 
861b5b4017aSHong Zhang   Input Parameters:
862bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
863b5b4017aSHong Zhang -  didp - the derivative of initial values w.r.t. parameters
864b5b4017aSHong Zhang 
865b5b4017aSHong Zhang   Level: intermediate
866b5b4017aSHong Zhang 
867bcf0153eSBarry Smith   Notes:
868bcf0153eSBarry Smith   When computing sensitivies w.r.t. initial condition, set didp to NULL so that the solver will take it as an identity matrix mathematically.
869bcf0153eSBarry Smith   `TS` adjoint does not reset the tangent linear solver automatically, `TSAdjointResetForward()` should be called to reset the tangent linear solver.
870b5b4017aSHong Zhang 
871bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSolve()`, `TSSetCostHessianProducts()`, `TSAdjointResetForward()`
872b5b4017aSHong Zhang @*/
873d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointSetForward(TS ts, Mat didp)
874d71ae5a4SJacob Faibussowitsch {
87533f72c5dSHong Zhang   Mat          A;
87633f72c5dSHong Zhang   Vec          sp;
87733f72c5dSHong Zhang   PetscScalar *xarr;
87833f72c5dSHong Zhang   PetscInt     lsize;
879b5b4017aSHong Zhang 
880b5b4017aSHong Zhang   PetscFunctionBegin;
881b5b4017aSHong Zhang   ts->forward_solve = PETSC_TRUE; /* turn on tangent linear mode */
8823c633725SBarry Smith   PetscCheck(ts->vecs_sensi2, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetCostHessianProducts() first");
8833c633725SBarry Smith   PetscCheck(ts->vec_dir, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Directional vector is missing. Call TSSetCostHessianProducts() to set it.");
88433f72c5dSHong Zhang   /* create a single-column dense matrix */
8859566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(ts->vec_sol, &lsize));
8869566063dSJacob Faibussowitsch   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)ts), lsize, PETSC_DECIDE, PETSC_DECIDE, 1, NULL, &A));
88733f72c5dSHong Zhang 
8889566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &sp));
8899566063dSJacob Faibussowitsch   PetscCall(MatDenseGetColumn(A, 0, &xarr));
8909566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(sp, xarr));
891ecf68647SHong Zhang   if (ts->vecs_sensi2p) { /* tangent linear variable initialized as 2*dIdP*dir */
89233f72c5dSHong Zhang     if (didp) {
8939566063dSJacob Faibussowitsch       PetscCall(MatMult(didp, ts->vec_dir, sp));
8949566063dSJacob Faibussowitsch       PetscCall(VecScale(sp, 2.));
89533f72c5dSHong Zhang     } else {
8969566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(sp));
89733f72c5dSHong Zhang     }
898ecf68647SHong Zhang   } else { /* tangent linear variable initialized as dir */
8999566063dSJacob Faibussowitsch     PetscCall(VecCopy(ts->vec_dir, sp));
90033f72c5dSHong Zhang   }
9019566063dSJacob Faibussowitsch   PetscCall(VecResetArray(sp));
9029566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreColumn(A, &xarr));
9039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sp));
90433f72c5dSHong Zhang 
9059566063dSJacob Faibussowitsch   PetscCall(TSForwardSetInitialSensitivities(ts, A)); /* if didp is NULL, identity matrix is assumed */
90633f72c5dSHong Zhang 
9079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
908b5b4017aSHong Zhang   PetscFunctionReturn(0);
909b5b4017aSHong Zhang }
910b5b4017aSHong Zhang 
911b5b4017aSHong Zhang /*@
912ecf68647SHong Zhang   TSAdjointResetForward - Reset the tangent linear solver and destroy the tangent linear context
913ecf68647SHong Zhang 
914c3339decSBarry Smith   Logically Collective
915ecf68647SHong Zhang 
916ecf68647SHong Zhang   Input Parameters:
917bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
918ecf68647SHong Zhang 
919ecf68647SHong Zhang   Level: intermediate
920ecf68647SHong Zhang 
921bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSetForward()`
922ecf68647SHong Zhang @*/
923d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointResetForward(TS ts)
924d71ae5a4SJacob Faibussowitsch {
925ecf68647SHong Zhang   PetscFunctionBegin;
926ecf68647SHong Zhang   ts->forward_solve = PETSC_FALSE; /* turn off tangent linear mode */
9279566063dSJacob Faibussowitsch   PetscCall(TSForwardReset(ts));
928ecf68647SHong Zhang   PetscFunctionReturn(0);
929ecf68647SHong Zhang }
930ecf68647SHong Zhang 
931ecf68647SHong Zhang /*@
932814e85d6SHong Zhang    TSAdjointSetUp - Sets up the internal data structures for the later use
933814e85d6SHong Zhang    of an adjoint solver
934814e85d6SHong Zhang 
935c3339decSBarry Smith    Collective
936814e85d6SHong Zhang 
937814e85d6SHong Zhang    Input Parameter:
938bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
939814e85d6SHong Zhang 
940814e85d6SHong Zhang    Level: advanced
941814e85d6SHong Zhang 
942bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSCreate()`, `TSAdjointStep()`, `TSSetCostGradients()`
943814e85d6SHong Zhang @*/
944d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointSetUp(TS ts)
945d71ae5a4SJacob Faibussowitsch {
946881c1a9bSHong Zhang   TSTrajectory tj;
947881c1a9bSHong Zhang   PetscBool    match;
948814e85d6SHong Zhang 
949814e85d6SHong Zhang   PetscFunctionBegin;
950814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
951814e85d6SHong Zhang   if (ts->adjointsetupcalled) PetscFunctionReturn(0);
9523c633725SBarry Smith   PetscCheck(ts->vecs_sensi, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetCostGradients() first");
9533c633725SBarry Smith   PetscCheck(!ts->vecs_sensip || ts->Jacp || ts->Jacprhs, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetRHSJacobianP() or TSSetIJacobianP() first");
9549566063dSJacob Faibussowitsch   PetscCall(TSGetTrajectory(ts, &tj));
9559566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)tj, TSTRAJECTORYBASIC, &match));
956881c1a9bSHong Zhang   if (match) {
957881c1a9bSHong Zhang     PetscBool solution_only;
9589566063dSJacob Faibussowitsch     PetscCall(TSTrajectoryGetSolutionOnly(tj, &solution_only));
9593c633725SBarry 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");
960881c1a9bSHong Zhang   }
9619566063dSJacob Faibussowitsch   PetscCall(TSTrajectorySetUseHistory(tj, PETSC_FALSE)); /* not use TSHistory */
96233f72c5dSHong Zhang 
963cd4cee2dSHong Zhang   if (ts->quadraturets) { /* if there is integral in the cost function */
9649566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ts->vecs_sensi[0], &ts->vec_drdu_col));
96548a46eb9SPierre Jolivet     if (ts->vecs_sensip) PetscCall(VecDuplicate(ts->vecs_sensip[0], &ts->vec_drdp_col));
966814e85d6SHong Zhang   }
967814e85d6SHong Zhang 
968dbbe0bcdSBarry Smith   PetscTryTypeMethod(ts, adjointsetup);
969814e85d6SHong Zhang   ts->adjointsetupcalled = PETSC_TRUE;
970814e85d6SHong Zhang   PetscFunctionReturn(0);
971814e85d6SHong Zhang }
972814e85d6SHong Zhang 
973814e85d6SHong Zhang /*@
974bcf0153eSBarry Smith   TSAdjointReset - Resets a `TS` adjoint context and removes any allocated `Vec`s and `Mat`s.
975ece46509SHong Zhang 
976c3339decSBarry Smith    Collective
977ece46509SHong Zhang 
978ece46509SHong Zhang    Input Parameter:
979bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
980ece46509SHong Zhang 
981ece46509SHong Zhang    Level: beginner
982ece46509SHong Zhang 
983bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSCreate()`, `TSAdjointSetUp()`, `TSADestroy()`
984ece46509SHong Zhang @*/
985d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointReset(TS ts)
986d71ae5a4SJacob Faibussowitsch {
987ece46509SHong Zhang   PetscFunctionBegin;
988ece46509SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
989dbbe0bcdSBarry Smith   PetscTryTypeMethod(ts, adjointreset);
9907207e0fdSHong Zhang   if (ts->quadraturets) { /* if there is integral in the cost function */
9919566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ts->vec_drdu_col));
99248a46eb9SPierre Jolivet     if (ts->vecs_sensip) PetscCall(VecDestroy(&ts->vec_drdp_col));
9937207e0fdSHong Zhang   }
994ece46509SHong Zhang   ts->vecs_sensi         = NULL;
995ece46509SHong Zhang   ts->vecs_sensip        = NULL;
996ece46509SHong Zhang   ts->vecs_sensi2        = NULL;
99733f72c5dSHong Zhang   ts->vecs_sensi2p       = NULL;
998ece46509SHong Zhang   ts->vec_dir            = NULL;
999ece46509SHong Zhang   ts->adjointsetupcalled = PETSC_FALSE;
1000ece46509SHong Zhang   PetscFunctionReturn(0);
1001ece46509SHong Zhang }
1002ece46509SHong Zhang 
1003ece46509SHong Zhang /*@
1004814e85d6SHong Zhang    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time
1005814e85d6SHong Zhang 
1006c3339decSBarry Smith    Logically Collective
1007814e85d6SHong Zhang 
1008814e85d6SHong Zhang    Input Parameters:
1009bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
1010a2b725a8SWilliam Gropp -  steps - number of steps to use
1011814e85d6SHong Zhang 
1012814e85d6SHong Zhang    Level: intermediate
1013814e85d6SHong Zhang 
1014814e85d6SHong Zhang    Notes:
1015bcf0153eSBarry Smith     Normally one does not call this and `TSAdjointSolve()` integrates back to the original timestep. One can call this
1016814e85d6SHong Zhang           so as to integrate back to less than the original timestep
1017814e85d6SHong Zhang 
1018bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSolve()`, `TS`, `TSSetExactFinalTime()`
1019814e85d6SHong Zhang @*/
1020d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointSetSteps(TS ts, PetscInt steps)
1021d71ae5a4SJacob Faibussowitsch {
1022814e85d6SHong Zhang   PetscFunctionBegin;
1023814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1024814e85d6SHong Zhang   PetscValidLogicalCollectiveInt(ts, steps, 2);
10253c633725SBarry Smith   PetscCheck(steps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Cannot step back a negative number of steps");
10263c633725SBarry Smith   PetscCheck(steps <= ts->steps, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Cannot step back more than the total number of forward steps");
1027814e85d6SHong Zhang   ts->adjoint_max_steps = steps;
1028814e85d6SHong Zhang   PetscFunctionReturn(0);
1029814e85d6SHong Zhang }
1030814e85d6SHong Zhang 
1031814e85d6SHong Zhang /*@C
1032bcf0153eSBarry Smith   TSAdjointSetRHSJacobian - Deprecated, use `TSSetRHSJacobianP()`
1033814e85d6SHong Zhang 
1034814e85d6SHong Zhang   Level: deprecated
1035814e85d6SHong Zhang 
1036814e85d6SHong Zhang @*/
1037d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointSetRHSJacobian(TS ts, Mat Amat, PetscErrorCode (*func)(TS, PetscReal, Vec, Mat, void *), void *ctx)
1038d71ae5a4SJacob Faibussowitsch {
1039814e85d6SHong Zhang   PetscFunctionBegin;
1040814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1041814e85d6SHong Zhang   PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2);
1042814e85d6SHong Zhang 
1043814e85d6SHong Zhang   ts->rhsjacobianp    = func;
1044814e85d6SHong Zhang   ts->rhsjacobianpctx = ctx;
1045814e85d6SHong Zhang   if (Amat) {
10469566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)Amat));
10479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&ts->Jacp));
1048814e85d6SHong Zhang     ts->Jacp = Amat;
1049814e85d6SHong Zhang   }
1050814e85d6SHong Zhang   PetscFunctionReturn(0);
1051814e85d6SHong Zhang }
1052814e85d6SHong Zhang 
1053814e85d6SHong Zhang /*@C
1054bcf0153eSBarry Smith   TSAdjointComputeRHSJacobian - Deprecated, use `TSComputeRHSJacobianP()`
1055814e85d6SHong Zhang 
1056814e85d6SHong Zhang   Level: deprecated
1057814e85d6SHong Zhang 
1058814e85d6SHong Zhang @*/
1059d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointComputeRHSJacobian(TS ts, PetscReal t, Vec U, Mat Amat)
1060d71ae5a4SJacob Faibussowitsch {
1061814e85d6SHong Zhang   PetscFunctionBegin;
1062814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1063c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
1064814e85d6SHong Zhang   PetscValidPointer(Amat, 4);
1065814e85d6SHong Zhang 
1066792fecdfSBarry Smith   PetscCallBack("TS callback JacobianP for sensitivity analysis", (*ts->rhsjacobianp)(ts, t, U, Amat, ts->rhsjacobianpctx));
1067814e85d6SHong Zhang   PetscFunctionReturn(0);
1068814e85d6SHong Zhang }
1069814e85d6SHong Zhang 
1070814e85d6SHong Zhang /*@
1071bcf0153eSBarry Smith   TSAdjointComputeDRDYFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobian()`
1072814e85d6SHong Zhang 
1073814e85d6SHong Zhang   Level: deprecated
1074814e85d6SHong Zhang 
1075814e85d6SHong Zhang @*/
1076d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointComputeDRDYFunction(TS ts, PetscReal t, Vec U, Vec *DRDU)
1077d71ae5a4SJacob Faibussowitsch {
1078814e85d6SHong Zhang   PetscFunctionBegin;
1079814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1080c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
1081814e85d6SHong Zhang 
1082792fecdfSBarry Smith   PetscCallBack("TS callback DRDY for sensitivity analysis", (*ts->drdufunction)(ts, t, U, DRDU, ts->costintegrandctx));
1083814e85d6SHong Zhang   PetscFunctionReturn(0);
1084814e85d6SHong Zhang }
1085814e85d6SHong Zhang 
1086814e85d6SHong Zhang /*@
1087bcf0153eSBarry Smith   TSAdjointComputeDRDPFunction - Deprecated, use `TSGetQuadratureTS()` then `TSComputeRHSJacobianP()`
1088814e85d6SHong Zhang 
1089814e85d6SHong Zhang   Level: deprecated
1090814e85d6SHong Zhang 
1091814e85d6SHong Zhang @*/
1092d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointComputeDRDPFunction(TS ts, PetscReal t, Vec U, Vec *DRDP)
1093d71ae5a4SJacob Faibussowitsch {
1094814e85d6SHong Zhang   PetscFunctionBegin;
1095814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1096c9ad9de0SHong Zhang   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
1097814e85d6SHong Zhang 
1098792fecdfSBarry Smith   PetscCallBack("TS callback DRDP for sensitivity analysis", (*ts->drdpfunction)(ts, t, U, DRDP, ts->costintegrandctx));
1099814e85d6SHong Zhang   PetscFunctionReturn(0);
1100814e85d6SHong Zhang }
1101814e85d6SHong Zhang 
1102814e85d6SHong Zhang /*@C
1103814e85d6SHong Zhang    TSAdjointMonitorSensi - monitors the first lambda sensitivity
1104814e85d6SHong Zhang 
1105814e85d6SHong Zhang    Level: intermediate
1106814e85d6SHong Zhang 
1107bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointMonitorSet()`
1108814e85d6SHong Zhang @*/
1109d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointMonitorSensi(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscInt numcost, Vec *lambda, Vec *mu, PetscViewerAndFormat *vf)
1110d71ae5a4SJacob Faibussowitsch {
1111814e85d6SHong Zhang   PetscViewer viewer = vf->viewer;
1112814e85d6SHong Zhang 
1113814e85d6SHong Zhang   PetscFunctionBegin;
1114064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8);
11159566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer, vf->format));
11169566063dSJacob Faibussowitsch   PetscCall(VecView(lambda[0], viewer));
11179566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
1118814e85d6SHong Zhang   PetscFunctionReturn(0);
1119814e85d6SHong Zhang }
1120814e85d6SHong Zhang 
1121814e85d6SHong Zhang /*@C
1122814e85d6SHong Zhang    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
1123814e85d6SHong Zhang 
1124c3339decSBarry Smith    Collective
1125814e85d6SHong Zhang 
1126814e85d6SHong Zhang    Input Parameters:
1127bcf0153eSBarry Smith +  ts - `TS` object you wish to monitor
1128814e85d6SHong Zhang .  name - the monitor type one is seeking
1129814e85d6SHong Zhang .  help - message indicating what monitoring is done
1130814e85d6SHong Zhang .  manual - manual page for the monitor
1131814e85d6SHong Zhang .  monitor - the monitor function
1132bcf0153eSBarry Smith -  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
1133814e85d6SHong Zhang 
1134814e85d6SHong Zhang    Level: developer
1135814e85d6SHong Zhang 
1136bcf0153eSBarry Smith .seealso: [](chapter_ts), `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
1137db781477SPatrick Sanan           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
1138db781477SPatrick Sanan           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
1139db781477SPatrick Sanan           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1140c2e3fba1SPatrick Sanan           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1141db781477SPatrick Sanan           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1142db781477SPatrick Sanan           `PetscOptionsFList()`, `PetscOptionsEList()`
1143814e85d6SHong Zhang @*/
1144d71ae5a4SJacob Faibussowitsch 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 *))
1145d71ae5a4SJacob Faibussowitsch {
1146814e85d6SHong Zhang   PetscViewer       viewer;
1147814e85d6SHong Zhang   PetscViewerFormat format;
1148814e85d6SHong Zhang   PetscBool         flg;
1149814e85d6SHong Zhang 
1150814e85d6SHong Zhang   PetscFunctionBegin;
11519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts), ((PetscObject)ts)->options, ((PetscObject)ts)->prefix, name, &viewer, &format, &flg));
1152814e85d6SHong Zhang   if (flg) {
1153814e85d6SHong Zhang     PetscViewerAndFormat *vf;
11549566063dSJacob Faibussowitsch     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
11559566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)viewer));
11561baa6e33SBarry Smith     if (monitorsetup) PetscCall((*monitorsetup)(ts, vf));
11579566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitorSet(ts, (PetscErrorCode(*)(TS, PetscInt, PetscReal, Vec, PetscInt, Vec *, Vec *, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
1158814e85d6SHong Zhang   }
1159814e85d6SHong Zhang   PetscFunctionReturn(0);
1160814e85d6SHong Zhang }
1161814e85d6SHong Zhang 
1162814e85d6SHong Zhang /*@C
1163814e85d6SHong Zhang    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
1164814e85d6SHong Zhang    timestep to display the iteration's  progress.
1165814e85d6SHong Zhang 
1166c3339decSBarry Smith    Logically Collective
1167814e85d6SHong Zhang 
1168814e85d6SHong Zhang    Input Parameters:
1169bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
1170814e85d6SHong Zhang .  adjointmonitor - monitoring routine
1171814e85d6SHong Zhang .  adjointmctx - [optional] user-defined context for private data for the
1172814e85d6SHong Zhang              monitor routine (use NULL if no context is desired)
1173814e85d6SHong Zhang -  adjointmonitordestroy - [optional] routine that frees monitor context
1174814e85d6SHong Zhang           (may be NULL)
1175814e85d6SHong Zhang 
1176814e85d6SHong Zhang    Calling sequence of monitor:
1177814e85d6SHong Zhang $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)
1178814e85d6SHong Zhang 
1179bcf0153eSBarry Smith +    ts - the `TS` context
1180814e85d6SHong 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
1181814e85d6SHong Zhang                                been interpolated to)
1182814e85d6SHong Zhang .    time - current time
1183814e85d6SHong Zhang .    u - current iterate
1184814e85d6SHong Zhang .    numcost - number of cost functionos
1185814e85d6SHong Zhang .    lambda - sensitivities to initial conditions
1186814e85d6SHong Zhang .    mu - sensitivities to parameters
1187814e85d6SHong Zhang -    adjointmctx - [optional] adjoint monitoring context
1188814e85d6SHong Zhang 
1189bcf0153eSBarry Smith    Level: intermediate
1190bcf0153eSBarry Smith 
1191bcf0153eSBarry Smith    Note:
1192814e85d6SHong Zhang    This routine adds an additional monitor to the list of monitors that
1193814e85d6SHong Zhang    already has been loaded.
1194814e85d6SHong Zhang 
1195bcf0153eSBarry Smith    Fortran Note:
1196814e85d6SHong Zhang    Only a single monitor function can be set for each TS object
1197814e85d6SHong Zhang 
1198bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, `TSAdjointMonitorCancel()`
1199814e85d6SHong Zhang @*/
1200d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointMonitorSet(TS ts, PetscErrorCode (*adjointmonitor)(TS, PetscInt, PetscReal, Vec, PetscInt, Vec *, Vec *, void *), void *adjointmctx, PetscErrorCode (*adjointmdestroy)(void **))
1201d71ae5a4SJacob Faibussowitsch {
1202814e85d6SHong Zhang   PetscInt  i;
1203814e85d6SHong Zhang   PetscBool identical;
1204814e85d6SHong Zhang 
1205814e85d6SHong Zhang   PetscFunctionBegin;
1206814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1207814e85d6SHong Zhang   for (i = 0; i < ts->numbermonitors; i++) {
12089566063dSJacob Faibussowitsch     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))adjointmonitor, adjointmctx, adjointmdestroy, (PetscErrorCode(*)(void))ts->adjointmonitor[i], ts->adjointmonitorcontext[i], ts->adjointmonitordestroy[i], &identical));
1209814e85d6SHong Zhang     if (identical) PetscFunctionReturn(0);
1210814e85d6SHong Zhang   }
12113c633725SBarry Smith   PetscCheck(ts->numberadjointmonitors < MAXTSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many adjoint monitors set");
1212814e85d6SHong Zhang   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
1213814e85d6SHong Zhang   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
1214814e85d6SHong Zhang   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void *)adjointmctx;
1215814e85d6SHong Zhang   PetscFunctionReturn(0);
1216814e85d6SHong Zhang }
1217814e85d6SHong Zhang 
1218814e85d6SHong Zhang /*@C
1219814e85d6SHong Zhang    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.
1220814e85d6SHong Zhang 
1221c3339decSBarry Smith    Logically Collective
1222814e85d6SHong Zhang 
1223814e85d6SHong Zhang    Input Parameters:
1224bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
1225814e85d6SHong Zhang 
1226814e85d6SHong Zhang    Notes:
1227814e85d6SHong Zhang    There is no way to remove a single, specific monitor.
1228814e85d6SHong Zhang 
1229814e85d6SHong Zhang    Level: intermediate
1230814e85d6SHong Zhang 
1231bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, `TSAdjointMonitorSet()`
1232814e85d6SHong Zhang @*/
1233d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointMonitorCancel(TS ts)
1234d71ae5a4SJacob Faibussowitsch {
1235814e85d6SHong Zhang   PetscInt i;
1236814e85d6SHong Zhang 
1237814e85d6SHong Zhang   PetscFunctionBegin;
1238814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1239814e85d6SHong Zhang   for (i = 0; i < ts->numberadjointmonitors; i++) {
124048a46eb9SPierre Jolivet     if (ts->adjointmonitordestroy[i]) PetscCall((*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]));
1241814e85d6SHong Zhang   }
1242814e85d6SHong Zhang   ts->numberadjointmonitors = 0;
1243814e85d6SHong Zhang   PetscFunctionReturn(0);
1244814e85d6SHong Zhang }
1245814e85d6SHong Zhang 
1246814e85d6SHong Zhang /*@C
1247814e85d6SHong Zhang    TSAdjointMonitorDefault - the default monitor of adjoint computations
1248814e85d6SHong Zhang 
1249814e85d6SHong Zhang    Level: intermediate
1250814e85d6SHong Zhang 
1251bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSAdjointSolve()`, `TSAdjointMonitorSet()`
1252814e85d6SHong Zhang @*/
1253d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointMonitorDefault(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscInt numcost, Vec *lambda, Vec *mu, PetscViewerAndFormat *vf)
1254d71ae5a4SJacob Faibussowitsch {
1255814e85d6SHong Zhang   PetscViewer viewer = vf->viewer;
1256814e85d6SHong Zhang 
1257814e85d6SHong Zhang   PetscFunctionBegin;
1258064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8);
12599566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer, vf->format));
12609566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
126163a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " TS dt %g time %g%s", step, (double)ts->time_step, (double)ptime, ts->steprollback ? " (r)\n" : "\n"));
12629566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
12639566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
1264814e85d6SHong Zhang   PetscFunctionReturn(0);
1265814e85d6SHong Zhang }
1266814e85d6SHong Zhang 
1267814e85d6SHong Zhang /*@C
1268bcf0153eSBarry Smith    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint `TS` solvers by calling
1269bcf0153eSBarry Smith    `VecView()` for the sensitivities to initial states at each timestep
1270814e85d6SHong Zhang 
1271c3339decSBarry Smith    Collective
1272814e85d6SHong Zhang 
1273814e85d6SHong Zhang    Input Parameters:
1274bcf0153eSBarry Smith +  ts - the `TS` context
1275814e85d6SHong Zhang .  step - current time-step
1276814e85d6SHong Zhang .  ptime - current time
1277814e85d6SHong Zhang .  u - current state
1278814e85d6SHong Zhang .  numcost - number of cost functions
1279814e85d6SHong Zhang .  lambda - sensitivities to initial conditions
1280814e85d6SHong Zhang .  mu - sensitivities to parameters
1281814e85d6SHong Zhang -  dummy - either a viewer or NULL
1282814e85d6SHong Zhang 
1283814e85d6SHong Zhang    Level: intermediate
1284814e85d6SHong Zhang 
1285bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSolve()`, `TSAdjointMonitorSet()`, `TSAdjointMonitorDefault()`, `VecView()`
1286814e85d6SHong Zhang @*/
1287d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointMonitorDrawSensi(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscInt numcost, Vec *lambda, Vec *mu, void *dummy)
1288d71ae5a4SJacob Faibussowitsch {
1289814e85d6SHong Zhang   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
1290814e85d6SHong Zhang   PetscDraw        draw;
1291814e85d6SHong Zhang   PetscReal        xl, yl, xr, yr, h;
1292814e85d6SHong Zhang   char             time[32];
1293814e85d6SHong Zhang 
1294814e85d6SHong Zhang   PetscFunctionBegin;
1295814e85d6SHong Zhang   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
1296814e85d6SHong Zhang 
12979566063dSJacob Faibussowitsch   PetscCall(VecView(lambda[0], ictx->viewer));
12989566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(ictx->viewer, 0, &draw));
12999566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(time, 32, "Timestep %d Time %g", (int)step, (double)ptime));
13009566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
1301814e85d6SHong Zhang   h = yl + .95 * (yr - yl);
13029566063dSJacob Faibussowitsch   PetscCall(PetscDrawStringCentered(draw, .5 * (xl + xr), h, PETSC_DRAW_BLACK, time));
13039566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
1304814e85d6SHong Zhang   PetscFunctionReturn(0);
1305814e85d6SHong Zhang }
1306814e85d6SHong Zhang 
1307814e85d6SHong Zhang /*
1308bcf0153eSBarry Smith    TSAdjointSetFromOptions - Sets various `TS` adjoint parameters from user options.
1309814e85d6SHong Zhang 
1310c3339decSBarry Smith    Collective
1311814e85d6SHong Zhang 
1312814e85d6SHong Zhang    Input Parameter:
1313bcf0153eSBarry Smith .  ts - the `TS` context
1314814e85d6SHong Zhang 
1315814e85d6SHong Zhang    Options Database Keys:
1316814e85d6SHong Zhang +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
1317814e85d6SHong Zhang .  -ts_adjoint_monitor - print information at each adjoint time step
1318814e85d6SHong Zhang -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically
1319814e85d6SHong Zhang 
1320814e85d6SHong Zhang    Level: developer
1321814e85d6SHong Zhang 
1322bcf0153eSBarry Smith    Note:
1323814e85d6SHong Zhang     This is not normally called directly by users
1324814e85d6SHong Zhang 
1325bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSSetSaveTrajectory()`, `TSTrajectorySetUp()`
1326814e85d6SHong Zhang */
1327d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointSetFromOptions(TS ts, PetscOptionItems *PetscOptionsObject)
1328d71ae5a4SJacob Faibussowitsch {
1329814e85d6SHong Zhang   PetscBool tflg, opt;
1330814e85d6SHong Zhang 
1331814e85d6SHong Zhang   PetscFunctionBegin;
1332dbbe0bcdSBarry Smith   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1333d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "TS Adjoint options");
1334814e85d6SHong Zhang   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
13359566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-ts_adjoint_solve", "Solve the adjoint problem immediately after solving the forward problem", "", tflg, &tflg, &opt));
1336814e85d6SHong Zhang   if (opt) {
13379566063dSJacob Faibussowitsch     PetscCall(TSSetSaveTrajectory(ts));
1338814e85d6SHong Zhang     ts->adjoint_solve = tflg;
1339814e85d6SHong Zhang   }
13409566063dSJacob Faibussowitsch   PetscCall(TSAdjointMonitorSetFromOptions(ts, "-ts_adjoint_monitor", "Monitor adjoint timestep size", "TSAdjointMonitorDefault", TSAdjointMonitorDefault, NULL));
13419566063dSJacob Faibussowitsch   PetscCall(TSAdjointMonitorSetFromOptions(ts, "-ts_adjoint_monitor_sensi", "Monitor sensitivity in the adjoint computation", "TSAdjointMonitorSensi", TSAdjointMonitorSensi, NULL));
1342814e85d6SHong Zhang   opt = PETSC_FALSE;
13439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsName("-ts_adjoint_monitor_draw_sensi", "Monitor adjoint sensitivities (lambda only) graphically", "TSAdjointMonitorDrawSensi", &opt));
1344814e85d6SHong Zhang   if (opt) {
1345814e85d6SHong Zhang     TSMonitorDrawCtx ctx;
1346814e85d6SHong Zhang     PetscInt         howoften = 1;
1347814e85d6SHong Zhang 
13489566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_adjoint_monitor_draw_sensi", "Monitor adjoint sensitivities (lambda only) graphically", "TSAdjointMonitorDrawSensi", howoften, &howoften, NULL));
13499566063dSJacob Faibussowitsch     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
13509566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitorSet(ts, TSAdjointMonitorDrawSensi, ctx, (PetscErrorCode(*)(void **))TSMonitorDrawCtxDestroy));
1351814e85d6SHong Zhang   }
1352814e85d6SHong Zhang   PetscFunctionReturn(0);
1353814e85d6SHong Zhang }
1354814e85d6SHong Zhang 
1355814e85d6SHong Zhang /*@
1356814e85d6SHong Zhang    TSAdjointStep - Steps one time step backward in the adjoint run
1357814e85d6SHong Zhang 
1358c3339decSBarry Smith    Collective
1359814e85d6SHong Zhang 
1360814e85d6SHong Zhang    Input Parameter:
1361bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
1362814e85d6SHong Zhang 
1363814e85d6SHong Zhang    Level: intermediate
1364814e85d6SHong Zhang 
1365bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSetUp()`, `TSAdjointSolve()`
1366814e85d6SHong Zhang @*/
1367d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointStep(TS ts)
1368d71ae5a4SJacob Faibussowitsch {
1369814e85d6SHong Zhang   DM dm;
1370814e85d6SHong Zhang 
1371814e85d6SHong Zhang   PetscFunctionBegin;
1372814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
13739566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
13749566063dSJacob Faibussowitsch   PetscCall(TSAdjointSetUp(ts));
13757b0e2f17SHong Zhang   ts->steps--; /* must decrease the step index before the adjoint step is taken. */
1376814e85d6SHong Zhang 
1377814e85d6SHong Zhang   ts->reason     = TS_CONVERGED_ITERATING;
1378814e85d6SHong Zhang   ts->ptime_prev = ts->ptime;
13799566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_AdjointStep, ts, 0, 0, 0));
1380dbbe0bcdSBarry Smith   PetscUseTypeMethod(ts, adjointstep);
13819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_AdjointStep, ts, 0, 0, 0));
13827b0e2f17SHong Zhang   ts->adjoint_steps++;
1383814e85d6SHong Zhang 
1384814e85d6SHong Zhang   if (ts->reason < 0) {
13853c633725SBarry Smith     PetscCheck(!ts->errorifstepfailed, PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSAdjointStep has failed due to %s", TSConvergedReasons[ts->reason]);
1386814e85d6SHong Zhang   } else if (!ts->reason) {
1387814e85d6SHong Zhang     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1388814e85d6SHong Zhang   }
1389814e85d6SHong Zhang   PetscFunctionReturn(0);
1390814e85d6SHong Zhang }
1391814e85d6SHong Zhang 
1392814e85d6SHong Zhang /*@
1393814e85d6SHong Zhang    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE
1394814e85d6SHong Zhang 
1395c3339decSBarry Smith    Collective
1396bcf0153eSBarry Smith `
1397814e85d6SHong Zhang    Input Parameter:
1398bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
1399814e85d6SHong Zhang 
1400bcf0153eSBarry Smith    Options Database Key:
1401814e85d6SHong Zhang . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values
1402814e85d6SHong Zhang 
1403814e85d6SHong Zhang    Level: intermediate
1404814e85d6SHong Zhang 
1405814e85d6SHong Zhang    Notes:
1406bcf0153eSBarry Smith    This must be called after a call to `TSSolve()` that solves the forward problem
1407814e85d6SHong Zhang 
1408bcf0153eSBarry Smith    By default this will integrate back to the initial time, one can use `TSAdjointSetSteps()` to step back to a later time
1409814e85d6SHong Zhang 
1410bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSAdjointSolve()`, `TSCreate()`, `TSSetCostGradients()`, `TSSetSolution()`, `TSAdjointStep()`
1411814e85d6SHong Zhang @*/
1412d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointSolve(TS ts)
1413d71ae5a4SJacob Faibussowitsch {
1414f1d62c27SHong Zhang   static PetscBool cite = PETSC_FALSE;
14157f59fb53SHong Zhang #if defined(TSADJOINT_STAGE)
14167f59fb53SHong Zhang   PetscLogStage adjoint_stage;
14177f59fb53SHong Zhang #endif
1418814e85d6SHong Zhang 
1419814e85d6SHong Zhang   PetscFunctionBegin;
1420814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1421421b783aSHong Zhang   PetscCall(PetscCitationsRegister("@article{Zhang2022tsadjoint,\n"
1422421b783aSHong Zhang                                    "  title         = {{PETSc TSAdjoint: A Discrete Adjoint ODE Solver for First-Order and Second-Order Sensitivity Analysis}},\n"
1423f1d62c27SHong Zhang                                    "  author        = {Zhang, Hong and Constantinescu, Emil M.  and Smith, Barry F.},\n"
1424421b783aSHong Zhang                                    "  journal       = {SIAM Journal on Scientific Computing},\n"
1425421b783aSHong Zhang                                    "  volume        = {44},\n"
1426421b783aSHong Zhang                                    "  number        = {1},\n"
1427421b783aSHong Zhang                                    "  pages         = {C1-C24},\n"
1428421b783aSHong Zhang                                    "  doi           = {10.1137/21M140078X},\n"
14299371c9d4SSatish Balay                                    "  year          = {2022}\n}\n",
14309371c9d4SSatish Balay                                    &cite));
14317f59fb53SHong Zhang #if defined(TSADJOINT_STAGE)
14329566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("TSAdjoint", &adjoint_stage));
14339566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(adjoint_stage));
14347f59fb53SHong Zhang #endif
14359566063dSJacob Faibussowitsch   PetscCall(TSAdjointSetUp(ts));
1436814e85d6SHong Zhang 
1437814e85d6SHong Zhang   /* reset time step and iteration counters */
1438814e85d6SHong Zhang   ts->adjoint_steps     = 0;
1439814e85d6SHong Zhang   ts->ksp_its           = 0;
1440814e85d6SHong Zhang   ts->snes_its          = 0;
1441814e85d6SHong Zhang   ts->num_snes_failures = 0;
1442814e85d6SHong Zhang   ts->reject            = 0;
1443814e85d6SHong Zhang   ts->reason            = TS_CONVERGED_ITERATING;
1444814e85d6SHong Zhang 
1445814e85d6SHong Zhang   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
1446814e85d6SHong Zhang   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
1447814e85d6SHong Zhang 
1448814e85d6SHong Zhang   while (!ts->reason) {
14499566063dSJacob Faibussowitsch     PetscCall(TSTrajectoryGet(ts->trajectory, ts, ts->steps, &ts->ptime));
14509566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitor(ts, ts->steps, ts->ptime, ts->vec_sol, ts->numcost, ts->vecs_sensi, ts->vecs_sensip));
14519566063dSJacob Faibussowitsch     PetscCall(TSAdjointEventHandler(ts));
14529566063dSJacob Faibussowitsch     PetscCall(TSAdjointStep(ts));
145348a46eb9SPierre Jolivet     if ((ts->vec_costintegral || ts->quadraturets) && !ts->costintegralfwd) PetscCall(TSAdjointCostIntegral(ts));
1454814e85d6SHong Zhang   }
1455bdbff044SHong Zhang   if (!ts->steps) {
14569566063dSJacob Faibussowitsch     PetscCall(TSTrajectoryGet(ts->trajectory, ts, ts->steps, &ts->ptime));
14579566063dSJacob Faibussowitsch     PetscCall(TSAdjointMonitor(ts, ts->steps, ts->ptime, ts->vec_sol, ts->numcost, ts->vecs_sensi, ts->vecs_sensip));
1458bdbff044SHong Zhang   }
1459814e85d6SHong Zhang   ts->solvetime = ts->ptime;
14609566063dSJacob Faibussowitsch   PetscCall(TSTrajectoryViewFromOptions(ts->trajectory, NULL, "-ts_trajectory_view"));
14619566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(ts->vecs_sensi[0], (PetscObject)ts, "-ts_adjoint_view_solution"));
1462814e85d6SHong Zhang   ts->adjoint_max_steps = 0;
14637f59fb53SHong Zhang #if defined(TSADJOINT_STAGE)
14649566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
14657f59fb53SHong Zhang #endif
1466814e85d6SHong Zhang   PetscFunctionReturn(0);
1467814e85d6SHong Zhang }
1468814e85d6SHong Zhang 
1469814e85d6SHong Zhang /*@C
1470bcf0153eSBarry Smith    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using `TSAdjointMonitorSet()`
1471814e85d6SHong Zhang 
1472c3339decSBarry Smith    Collective
1473814e85d6SHong Zhang 
1474814e85d6SHong Zhang    Input Parameters:
1475bcf0153eSBarry Smith +  ts - time stepping context obtained from `TSCreate()`
1476814e85d6SHong Zhang .  step - step number that has just completed
1477814e85d6SHong Zhang .  ptime - model time of the state
1478814e85d6SHong Zhang .  u - state at the current model time
1479814e85d6SHong Zhang .  numcost - number of cost functions (dimension of lambda  or mu)
1480814e85d6SHong Zhang .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
1481814e85d6SHong Zhang -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters
1482814e85d6SHong Zhang 
1483814e85d6SHong Zhang    Level: developer
1484814e85d6SHong Zhang 
1485bcf0153eSBarry Smith    Note:
1486bcf0153eSBarry Smith    `TSAdjointMonitor()` is typically used automatically within the time stepping implementations.
1487bcf0153eSBarry Smith    Users would almost never call this routine directly.
1488bcf0153eSBarry Smith 
1489bcf0153eSBarry Smith .seealso: `TSAdjointMonitorSet()`, `TSAdjointSolve()`
1490814e85d6SHong Zhang @*/
1491d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointMonitor(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscInt numcost, Vec *lambda, Vec *mu)
1492d71ae5a4SJacob Faibussowitsch {
1493814e85d6SHong Zhang   PetscInt i, n = ts->numberadjointmonitors;
1494814e85d6SHong Zhang 
1495814e85d6SHong Zhang   PetscFunctionBegin;
1496814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1497814e85d6SHong Zhang   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
14989566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(u));
149948a46eb9SPierre Jolivet   for (i = 0; i < n; i++) PetscCall((*ts->adjointmonitor[i])(ts, step, ptime, u, numcost, lambda, mu, ts->adjointmonitorcontext[i]));
15009566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(u));
1501814e85d6SHong Zhang   PetscFunctionReturn(0);
1502814e85d6SHong Zhang }
1503814e85d6SHong Zhang 
1504814e85d6SHong Zhang /*@
1505814e85d6SHong Zhang  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.
1506814e85d6SHong Zhang 
1507c3339decSBarry Smith  Collective
1508814e85d6SHong Zhang 
15094165533cSJose E. Roman  Input Parameter:
1510814e85d6SHong Zhang  .  ts - time stepping context
1511814e85d6SHong Zhang 
1512814e85d6SHong Zhang  Level: advanced
1513814e85d6SHong Zhang 
1514814e85d6SHong Zhang  Notes:
1515bcf0153eSBarry Smith  This function cannot be called until `TSAdjointStep()` has been completed.
1516814e85d6SHong Zhang 
1517bcf0153eSBarry Smith  .seealso: [](chapter_ts), `TSAdjointSolve()`, `TSAdjointStep()`
1518814e85d6SHong Zhang  @*/
1519d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointCostIntegral(TS ts)
1520d71ae5a4SJacob Faibussowitsch {
1521362febeeSStefano Zampini   PetscFunctionBegin;
1522814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1523dbbe0bcdSBarry Smith   PetscUseTypeMethod(ts, adjointintegral);
1524814e85d6SHong Zhang   PetscFunctionReturn(0);
1525814e85d6SHong Zhang }
1526814e85d6SHong Zhang 
1527814e85d6SHong Zhang /* ------------------ Forward (tangent linear) sensitivity  ------------------*/
1528814e85d6SHong Zhang 
1529814e85d6SHong Zhang /*@
1530814e85d6SHong Zhang   TSForwardSetUp - Sets up the internal data structures for the later use
1531814e85d6SHong Zhang   of forward sensitivity analysis
1532814e85d6SHong Zhang 
1533c3339decSBarry Smith   Collective
1534814e85d6SHong Zhang 
1535814e85d6SHong Zhang   Input Parameter:
1536bcf0153eSBarry Smith . ts - the `TS` context obtained from `TSCreate()`
1537814e85d6SHong Zhang 
1538814e85d6SHong Zhang   Level: advanced
1539814e85d6SHong Zhang 
1540bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSCreate()`, `TSDestroy()`, `TSSetUp()`
1541814e85d6SHong Zhang @*/
1542d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardSetUp(TS ts)
1543d71ae5a4SJacob Faibussowitsch {
1544814e85d6SHong Zhang   PetscFunctionBegin;
1545814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1546814e85d6SHong Zhang   if (ts->forwardsetupcalled) PetscFunctionReturn(0);
1547dbbe0bcdSBarry Smith   PetscTryTypeMethod(ts, forwardsetup);
15489566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &ts->vec_sensip_col));
1549814e85d6SHong Zhang   ts->forwardsetupcalled = PETSC_TRUE;
1550814e85d6SHong Zhang   PetscFunctionReturn(0);
1551814e85d6SHong Zhang }
1552814e85d6SHong Zhang 
1553814e85d6SHong Zhang /*@
15547adebddeSHong Zhang   TSForwardReset - Reset the internal data structures used by forward sensitivity analysis
15557adebddeSHong Zhang 
1556c3339decSBarry Smith   Collective
15577adebddeSHong Zhang 
15587adebddeSHong Zhang   Input Parameter:
1559bcf0153eSBarry Smith . ts - the `TS` context obtained from `TSCreate()`
15607adebddeSHong Zhang 
15617adebddeSHong Zhang   Level: advanced
15627adebddeSHong Zhang 
1563bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSCreate()`, `TSDestroy()`, `TSForwardSetUp()`
15647adebddeSHong Zhang @*/
1565d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardReset(TS ts)
1566d71ae5a4SJacob Faibussowitsch {
15677207e0fdSHong Zhang   TS quadts = ts->quadraturets;
15687adebddeSHong Zhang 
15697adebddeSHong Zhang   PetscFunctionBegin;
15707adebddeSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1571dbbe0bcdSBarry Smith   PetscTryTypeMethod(ts, forwardreset);
15729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ts->mat_sensip));
157348a46eb9SPierre Jolivet   if (quadts) PetscCall(MatDestroy(&quadts->mat_sensip));
15749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ts->vec_sensip_col));
15757adebddeSHong Zhang   ts->forward_solve      = PETSC_FALSE;
15767adebddeSHong Zhang   ts->forwardsetupcalled = PETSC_FALSE;
15777adebddeSHong Zhang   PetscFunctionReturn(0);
15787adebddeSHong Zhang }
15797adebddeSHong Zhang 
15807adebddeSHong Zhang /*@
1581814e85d6SHong Zhang   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.
1582814e85d6SHong Zhang 
1583d8d19677SJose E. Roman   Input Parameters:
1584bcf0153eSBarry Smith + ts - the `TS` context obtained from `TSCreate()`
1585814e85d6SHong Zhang . numfwdint - number of integrals
158667b8a455SSatish Balay - vp - the vectors containing the gradients for each integral w.r.t. parameters
1587814e85d6SHong Zhang 
15887207e0fdSHong Zhang   Level: deprecated
1589814e85d6SHong Zhang 
1590bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1591814e85d6SHong Zhang @*/
1592d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardSetIntegralGradients(TS ts, PetscInt numfwdint, Vec *vp)
1593d71ae5a4SJacob Faibussowitsch {
1594814e85d6SHong Zhang   PetscFunctionBegin;
1595814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
15963c633725SBarry 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()");
1597814e85d6SHong Zhang   if (!ts->numcost) ts->numcost = numfwdint;
1598814e85d6SHong Zhang 
1599814e85d6SHong Zhang   ts->vecs_integral_sensip = vp;
1600814e85d6SHong Zhang   PetscFunctionReturn(0);
1601814e85d6SHong Zhang }
1602814e85d6SHong Zhang 
1603814e85d6SHong Zhang /*@
1604814e85d6SHong Zhang   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.
1605814e85d6SHong Zhang 
1606814e85d6SHong Zhang   Input Parameter:
1607bcf0153eSBarry Smith . ts - the `TS` context obtained from `TSCreate()`
1608814e85d6SHong Zhang 
1609814e85d6SHong Zhang   Output Parameter:
161067b8a455SSatish Balay . vp - the vectors containing the gradients for each integral w.r.t. parameters
1611814e85d6SHong Zhang 
16127207e0fdSHong Zhang   Level: deprecated
1613814e85d6SHong Zhang 
1614bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSForwardSetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1615814e85d6SHong Zhang @*/
1616d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardGetIntegralGradients(TS ts, PetscInt *numfwdint, Vec **vp)
1617d71ae5a4SJacob Faibussowitsch {
1618814e85d6SHong Zhang   PetscFunctionBegin;
1619814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1620814e85d6SHong Zhang   PetscValidPointer(vp, 3);
1621814e85d6SHong Zhang   if (numfwdint) *numfwdint = ts->numcost;
1622814e85d6SHong Zhang   if (vp) *vp = ts->vecs_integral_sensip;
1623814e85d6SHong Zhang   PetscFunctionReturn(0);
1624814e85d6SHong Zhang }
1625814e85d6SHong Zhang 
1626814e85d6SHong Zhang /*@
1627814e85d6SHong Zhang   TSForwardStep - Compute the forward sensitivity for one time step.
1628814e85d6SHong Zhang 
1629c3339decSBarry Smith   Collective
1630814e85d6SHong Zhang 
16314165533cSJose E. Roman   Input Parameter:
1632814e85d6SHong Zhang . ts - time stepping context
1633814e85d6SHong Zhang 
1634814e85d6SHong Zhang   Level: advanced
1635814e85d6SHong Zhang 
1636814e85d6SHong Zhang   Notes:
1637bcf0153eSBarry Smith   This function cannot be called until `TSStep()` has been completed.
1638814e85d6SHong Zhang 
1639bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSForwardSetSensitivities()`, `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardSetUp()`
1640814e85d6SHong Zhang @*/
1641d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardStep(TS ts)
1642d71ae5a4SJacob Faibussowitsch {
1643362febeeSStefano Zampini   PetscFunctionBegin;
1644814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
16459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(TS_ForwardStep, ts, 0, 0, 0));
1646dbbe0bcdSBarry Smith   PetscUseTypeMethod(ts, forwardstep);
16479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(TS_ForwardStep, ts, 0, 0, 0));
16483c633725SBarry Smith   PetscCheck(ts->reason >= 0 || !ts->errorifstepfailed, PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSFowardStep has failed due to %s", TSConvergedReasons[ts->reason]);
1649814e85d6SHong Zhang   PetscFunctionReturn(0);
1650814e85d6SHong Zhang }
1651814e85d6SHong Zhang 
1652814e85d6SHong Zhang /*@
1653814e85d6SHong Zhang   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.
1654814e85d6SHong Zhang 
1655c3339decSBarry Smith   Logically Collective
1656814e85d6SHong Zhang 
1657814e85d6SHong Zhang   Input Parameters:
1658bcf0153eSBarry Smith + ts - the `TS` context obtained from `TSCreate()`
1659814e85d6SHong Zhang . nump - number of parameters
1660814e85d6SHong Zhang - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1661814e85d6SHong Zhang 
1662814e85d6SHong Zhang   Level: beginner
1663814e85d6SHong Zhang 
1664814e85d6SHong Zhang   Notes:
1665814e85d6SHong Zhang   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
1666bcf0153eSBarry Smith   This function turns on a flag to trigger `TSSolve()` to compute forward sensitivities automatically.
1667bcf0153eSBarry Smith   You must call this function before `TSSolve()`.
1668814e85d6SHong Zhang   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.
1669814e85d6SHong Zhang 
1670bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSForwardGetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1671814e85d6SHong Zhang @*/
1672d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardSetSensitivities(TS ts, PetscInt nump, Mat Smat)
1673d71ae5a4SJacob Faibussowitsch {
1674814e85d6SHong Zhang   PetscFunctionBegin;
1675814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1676814e85d6SHong Zhang   PetscValidHeaderSpecific(Smat, MAT_CLASSID, 3);
1677814e85d6SHong Zhang   ts->forward_solve = PETSC_TRUE;
1678b5b4017aSHong Zhang   if (nump == PETSC_DEFAULT) {
16799566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Smat, NULL, &ts->num_parameters));
1680b5b4017aSHong Zhang   } else ts->num_parameters = nump;
16819566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)Smat));
16829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ts->mat_sensip));
1683814e85d6SHong Zhang   ts->mat_sensip = Smat;
1684814e85d6SHong Zhang   PetscFunctionReturn(0);
1685814e85d6SHong Zhang }
1686814e85d6SHong Zhang 
1687814e85d6SHong Zhang /*@
1688814e85d6SHong Zhang   TSForwardGetSensitivities - Returns the trajectory sensitivities
1689814e85d6SHong Zhang 
1690bcf0153eSBarry Smith   Not Collective, but Smat returned is parallel if ts is parallel
1691814e85d6SHong Zhang 
1692d8d19677SJose E. Roman   Output Parameters:
1693bcf0153eSBarry Smith + ts - the `TS` context obtained from `TSCreate()`
1694814e85d6SHong Zhang . nump - number of parameters
1695814e85d6SHong Zhang - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters
1696814e85d6SHong Zhang 
1697814e85d6SHong Zhang   Level: intermediate
1698814e85d6SHong Zhang 
1699bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSForwardSetSensitivities()`, `TSForwardSetIntegralGradients()`, `TSForwardGetIntegralGradients()`, `TSForwardStep()`
1700814e85d6SHong Zhang @*/
1701d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardGetSensitivities(TS ts, PetscInt *nump, Mat *Smat)
1702d71ae5a4SJacob Faibussowitsch {
1703814e85d6SHong Zhang   PetscFunctionBegin;
1704814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1705814e85d6SHong Zhang   if (nump) *nump = ts->num_parameters;
1706814e85d6SHong Zhang   if (Smat) *Smat = ts->mat_sensip;
1707814e85d6SHong Zhang   PetscFunctionReturn(0);
1708814e85d6SHong Zhang }
1709814e85d6SHong Zhang 
1710814e85d6SHong Zhang /*@
1711814e85d6SHong Zhang    TSForwardCostIntegral - Evaluate the cost integral in the forward run.
1712814e85d6SHong Zhang 
1713c3339decSBarry Smith    Collective
1714814e85d6SHong Zhang 
17154165533cSJose E. Roman    Input Parameter:
1716814e85d6SHong Zhang .  ts - time stepping context
1717814e85d6SHong Zhang 
1718814e85d6SHong Zhang    Level: advanced
1719814e85d6SHong Zhang 
1720bcf0153eSBarry Smith    Note:
1721bcf0153eSBarry Smith    This function cannot be called until `TSStep()` has been completed.
1722814e85d6SHong Zhang 
1723bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSSolve()`, `TSAdjointCostIntegral()`
1724814e85d6SHong Zhang @*/
1725d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardCostIntegral(TS ts)
1726d71ae5a4SJacob Faibussowitsch {
1727362febeeSStefano Zampini   PetscFunctionBegin;
1728814e85d6SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1729dbbe0bcdSBarry Smith   PetscUseTypeMethod(ts, forwardintegral);
1730814e85d6SHong Zhang   PetscFunctionReturn(0);
1731814e85d6SHong Zhang }
1732b5b4017aSHong Zhang 
1733b5b4017aSHong Zhang /*@
1734b5b4017aSHong Zhang   TSForwardSetInitialSensitivities - Set initial values for tangent linear sensitivities
1735b5b4017aSHong Zhang 
1736c3339decSBarry Smith   Collective
1737b5b4017aSHong Zhang 
1738d8d19677SJose E. Roman   Input Parameters:
1739bcf0153eSBarry Smith + ts - the `TS` context obtained from `TSCreate()`
1740b5b4017aSHong Zhang - didp - parametric sensitivities of the initial condition
1741b5b4017aSHong Zhang 
1742b5b4017aSHong Zhang   Level: intermediate
1743b5b4017aSHong Zhang 
1744bcf0153eSBarry Smith   Notes:
1745bcf0153eSBarry Smith   `TSSolve()` allows users to pass the initial solution directly to `TS`. But the tangent linear variables cannot be initialized in this way.
1746bcf0153eSBarry Smith    This function is used to set initial values for tangent linear variables.
1747b5b4017aSHong Zhang 
1748bcf0153eSBarry Smith .seealso: [](chapter_ts), `TS`, `TSForwardSetSensitivities()`
1749b5b4017aSHong Zhang @*/
1750d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardSetInitialSensitivities(TS ts, Mat didp)
1751d71ae5a4SJacob Faibussowitsch {
1752362febeeSStefano Zampini   PetscFunctionBegin;
1753b5b4017aSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1754b5b4017aSHong Zhang   PetscValidHeaderSpecific(didp, MAT_CLASSID, 2);
175548a46eb9SPierre Jolivet   if (!ts->mat_sensip) PetscCall(TSForwardSetSensitivities(ts, PETSC_DEFAULT, didp));
1756b5b4017aSHong Zhang   PetscFunctionReturn(0);
1757b5b4017aSHong Zhang }
17586affb6f8SHong Zhang 
17596affb6f8SHong Zhang /*@
17606affb6f8SHong Zhang    TSForwardGetStages - Get the number of stages and the tangent linear sensitivities at the intermediate stages
17616affb6f8SHong Zhang 
17626affb6f8SHong Zhang    Input Parameter:
1763bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
17646affb6f8SHong Zhang 
17656affb6f8SHong Zhang    Output Parameters:
1766cd4cee2dSHong Zhang +  ns - number of stages
17676affb6f8SHong Zhang -  S - tangent linear sensitivities at the intermediate stages
17686affb6f8SHong Zhang 
17696affb6f8SHong Zhang    Level: advanced
17706affb6f8SHong Zhang 
1771bcf0153eSBarry Smith .seealso: `TS`
17726affb6f8SHong Zhang @*/
1773d71ae5a4SJacob Faibussowitsch PetscErrorCode TSForwardGetStages(TS ts, PetscInt *ns, Mat **S)
1774d71ae5a4SJacob Faibussowitsch {
17756affb6f8SHong Zhang   PetscFunctionBegin;
17766affb6f8SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
17776affb6f8SHong Zhang 
17786affb6f8SHong Zhang   if (!ts->ops->getstages) *S = NULL;
1779dbbe0bcdSBarry Smith   else PetscUseTypeMethod(ts, forwardgetstages, ns, S);
17806affb6f8SHong Zhang   PetscFunctionReturn(0);
17816affb6f8SHong Zhang }
1782cd4cee2dSHong Zhang 
1783cd4cee2dSHong Zhang /*@
1784bcf0153eSBarry Smith    TSCreateQuadratureTS - Create a sub-`TS` that evaluates integrals over time
1785cd4cee2dSHong Zhang 
1786d8d19677SJose E. Roman    Input Parameters:
1787bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
1788cd4cee2dSHong Zhang -  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
1789cd4cee2dSHong Zhang 
1790cd4cee2dSHong Zhang    Output Parameters:
1791bcf0153eSBarry Smith .  quadts - the child `TS` context
1792cd4cee2dSHong Zhang 
1793cd4cee2dSHong Zhang    Level: intermediate
1794cd4cee2dSHong Zhang 
1795bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSGetQuadratureTS()`
1796cd4cee2dSHong Zhang @*/
1797d71ae5a4SJacob Faibussowitsch PetscErrorCode TSCreateQuadratureTS(TS ts, PetscBool fwd, TS *quadts)
1798d71ae5a4SJacob Faibussowitsch {
1799cd4cee2dSHong Zhang   char prefix[128];
1800cd4cee2dSHong Zhang 
1801cd4cee2dSHong Zhang   PetscFunctionBegin;
1802cd4cee2dSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1803064a246eSJacob Faibussowitsch   PetscValidPointer(quadts, 3);
18049566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts->quadraturets));
18059566063dSJacob Faibussowitsch   PetscCall(TSCreate(PetscObjectComm((PetscObject)ts), &ts->quadraturets));
18069566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->quadraturets, (PetscObject)ts, 1));
18079566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%squad_", ((PetscObject)ts)->prefix ? ((PetscObject)ts)->prefix : ""));
18089566063dSJacob Faibussowitsch   PetscCall(TSSetOptionsPrefix(ts->quadraturets, prefix));
1809cd4cee2dSHong Zhang   *quadts = ts->quadraturets;
1810cd4cee2dSHong Zhang 
1811cd4cee2dSHong Zhang   if (ts->numcost) {
18129566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, ts->numcost, &(*quadts)->vec_sol));
1813cd4cee2dSHong Zhang   } else {
18149566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, 1, &(*quadts)->vec_sol));
1815cd4cee2dSHong Zhang   }
1816cd4cee2dSHong Zhang   ts->costintegralfwd = fwd;
1817cd4cee2dSHong Zhang   PetscFunctionReturn(0);
1818cd4cee2dSHong Zhang }
1819cd4cee2dSHong Zhang 
1820cd4cee2dSHong Zhang /*@
1821bcf0153eSBarry Smith    TSGetQuadratureTS - Return the sub-`TS` that evaluates integrals over time
1822cd4cee2dSHong Zhang 
1823cd4cee2dSHong Zhang    Input Parameter:
1824bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
1825cd4cee2dSHong Zhang 
1826cd4cee2dSHong Zhang    Output Parameters:
1827cd4cee2dSHong Zhang +  fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
1828bcf0153eSBarry Smith -  quadts - the child `TS` context
1829cd4cee2dSHong Zhang 
1830cd4cee2dSHong Zhang    Level: intermediate
1831cd4cee2dSHong Zhang 
1832bcf0153eSBarry Smith .seealso: [](chapter_ts), `TSCreateQuadratureTS()`
1833cd4cee2dSHong Zhang @*/
1834d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGetQuadratureTS(TS ts, PetscBool *fwd, TS *quadts)
1835d71ae5a4SJacob Faibussowitsch {
1836cd4cee2dSHong Zhang   PetscFunctionBegin;
1837cd4cee2dSHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1838cd4cee2dSHong Zhang   if (fwd) *fwd = ts->costintegralfwd;
1839cd4cee2dSHong Zhang   if (quadts) *quadts = ts->quadraturets;
1840cd4cee2dSHong Zhang   PetscFunctionReturn(0);
1841cd4cee2dSHong Zhang }
1842ba0675f6SHong Zhang 
1843ba0675f6SHong Zhang /*@
1844bcf0153eSBarry Smith    TSComputeSNESJacobian - Compute the Jacobian needed for the `SNESSolve()` in `TS`
1845bcf0153eSBarry Smith 
1846c3339decSBarry Smith    Collective
1847ba0675f6SHong Zhang 
1848ba0675f6SHong Zhang    Input Parameters:
1849bcf0153eSBarry Smith +  ts - the `TS` context obtained from `TSCreate()`
1850ba0675f6SHong Zhang -  x - state vector
1851ba0675f6SHong Zhang 
1852ba0675f6SHong Zhang    Output Parameters:
1853ba0675f6SHong Zhang +  J - Jacobian matrix
1854ba0675f6SHong Zhang -  Jpre - preconditioning matrix for J (may be same as J)
1855ba0675f6SHong Zhang 
1856ba0675f6SHong Zhang    Level: developer
1857ba0675f6SHong Zhang 
1858bcf0153eSBarry Smith    Note:
1859bcf0153eSBarry Smith    Uses finite differencing when `TS` Jacobian is not available.
1860bcf0153eSBarry Smith 
1861bcf0153eSBarry Smith .seealso: `SNES`, `TS`, `SNESSetJacobian()`, TSSetRHSJacobian()`, `TSSetIJacobian()`
1862ba0675f6SHong Zhang @*/
1863d71ae5a4SJacob Faibussowitsch PetscErrorCode TSComputeSNESJacobian(TS ts, Vec x, Mat J, Mat Jpre)
1864d71ae5a4SJacob Faibussowitsch {
1865ba0675f6SHong Zhang   SNES snes                                          = ts->snes;
1866ba0675f6SHong Zhang   PetscErrorCode (*jac)(SNES, Vec, Mat, Mat, void *) = NULL;
1867ba0675f6SHong Zhang 
1868ba0675f6SHong Zhang   PetscFunctionBegin;
1869ba0675f6SHong Zhang   /*
1870ba0675f6SHong Zhang     Unlike implicit methods, explicit methods do not have SNESMatFDColoring in the snes object
1871ba0675f6SHong Zhang     because SNESSolve() has not been called yet; so querying SNESMatFDColoring does not work for
1872ba0675f6SHong Zhang     explicit methods. Instead, we check the Jacobian compute function directly to determin if FD
1873ba0675f6SHong Zhang     coloring is used.
1874ba0675f6SHong Zhang   */
18759566063dSJacob Faibussowitsch   PetscCall(SNESGetJacobian(snes, NULL, NULL, &jac, NULL));
1876ba0675f6SHong Zhang   if (jac == SNESComputeJacobianDefaultColor) {
1877ba0675f6SHong Zhang     Vec f;
18789566063dSJacob Faibussowitsch     PetscCall(SNESSetSolution(snes, x));
18799566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
1880ba0675f6SHong Zhang     /* Force MatFDColoringApply to evaluate the SNES residual function for the base vector */
18819566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, x, f));
1882ba0675f6SHong Zhang   }
18839566063dSJacob Faibussowitsch   PetscCall(SNESComputeJacobian(snes, x, J, Jpre));
1884ba0675f6SHong Zhang   PetscFunctionReturn(0);
1885ba0675f6SHong Zhang }
1886