xref: /petsc/src/ts/interface/sensitivity/tssen.c (revision bcf0153e883cfed9568ef4557dcc209048fb58f7)
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 
13*bcf0153eSBarry Smith   Logically Collective on ts
14814e85d6SHong Zhang 
15814e85d6SHong Zhang   Input Parameters:
16*bcf0153eSBarry 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 
30*bcf0153eSBarry 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 
33*bcf0153eSBarry 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 
54*bcf0153eSBarry Smith   Logically Collective on ts
55cd4cee2dSHong Zhang 
56f899ff85SJose E. Roman   Input Parameter:
57*bcf0153eSBarry 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 
73*bcf0153eSBarry 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 
76*bcf0153eSBarry 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 
90*bcf0153eSBarry Smith   Collective on ts
91814e85d6SHong Zhang 
92814e85d6SHong Zhang   Input Parameters:
93*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
94814e85d6SHong Zhang 
95814e85d6SHong Zhang   Level: developer
96814e85d6SHong Zhang 
97*bcf0153eSBarry 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 
113*bcf0153eSBarry Smith   Logically Collective on ts
11433f72c5dSHong Zhang 
11533f72c5dSHong Zhang   Input Parameters:
116*bcf0153eSBarry 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 
132*bcf0153eSBarry 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 
135*bcf0153eSBarry 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 
156*bcf0153eSBarry Smith   Collective on ts
15733f72c5dSHong Zhang 
15833f72c5dSHong Zhang   Input Parameters:
159*bcf0153eSBarry 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 
171*bcf0153eSBarry 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 
212*bcf0153eSBarry Smith     Logically Collective on ts
213814e85d6SHong Zhang 
214814e85d6SHong Zhang     Input Parameters:
215*bcf0153eSBarry 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 
235*bcf0153eSBarry 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 
238*bcf0153eSBarry 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:
279*bcf0153eSBarry 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 
286*bcf0153eSBarry 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:
304*bcf0153eSBarry 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 
311*bcf0153eSBarry Smith    Level: deprecated
312*bcf0153eSBarry Smith 
313*bcf0153eSBarry 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 
317*bcf0153eSBarry 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
334*bcf0153eSBarry 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
351*bcf0153eSBarry 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 
370*bcf0153eSBarry Smith   Logically Collective on ts
371b5b4017aSHong Zhang 
372b5b4017aSHong Zhang   Input Parameters:
373*bcf0153eSBarry 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 
405*bcf0153eSBarry 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 
428*bcf0153eSBarry Smith   Collective on ts
429b5b4017aSHong Zhang 
430b5b4017aSHong Zhang   Input Parameters:
431*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
432b5b4017aSHong Zhang 
433b5b4017aSHong Zhang   Level: developer
434b5b4017aSHong Zhang 
435*bcf0153eSBarry Smith   Note:
436*bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionUU()` is typically used for sensitivity implementation,
437*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
438*bcf0153eSBarry Smith 
439*bcf0153eSBarry 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 
462*bcf0153eSBarry Smith   Collective on ts
463b5b4017aSHong Zhang 
464b5b4017aSHong Zhang   Input Parameters:
465*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
466b5b4017aSHong Zhang 
467b5b4017aSHong Zhang   Level: developer
468b5b4017aSHong Zhang 
469*bcf0153eSBarry Smith   Note:
470*bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionUP()` is typically used for sensitivity implementation,
471*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
472*bcf0153eSBarry Smith 
473*bcf0153eSBarry 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 
496*bcf0153eSBarry Smith   Collective on ts
497b5b4017aSHong Zhang 
498b5b4017aSHong Zhang   Input Parameters:
499*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
500b5b4017aSHong Zhang 
501b5b4017aSHong Zhang   Level: developer
502b5b4017aSHong Zhang 
503*bcf0153eSBarry Smith   Note:
504*bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionPU()` is typically used for sensitivity implementation,
505*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
506*bcf0153eSBarry Smith 
507*bcf0153eSBarry 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 
530*bcf0153eSBarry Smith   Collective on ts
531b5b4017aSHong Zhang 
532b5b4017aSHong Zhang   Input Parameters:
533*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
534b5b4017aSHong Zhang 
535b5b4017aSHong Zhang   Level: developer
536b5b4017aSHong Zhang 
537*bcf0153eSBarry Smith   Note:
538*bcf0153eSBarry Smith   `TSComputeIHessianProductFunctionPP()` is typically used for sensitivity implementation,
539*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
540*bcf0153eSBarry Smith 
541*bcf0153eSBarry 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 
564*bcf0153eSBarry Smith   Logically Collective on ts
56513af1a74SHong Zhang 
56613af1a74SHong Zhang   Input Parameters:
567*bcf0153eSBarry 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 
599*bcf0153eSBarry 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 
622*bcf0153eSBarry Smith   Collective on ts
62313af1a74SHong Zhang 
62413af1a74SHong Zhang   Input Parameters:
625*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
62613af1a74SHong Zhang 
62713af1a74SHong Zhang   Level: developer
62813af1a74SHong Zhang 
629*bcf0153eSBarry Smith   Note:
630*bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionUU()` is typically used for sensitivity implementation,
631*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
632*bcf0153eSBarry Smith 
633*bcf0153eSBarry 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 
649*bcf0153eSBarry Smith   Collective on ts
65013af1a74SHong Zhang 
65113af1a74SHong Zhang   Input Parameters:
652*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
65313af1a74SHong Zhang 
65413af1a74SHong Zhang   Level: developer
65513af1a74SHong Zhang 
656*bcf0153eSBarry Smith   Note:
657*bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionUP()` is typically used for sensitivity implementation,
658*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
659*bcf0153eSBarry Smith 
660*bcf0153eSBarry 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 
676*bcf0153eSBarry Smith   Collective on ts
67713af1a74SHong Zhang 
67813af1a74SHong Zhang   Input Parameters:
679*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
68013af1a74SHong Zhang 
68113af1a74SHong Zhang   Level: developer
68213af1a74SHong Zhang 
683*bcf0153eSBarry Smith   Note:
684*bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionPU()` is typically used for sensitivity implementation,
685*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
686*bcf0153eSBarry Smith 
687*bcf0153eSBarry 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 
703*bcf0153eSBarry Smith   Collective on ts
70413af1a74SHong Zhang 
70513af1a74SHong Zhang   Input Parameters:
706*bcf0153eSBarry Smith . ts   - The `TS` context obtained from `TSCreate()`
70713af1a74SHong Zhang 
70813af1a74SHong Zhang   Level: developer
70913af1a74SHong Zhang 
710*bcf0153eSBarry Smith   Note:
711*bcf0153eSBarry Smith   `TSComputeRHSHessianProductFunctionPP()` is typically used for sensitivity implementation,
712*bcf0153eSBarry Smith   so most users would not generally call this routine themselves.
713*bcf0153eSBarry Smith 
714*bcf0153eSBarry 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
731*bcf0153eSBarry Smith       for use by the `TS` adjoint routines.
732814e85d6SHong Zhang 
733*bcf0153eSBarry Smith    Logically Collective on ts
734814e85d6SHong Zhang 
735814e85d6SHong Zhang    Input Parameters:
736*bcf0153eSBarry 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:
744814e85d6SHong Zhang     the entries in these vectors must be correctly initialized with the values lamda_i = df/dy|finaltime  mu_i = df/dp|finaltime
745814e85d6SHong Zhang 
746*bcf0153eSBarry Smith    After `TSAdjointSolve()` is called the lamba and the mu contain the computed sensitivities
747814e85d6SHong Zhang 
748*bcf0153eSBarry 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 /*@
763*bcf0153eSBarry Smith    TSGetCostGradients - Returns the gradients from the `TSAdjointSolve()`
764814e85d6SHong Zhang 
765*bcf0153eSBarry Smith    Not Collective, but the vectors returned are parallel if `TS` is parallel
766814e85d6SHong Zhang 
767814e85d6SHong Zhang    Input Parameter:
768*bcf0153eSBarry 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 
777*bcf0153eSBarry 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
791*bcf0153eSBarry Smith    for use by the `TS` adjoint routines.
792b5b4017aSHong Zhang 
793*bcf0153eSBarry Smith    Logically Collective on ts
794b5b4017aSHong Zhang 
795b5b4017aSHong Zhang    Input Parameters:
796*bcf0153eSBarry 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 
804*bcf0153eSBarry Smith    Notes:
805*bcf0153eSBarry Smith    Hessian of the cost function is completely different from Hessian of the ODE/DAE system
806b5b4017aSHong Zhang 
807*bcf0153eSBarry Smith    For second-order adjoint, one needs to call this function and then `TSAdjointSetForward()` before `TSSolve()`.
808b5b4017aSHong Zhang 
809*bcf0153eSBarry Smith    After `TSAdjointSolve()` is called, the lamba2 and the mu2 will contain the computed second-order adjoint sensitivities, and can be used to produce Hessian-vector product (not the full Hessian matrix). Users must provide a direction vector; it is usually generated by an optimization solver.
810b5b4017aSHong Zhang 
8113fca9621SHong Zhang    Passing NULL for lambda2 disables the second-order calculation.
812*bcf0153eSBarry Smith 
813*bcf0153eSBarry 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 /*@
828*bcf0153eSBarry Smith    TSGetCostHessianProducts - Returns the gradients from the `TSAdjointSolve()`
829b5b4017aSHong Zhang 
830*bcf0153eSBarry Smith    Not Collective, but vectors returned are parallel if `TS` is parallel
831b5b4017aSHong Zhang 
832b5b4017aSHong Zhang    Input Parameter:
833*bcf0153eSBarry 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 
843*bcf0153eSBarry 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 
859*bcf0153eSBarry Smith   Logically Collective on ts
860b5b4017aSHong Zhang 
861b5b4017aSHong Zhang   Input Parameters:
862*bcf0153eSBarry 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 
867*bcf0153eSBarry Smith   Notes:
868*bcf0153eSBarry 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.
869*bcf0153eSBarry Smith   `TS` adjoint does not reset the tangent linear solver automatically, `TSAdjointResetForward()` should be called to reset the tangent linear solver.
870b5b4017aSHong Zhang 
871*bcf0153eSBarry 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 
914*bcf0153eSBarry Smith   Logically Collective on ts
915ecf68647SHong Zhang 
916ecf68647SHong Zhang   Input Parameters:
917*bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
918ecf68647SHong Zhang 
919ecf68647SHong Zhang   Level: intermediate
920ecf68647SHong Zhang 
921*bcf0153eSBarry 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 
935*bcf0153eSBarry Smith    Collective on ts
936814e85d6SHong Zhang 
937814e85d6SHong Zhang    Input Parameter:
938*bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
939814e85d6SHong Zhang 
940814e85d6SHong Zhang    Level: advanced
941814e85d6SHong Zhang 
942*bcf0153eSBarry 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 /*@
974*bcf0153eSBarry Smith   TSAdjointReset - Resets a `TS` adjoint context and removes any allocated `Vec`s and `Mat`s.
975ece46509SHong Zhang 
976*bcf0153eSBarry Smith    Collective on ts
977ece46509SHong Zhang 
978ece46509SHong Zhang    Input Parameter:
979*bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
980ece46509SHong Zhang 
981ece46509SHong Zhang    Level: beginner
982ece46509SHong Zhang 
983*bcf0153eSBarry 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 
1006*bcf0153eSBarry Smith    Logically Collective on ts
1007814e85d6SHong Zhang 
1008814e85d6SHong Zhang    Input Parameters:
1009*bcf0153eSBarry 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:
1015*bcf0153eSBarry 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 
1018*bcf0153eSBarry 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
1032*bcf0153eSBarry 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
1054*bcf0153eSBarry 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 /*@
1071*bcf0153eSBarry 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 /*@
1087*bcf0153eSBarry 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 
1107*bcf0153eSBarry 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 
1124*bcf0153eSBarry Smith    Collective on ts
1125814e85d6SHong Zhang 
1126814e85d6SHong Zhang    Input Parameters:
1127*bcf0153eSBarry 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
1132*bcf0153eSBarry 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 
1136*bcf0153eSBarry 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 
1166*bcf0153eSBarry Smith    Logically Collective on ts
1167814e85d6SHong Zhang 
1168814e85d6SHong Zhang    Input Parameters:
1169*bcf0153eSBarry 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 
1179*bcf0153eSBarry 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 
1189*bcf0153eSBarry Smith    Level: intermediate
1190*bcf0153eSBarry Smith 
1191*bcf0153eSBarry Smith    Note:
1192814e85d6SHong Zhang    This routine adds an additional monitor to the list of monitors that
1193814e85d6SHong Zhang    already has been loaded.
1194814e85d6SHong Zhang 
1195*bcf0153eSBarry Smith    Fortran Note:
1196814e85d6SHong Zhang    Only a single monitor function can be set for each TS object
1197814e85d6SHong Zhang 
1198*bcf0153eSBarry 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 
1221*bcf0153eSBarry Smith    Logically Collective on ts
1222814e85d6SHong Zhang 
1223814e85d6SHong Zhang    Input Parameters:
1224*bcf0153eSBarry 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 
1231*bcf0153eSBarry 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 
1251*bcf0153eSBarry 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
1268*bcf0153eSBarry Smith    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint `TS` solvers by calling
1269*bcf0153eSBarry Smith    `VecView()` for the sensitivities to initial states at each timestep
1270814e85d6SHong Zhang 
1271*bcf0153eSBarry Smith    Collective on ts
1272814e85d6SHong Zhang 
1273814e85d6SHong Zhang    Input Parameters:
1274*bcf0153eSBarry 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 
1285*bcf0153eSBarry 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 /*
1308*bcf0153eSBarry Smith    TSAdjointSetFromOptions - Sets various `TS` adjoint parameters from user options.
1309814e85d6SHong Zhang 
1310*bcf0153eSBarry Smith    Collective on ts
1311814e85d6SHong Zhang 
1312814e85d6SHong Zhang    Input Parameter:
1313*bcf0153eSBarry 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 
1322*bcf0153eSBarry Smith    Note:
1323814e85d6SHong Zhang     This is not normally called directly by users
1324814e85d6SHong Zhang 
1325*bcf0153eSBarry 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 
1358*bcf0153eSBarry Smith    Collective on ts
1359814e85d6SHong Zhang 
1360814e85d6SHong Zhang    Input Parameter:
1361*bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
1362814e85d6SHong Zhang 
1363814e85d6SHong Zhang    Level: intermediate
1364814e85d6SHong Zhang 
1365*bcf0153eSBarry 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 
1395*bcf0153eSBarry Smith    Collective on ts
1396*bcf0153eSBarry Smith `
1397814e85d6SHong Zhang    Input Parameter:
1398*bcf0153eSBarry Smith .  ts - the `TS` context obtained from `TSCreate()`
1399814e85d6SHong Zhang 
1400*bcf0153eSBarry 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:
1406*bcf0153eSBarry Smith    This must be called after a call to `TSSolve()` that solves the forward problem
1407814e85d6SHong Zhang 
1408*bcf0153eSBarry Smith    By default this will integrate back to the initial time, one can use `TSAdjointSetSteps()` to step back to a later time
1409814e85d6SHong Zhang 
1410*bcf0153eSBarry 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
1470*bcf0153eSBarry Smith    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using `TSAdjointMonitorSet()`
1471814e85d6SHong Zhang 
1472*bcf0153eSBarry Smith    Collective on ts
1473814e85d6SHong Zhang 
1474814e85d6SHong Zhang    Input Parameters:
1475*bcf0153eSBarry 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 
1485*bcf0153eSBarry Smith    Note:
1486*bcf0153eSBarry Smith    `TSAdjointMonitor()` is typically used automatically within the time stepping implementations.
1487*bcf0153eSBarry Smith    Users would almost never call this routine directly.
1488*bcf0153eSBarry Smith 
1489*bcf0153eSBarry 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 
1507*bcf0153eSBarry Smith  Collective on ts
1508814e85d6SHong Zhang 
15094165533cSJose E. Roman  Input Parameter:
1510814e85d6SHong Zhang  .  ts - time stepping context
1511814e85d6SHong Zhang 
1512814e85d6SHong Zhang  Level: advanced
1513814e85d6SHong Zhang 
1514814e85d6SHong Zhang  Notes:
1515*bcf0153eSBarry Smith  This function cannot be called until `TSAdjointStep()` has been completed.
1516814e85d6SHong Zhang 
1517*bcf0153eSBarry 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 
1533*bcf0153eSBarry Smith   Collective on ts
1534814e85d6SHong Zhang 
1535814e85d6SHong Zhang   Input Parameter:
1536*bcf0153eSBarry Smith . ts - the `TS` context obtained from `TSCreate()`
1537814e85d6SHong Zhang 
1538814e85d6SHong Zhang   Level: advanced
1539814e85d6SHong Zhang 
1540*bcf0153eSBarry 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 
1556*bcf0153eSBarry Smith   Collective on ts
15577adebddeSHong Zhang 
15587adebddeSHong Zhang   Input Parameter:
1559*bcf0153eSBarry Smith . ts - the `TS` context obtained from `TSCreate()`
15607adebddeSHong Zhang 
15617adebddeSHong Zhang   Level: advanced
15627adebddeSHong Zhang 
1563*bcf0153eSBarry 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:
1584*bcf0153eSBarry 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 
1590*bcf0153eSBarry 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:
1607*bcf0153eSBarry 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 
1614*bcf0153eSBarry 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 
1629*bcf0153eSBarry Smith   Collective on ts
1630814e85d6SHong Zhang 
16314165533cSJose E. Roman   Input Parameter:
1632814e85d6SHong Zhang . ts - time stepping context
1633814e85d6SHong Zhang 
1634814e85d6SHong Zhang   Level: advanced
1635814e85d6SHong Zhang 
1636814e85d6SHong Zhang   Notes:
1637*bcf0153eSBarry Smith   This function cannot be called until `TSStep()` has been completed.
1638814e85d6SHong Zhang 
1639*bcf0153eSBarry 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 
1655*bcf0153eSBarry Smith   Logically Collective on ts
1656814e85d6SHong Zhang 
1657814e85d6SHong Zhang   Input Parameters:
1658*bcf0153eSBarry 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.
1666*bcf0153eSBarry Smith   This function turns on a flag to trigger `TSSolve()` to compute forward sensitivities automatically.
1667*bcf0153eSBarry 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 
1670*bcf0153eSBarry 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 
1690*bcf0153eSBarry Smith   Not Collective, but Smat returned is parallel if ts is parallel
1691814e85d6SHong Zhang 
1692d8d19677SJose E. Roman   Output Parameters:
1693*bcf0153eSBarry 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 
1699*bcf0153eSBarry 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 
1713*bcf0153eSBarry Smith    Collective on ts
1714814e85d6SHong Zhang 
17154165533cSJose E. Roman    Input Parameter:
1716814e85d6SHong Zhang .  ts - time stepping context
1717814e85d6SHong Zhang 
1718814e85d6SHong Zhang    Level: advanced
1719814e85d6SHong Zhang 
1720*bcf0153eSBarry Smith    Note:
1721*bcf0153eSBarry Smith    This function cannot be called until `TSStep()` has been completed.
1722814e85d6SHong Zhang 
1723*bcf0153eSBarry 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 
1736*bcf0153eSBarry Smith   Collective on ts
1737b5b4017aSHong Zhang 
1738d8d19677SJose E. Roman   Input Parameters:
1739*bcf0153eSBarry 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 
1744*bcf0153eSBarry Smith   Notes:
1745*bcf0153eSBarry Smith   `TSSolve()` allows users to pass the initial solution directly to `TS`. But the tangent linear variables cannot be initialized in this way.
1746*bcf0153eSBarry Smith    This function is used to set initial values for tangent linear variables.
1747b5b4017aSHong Zhang 
1748*bcf0153eSBarry 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:
1763*bcf0153eSBarry 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 
1771*bcf0153eSBarry 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 /*@
1784*bcf0153eSBarry Smith    TSCreateQuadratureTS - Create a sub-`TS` that evaluates integrals over time
1785cd4cee2dSHong Zhang 
1786d8d19677SJose E. Roman    Input Parameters:
1787*bcf0153eSBarry 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:
1791*bcf0153eSBarry Smith .  quadts - the child `TS` context
1792cd4cee2dSHong Zhang 
1793cd4cee2dSHong Zhang    Level: intermediate
1794cd4cee2dSHong Zhang 
1795*bcf0153eSBarry 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 /*@
1821*bcf0153eSBarry Smith    TSGetQuadratureTS - Return the sub-`TS` that evaluates integrals over time
1822cd4cee2dSHong Zhang 
1823cd4cee2dSHong Zhang    Input Parameter:
1824*bcf0153eSBarry 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
1828*bcf0153eSBarry Smith -  quadts - the child `TS` context
1829cd4cee2dSHong Zhang 
1830cd4cee2dSHong Zhang    Level: intermediate
1831cd4cee2dSHong Zhang 
1832*bcf0153eSBarry 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 /*@
1844*bcf0153eSBarry Smith    TSComputeSNESJacobian - Compute the Jacobian needed for the `SNESSolve()` in `TS`
1845*bcf0153eSBarry Smith 
1846*bcf0153eSBarry Smith    Collective on ts
1847ba0675f6SHong Zhang 
1848ba0675f6SHong Zhang    Input Parameters:
1849*bcf0153eSBarry 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 
1858*bcf0153eSBarry Smith    Note:
1859*bcf0153eSBarry Smith    Uses finite differencing when `TS` Jacobian is not available.
1860*bcf0153eSBarry Smith 
1861*bcf0153eSBarry 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