xref: /petsc/src/ts/interface/ts.c (revision b43aa488f900e1fa15f896f863d5deacb647a378)
1 #include <petsc/private/tsimpl.h> /*I "petscts.h"  I*/
2 #include <petscdmda.h>
3 #include <petscdmshell.h>
4 #include <petscdmplex.h>  // For TSSetFromOptions()
5 #include <petscdmswarm.h> // For TSSetFromOptions()
6 #include <petscviewer.h>
7 #include <petscdraw.h>
8 #include <petscconvest.h>
9 
10 /* Logging support */
11 PetscClassId  TS_CLASSID, DMTS_CLASSID;
12 PetscLogEvent TS_Step, TS_PseudoComputeTimeStep, TS_FunctionEval, TS_JacobianEval;
13 
14 const char *const TSExactFinalTimeOptions[] = {"UNSPECIFIED", "STEPOVER", "INTERPOLATE", "MATCHSTEP", "TSExactFinalTimeOption", "TS_EXACTFINALTIME_", NULL};
15 
16 static PetscErrorCode TSAdaptSetDefaultType(TSAdapt adapt, TSAdaptType default_type)
17 {
18   PetscFunctionBegin;
19   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
20   PetscValidCharPointer(default_type, 2);
21   if (!((PetscObject)adapt)->type_name) PetscCall(TSAdaptSetType(adapt, default_type));
22   PetscFunctionReturn(PETSC_SUCCESS);
23 }
24 
25 /*@
26   TSSetFromOptions - Sets various `TS` parameters from the options database
27 
28   Collective
29 
30   Input Parameter:
31 . ts - the `TS` context obtained from `TSCreate()`
32 
33   Options Database Keys:
34 + -ts_type <type>                                                    - EULER, BEULER, SUNDIALS, PSEUDO, CN, RK, THETA, ALPHA, GLLE,  SSP, GLEE, BSYMP, IRK, see `TSType`
35 . -ts_save_trajectory                                                - checkpoint the solution at each time-step
36 . -ts_max_time <time>                                                - maximum time to compute to
37 . -ts_time_span <t0,...tf>                                           - sets the time span, solutions are computed and stored for each indicated time
38 . -ts_max_steps <steps>                                              - maximum number of time-steps to take
39 . -ts_init_time <time>                                               - initial time to start computation
40 . -ts_final_time <time>                                              - final time to compute to (deprecated: use `-ts_max_time`)
41 . -ts_dt <dt>                                                        - initial time step
42 . -ts_exact_final_time <stepover,interpolate,matchstep>              - whether to stop at the exact given final time and how to compute the solution at that time
43 . -ts_max_snes_failures <maxfailures>                                - Maximum number of nonlinear solve failures allowed
44 . -ts_max_reject <maxrejects>                                        - Maximum number of step rejections before step fails
45 . -ts_error_if_step_fails <true,false>                               - Error if no step succeeds
46 . -ts_rtol <rtol>                                                    - relative tolerance for local truncation error
47 . -ts_atol <atol>                                                    - Absolute tolerance for local truncation error
48 . -ts_rhs_jacobian_test_mult -mat_shell_test_mult_view               - test the Jacobian at each iteration against finite difference with RHS function
49 . -ts_rhs_jacobian_test_mult_transpose                               - test the Jacobian at each iteration against finite difference with RHS function
50 . -ts_adjoint_solve <yes,no>                                         - After solving the ODE/DAE solve the adjoint problem (requires `-ts_save_trajectory`)
51 . -ts_fd_color                                                       - Use finite differences with coloring to compute IJacobian
52 . -ts_monitor                                                        - print information at each timestep
53 . -ts_monitor_cancel                                                 - Cancel all monitors
54 . -ts_monitor_lg_solution                                            - Monitor solution graphically
55 . -ts_monitor_lg_error                                               - Monitor error graphically
56 . -ts_monitor_error                                                  - Monitors norm of error
57 . -ts_monitor_lg_timestep                                            - Monitor timestep size graphically
58 . -ts_monitor_lg_timestep_log                                        - Monitor log timestep size graphically
59 . -ts_monitor_lg_snes_iterations                                     - Monitor number nonlinear iterations for each timestep graphically
60 . -ts_monitor_lg_ksp_iterations                                      - Monitor number nonlinear iterations for each timestep graphically
61 . -ts_monitor_sp_eig                                                 - Monitor eigenvalues of linearized operator graphically
62 . -ts_monitor_draw_solution                                          - Monitor solution graphically
63 . -ts_monitor_draw_solution_phase  <xleft,yleft,xright,yright>       - Monitor solution graphically with phase diagram, requires problem with exactly 2 degrees of freedom
64 . -ts_monitor_draw_error                                             - Monitor error graphically, requires use to have provided TSSetSolutionFunction()
65 . -ts_monitor_solution [ascii binary draw][:filename][:viewerformat] - monitors the solution at each timestep
66 . -ts_monitor_solution_interval <interval>                           - output once every interval (default=1) time steps
67 . -ts_monitor_solution_vtk <filename.vts,filename.vtu>               - Save each time step to a binary file, use filename-%%03" PetscInt_FMT ".vts (filename-%%03" PetscInt_FMT ".vtu)
68 - -ts_monitor_envelope                                               - determine maximum and minimum value of each component of the solution over the solution time
69 
70   Level: beginner
71 
72   Notes:
73   See `SNESSetFromOptions()` and `KSPSetFromOptions()` for how to control the nonlinear and linear solves used by the time-stepper.
74 
75   Certain `SNES` options get reset for each new nonlinear solver, for example `-snes_lag_jacobian its` and `-snes_lag_preconditioner its`, in order
76   to retain them over the multiple nonlinear solves that `TS` uses you mush also provide `-snes_lag_jacobian_persists true` and
77   `-snes_lag_preconditioner_persists true`
78 
79   Developer Notes:
80   We should unify all the -ts_monitor options in the way that -xxx_view has been unified
81 
82 .seealso: [](ch_ts), `TS`, `TSGetType()`
83 @*/
84 PetscErrorCode TSSetFromOptions(TS ts)
85 {
86   PetscBool              opt, flg, tflg;
87   char                   monfilename[PETSC_MAX_PATH_LEN];
88   PetscReal              time_step, tspan[100];
89   PetscInt               nt = PETSC_STATIC_ARRAY_LENGTH(tspan);
90   TSExactFinalTimeOption eftopt;
91   char                   dir[16];
92   TSIFunction            ifun;
93   const char            *defaultType;
94   char                   typeName[256];
95 
96   PetscFunctionBegin;
97   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
98 
99   PetscCall(TSRegisterAll());
100   PetscCall(TSGetIFunction(ts, NULL, &ifun, NULL));
101 
102   PetscObjectOptionsBegin((PetscObject)ts);
103   if (((PetscObject)ts)->type_name) defaultType = ((PetscObject)ts)->type_name;
104   else defaultType = ifun ? TSBEULER : TSEULER;
105   PetscCall(PetscOptionsFList("-ts_type", "TS method", "TSSetType", TSList, defaultType, typeName, 256, &opt));
106   if (opt) PetscCall(TSSetType(ts, typeName));
107   else PetscCall(TSSetType(ts, defaultType));
108 
109   /* Handle generic TS options */
110   PetscCall(PetscOptionsDeprecated("-ts_final_time", "-ts_max_time", "3.10", NULL));
111   PetscCall(PetscOptionsReal("-ts_max_time", "Maximum time to run to", "TSSetMaxTime", ts->max_time, &ts->max_time, NULL));
112   PetscCall(PetscOptionsRealArray("-ts_time_span", "Time span", "TSSetTimeSpan", tspan, &nt, &flg));
113   if (flg) PetscCall(TSSetTimeSpan(ts, nt, tspan));
114   PetscCall(PetscOptionsInt("-ts_max_steps", "Maximum number of time steps", "TSSetMaxSteps", ts->max_steps, &ts->max_steps, NULL));
115   PetscCall(PetscOptionsReal("-ts_init_time", "Initial time", "TSSetTime", ts->ptime, &ts->ptime, NULL));
116   PetscCall(PetscOptionsReal("-ts_dt", "Initial time step", "TSSetTimeStep", ts->time_step, &time_step, &flg));
117   if (flg) PetscCall(TSSetTimeStep(ts, time_step));
118   PetscCall(PetscOptionsEnum("-ts_exact_final_time", "Option for handling of final time step", "TSSetExactFinalTime", TSExactFinalTimeOptions, (PetscEnum)ts->exact_final_time, (PetscEnum *)&eftopt, &flg));
119   if (flg) PetscCall(TSSetExactFinalTime(ts, eftopt));
120   PetscCall(PetscOptionsInt("-ts_max_snes_failures", "Maximum number of nonlinear solve failures", "TSSetMaxSNESFailures", ts->max_snes_failures, &ts->max_snes_failures, NULL));
121   PetscCall(PetscOptionsInt("-ts_max_reject", "Maximum number of step rejections before step fails", "TSSetMaxStepRejections", ts->max_reject, &ts->max_reject, NULL));
122   PetscCall(PetscOptionsBool("-ts_error_if_step_fails", "Error if no step succeeds", "TSSetErrorIfStepFails", ts->errorifstepfailed, &ts->errorifstepfailed, NULL));
123   PetscCall(PetscOptionsReal("-ts_rtol", "Relative tolerance for local truncation error", "TSSetTolerances", ts->rtol, &ts->rtol, NULL));
124   PetscCall(PetscOptionsReal("-ts_atol", "Absolute tolerance for local truncation error", "TSSetTolerances", ts->atol, &ts->atol, NULL));
125 
126   PetscCall(PetscOptionsBool("-ts_rhs_jacobian_test_mult", "Test the RHS Jacobian for consistency with RHS at each solve ", "None", ts->testjacobian, &ts->testjacobian, NULL));
127   PetscCall(PetscOptionsBool("-ts_rhs_jacobian_test_mult_transpose", "Test the RHS Jacobian transpose for consistency with RHS at each solve ", "None", ts->testjacobiantranspose, &ts->testjacobiantranspose, NULL));
128   PetscCall(PetscOptionsBool("-ts_use_splitrhsfunction", "Use the split RHS function for multirate solvers ", "TSSetUseSplitRHSFunction", ts->use_splitrhsfunction, &ts->use_splitrhsfunction, NULL));
129 #if defined(PETSC_HAVE_SAWS)
130   {
131     PetscBool set;
132     flg = PETSC_FALSE;
133     PetscCall(PetscOptionsBool("-ts_saws_block", "Block for SAWs memory snooper at end of TSSolve", "PetscObjectSAWsBlock", ((PetscObject)ts)->amspublishblock, &flg, &set));
134     if (set) PetscCall(PetscObjectSAWsSetBlock((PetscObject)ts, flg));
135   }
136 #endif
137 
138   /* Monitor options */
139   PetscCall(PetscOptionsInt("-ts_monitor_frequency", "Number of time steps between monitor output", "TSMonitorSetFrequency", ts->monitorFrequency, &ts->monitorFrequency, NULL));
140   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor", "Monitor time and timestep size", "TSMonitorDefault", TSMonitorDefault, NULL));
141   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_extreme", "Monitor extreme values of the solution", "TSMonitorExtreme", TSMonitorExtreme, NULL));
142   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_solution", "View the solution at each timestep", "TSMonitorSolution", TSMonitorSolution, NULL));
143   PetscCall(TSMonitorSetFromOptions(ts, "-ts_dmswarm_monitor_moments", "Monitor moments of particle distribution", "TSDMSwarmMonitorMoments", TSDMSwarmMonitorMoments, NULL));
144 
145   PetscCall(PetscOptionsString("-ts_monitor_python", "Use Python function", "TSMonitorSet", NULL, monfilename, sizeof(monfilename), &flg));
146   if (flg) PetscCall(PetscPythonMonitorSet((PetscObject)ts, monfilename));
147 
148   PetscCall(PetscOptionsName("-ts_monitor_lg_solution", "Monitor solution graphically", "TSMonitorLGSolution", &opt));
149   if (opt) {
150     PetscInt  howoften = 1;
151     DM        dm;
152     PetscBool net;
153 
154     PetscCall(PetscOptionsInt("-ts_monitor_lg_solution", "Monitor solution graphically", "TSMonitorLGSolution", howoften, &howoften, NULL));
155     PetscCall(TSGetDM(ts, &dm));
156     PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMNETWORK, &net));
157     if (net) {
158       TSMonitorLGCtxNetwork ctx;
159       PetscCall(TSMonitorLGCtxNetworkCreate(ts, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 600, 400, howoften, &ctx));
160       PetscCall(TSMonitorSet(ts, TSMonitorLGCtxNetworkSolution, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxNetworkDestroy));
161       PetscCall(PetscOptionsBool("-ts_monitor_lg_solution_semilogy", "Plot the solution with a semi-log axis", "", ctx->semilogy, &ctx->semilogy, NULL));
162     } else {
163       TSMonitorLGCtx ctx;
164       PetscCall(TSMonitorLGCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
165       PetscCall(TSMonitorSet(ts, TSMonitorLGSolution, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxDestroy));
166     }
167   }
168 
169   PetscCall(PetscOptionsName("-ts_monitor_lg_error", "Monitor error graphically", "TSMonitorLGError", &opt));
170   if (opt) {
171     TSMonitorLGCtx ctx;
172     PetscInt       howoften = 1;
173 
174     PetscCall(PetscOptionsInt("-ts_monitor_lg_error", "Monitor error graphically", "TSMonitorLGError", howoften, &howoften, NULL));
175     PetscCall(TSMonitorLGCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
176     PetscCall(TSMonitorSet(ts, TSMonitorLGError, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxDestroy));
177   }
178   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_error", "View the error at each timestep", "TSMonitorError", TSMonitorError, NULL));
179 
180   PetscCall(PetscOptionsName("-ts_monitor_lg_timestep", "Monitor timestep size graphically", "TSMonitorLGTimeStep", &opt));
181   if (opt) {
182     TSMonitorLGCtx ctx;
183     PetscInt       howoften = 1;
184 
185     PetscCall(PetscOptionsInt("-ts_monitor_lg_timestep", "Monitor timestep size graphically", "TSMonitorLGTimeStep", howoften, &howoften, NULL));
186     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
187     PetscCall(TSMonitorSet(ts, TSMonitorLGTimeStep, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxDestroy));
188   }
189   PetscCall(PetscOptionsName("-ts_monitor_lg_timestep_log", "Monitor log timestep size graphically", "TSMonitorLGTimeStep", &opt));
190   if (opt) {
191     TSMonitorLGCtx ctx;
192     PetscInt       howoften = 1;
193 
194     PetscCall(PetscOptionsInt("-ts_monitor_lg_timestep_log", "Monitor log timestep size graphically", "TSMonitorLGTimeStep", howoften, &howoften, NULL));
195     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
196     PetscCall(TSMonitorSet(ts, TSMonitorLGTimeStep, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxDestroy));
197     ctx->semilogy = PETSC_TRUE;
198   }
199 
200   PetscCall(PetscOptionsName("-ts_monitor_lg_snes_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGSNESIterations", &opt));
201   if (opt) {
202     TSMonitorLGCtx ctx;
203     PetscInt       howoften = 1;
204 
205     PetscCall(PetscOptionsInt("-ts_monitor_lg_snes_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGSNESIterations", howoften, &howoften, NULL));
206     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
207     PetscCall(TSMonitorSet(ts, TSMonitorLGSNESIterations, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxDestroy));
208   }
209   PetscCall(PetscOptionsName("-ts_monitor_lg_ksp_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGKSPIterations", &opt));
210   if (opt) {
211     TSMonitorLGCtx ctx;
212     PetscInt       howoften = 1;
213 
214     PetscCall(PetscOptionsInt("-ts_monitor_lg_ksp_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGKSPIterations", howoften, &howoften, NULL));
215     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
216     PetscCall(TSMonitorSet(ts, TSMonitorLGKSPIterations, ctx, (PetscErrorCode(*)(void **))TSMonitorLGCtxDestroy));
217   }
218   PetscCall(PetscOptionsName("-ts_monitor_sp_eig", "Monitor eigenvalues of linearized operator graphically", "TSMonitorSPEig", &opt));
219   if (opt) {
220     TSMonitorSPEigCtx ctx;
221     PetscInt          howoften = 1;
222 
223     PetscCall(PetscOptionsInt("-ts_monitor_sp_eig", "Monitor eigenvalues of linearized operator graphically", "TSMonitorSPEig", howoften, &howoften, NULL));
224     PetscCall(TSMonitorSPEigCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
225     PetscCall(TSMonitorSet(ts, TSMonitorSPEig, ctx, (PetscErrorCode(*)(void **))TSMonitorSPEigCtxDestroy));
226   }
227   PetscCall(PetscOptionsName("-ts_monitor_sp_swarm", "Display particle phase space from the DMSwarm", "TSMonitorSPSwarm", &opt));
228   if (opt) {
229     TSMonitorSPCtx ctx;
230     PetscInt       howoften = 1, retain = 0;
231     PetscBool      phase = PETSC_TRUE, create = PETSC_TRUE, multispecies = PETSC_FALSE;
232 
233     for (PetscInt i = 0; i < ts->numbermonitors; ++i)
234       if (ts->monitor[i] == TSMonitorSPSwarmSolution) {
235         create = PETSC_FALSE;
236         break;
237       }
238     if (create) {
239       PetscCall(PetscOptionsInt("-ts_monitor_sp_swarm", "Display particles phase space from the DMSwarm", "TSMonitorSPSwarm", howoften, &howoften, NULL));
240       PetscCall(PetscOptionsInt("-ts_monitor_sp_swarm_retain", "Retain n points plotted to show trajectory, -1 for all points", "TSMonitorSPSwarm", retain, &retain, NULL));
241       PetscCall(PetscOptionsBool("-ts_monitor_sp_swarm_phase", "Plot in phase space rather than coordinate space", "TSMonitorSPSwarm", phase, &phase, NULL));
242       PetscCall(PetscOptionsBool("-ts_monitor_sp_swarm_multi_species", "Color particles by particle species", "TSMonitorSPSwarm", multispecies, &multispecies, NULL));
243       PetscCall(TSMonitorSPCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, retain, phase, multispecies, &ctx));
244       PetscCall(TSMonitorSet(ts, TSMonitorSPSwarmSolution, ctx, (PetscErrorCode(*)(void **))TSMonitorSPCtxDestroy));
245     }
246   }
247   PetscCall(PetscOptionsName("-ts_monitor_hg_swarm", "Display particle histogram from the DMSwarm", "TSMonitorHGSwarm", &opt));
248   if (opt) {
249     TSMonitorHGCtx ctx;
250     PetscInt       howoften = 1, Ns = 1;
251     PetscBool      velocity = PETSC_FALSE, create = PETSC_TRUE;
252 
253     for (PetscInt i = 0; i < ts->numbermonitors; ++i)
254       if (ts->monitor[i] == TSMonitorHGSwarmSolution) {
255         create = PETSC_FALSE;
256         break;
257       }
258     if (create) {
259       DM       sw, dm;
260       PetscInt Nc, Nb;
261 
262       PetscCall(TSGetDM(ts, &sw));
263       PetscCall(DMSwarmGetCellDM(sw, &dm));
264       PetscCall(DMPlexGetHeightStratum(dm, 0, NULL, &Nc));
265       Nb = PetscMin(20, PetscMax(10, Nc));
266       PetscCall(PetscOptionsInt("-ts_monitor_hg_swarm", "Display particles histogram from the DMSwarm", "TSMonitorHGSwarm", howoften, &howoften, NULL));
267       PetscCall(PetscOptionsBool("-ts_monitor_hg_swarm_velocity", "Plot in velocity space rather than coordinate space", "TSMonitorHGSwarm", velocity, &velocity, NULL));
268       PetscCall(PetscOptionsInt("-ts_monitor_hg_swarm_species", "Number of species to histogram", "TSMonitorHGSwarm", Ns, &Ns, NULL));
269       PetscCall(PetscOptionsInt("-ts_monitor_hg_swarm_bins", "Number of histogram bins", "TSMonitorHGSwarm", Nb, &Nb, NULL));
270       PetscCall(TSMonitorHGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, Ns, Nb, velocity, &ctx));
271       PetscCall(TSMonitorSet(ts, TSMonitorHGSwarmSolution, ctx, (PetscErrorCode(*)(void **))TSMonitorHGCtxDestroy));
272     }
273   }
274   opt = PETSC_FALSE;
275   PetscCall(PetscOptionsName("-ts_monitor_draw_solution", "Monitor solution graphically", "TSMonitorDrawSolution", &opt));
276   if (opt) {
277     TSMonitorDrawCtx ctx;
278     PetscInt         howoften = 1;
279 
280     PetscCall(PetscOptionsInt("-ts_monitor_draw_solution", "Monitor solution graphically", "TSMonitorDrawSolution", howoften, &howoften, NULL));
281     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, "Computed Solution", PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
282     PetscCall(TSMonitorSet(ts, TSMonitorDrawSolution, ctx, (PetscErrorCode(*)(void **))TSMonitorDrawCtxDestroy));
283   }
284   opt = PETSC_FALSE;
285   PetscCall(PetscOptionsName("-ts_monitor_draw_solution_phase", "Monitor solution graphically", "TSMonitorDrawSolutionPhase", &opt));
286   if (opt) {
287     TSMonitorDrawCtx ctx;
288     PetscReal        bounds[4];
289     PetscInt         n = 4;
290     PetscDraw        draw;
291     PetscDrawAxis    axis;
292 
293     PetscCall(PetscOptionsRealArray("-ts_monitor_draw_solution_phase", "Monitor solution graphically", "TSMonitorDrawSolutionPhase", bounds, &n, NULL));
294     PetscCheck(n == 4, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Must provide bounding box of phase field");
295     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, 1, &ctx));
296     PetscCall(PetscViewerDrawGetDraw(ctx->viewer, 0, &draw));
297     PetscCall(PetscViewerDrawGetDrawAxis(ctx->viewer, 0, &axis));
298     PetscCall(PetscDrawAxisSetLimits(axis, bounds[0], bounds[2], bounds[1], bounds[3]));
299     PetscCall(PetscDrawAxisSetLabels(axis, "Phase Diagram", "Variable 1", "Variable 2"));
300     PetscCall(TSMonitorSet(ts, TSMonitorDrawSolutionPhase, ctx, (PetscErrorCode(*)(void **))TSMonitorDrawCtxDestroy));
301   }
302   opt = PETSC_FALSE;
303   PetscCall(PetscOptionsName("-ts_monitor_draw_error", "Monitor error graphically", "TSMonitorDrawError", &opt));
304   if (opt) {
305     TSMonitorDrawCtx ctx;
306     PetscInt         howoften = 1;
307 
308     PetscCall(PetscOptionsInt("-ts_monitor_draw_error", "Monitor error graphically", "TSMonitorDrawError", howoften, &howoften, NULL));
309     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, "Error", PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
310     PetscCall(TSMonitorSet(ts, TSMonitorDrawError, ctx, (PetscErrorCode(*)(void **))TSMonitorDrawCtxDestroy));
311   }
312   opt = PETSC_FALSE;
313   PetscCall(PetscOptionsName("-ts_monitor_draw_solution_function", "Monitor solution provided by TSMonitorSetSolutionFunction() graphically", "TSMonitorDrawSolutionFunction", &opt));
314   if (opt) {
315     TSMonitorDrawCtx ctx;
316     PetscInt         howoften = 1;
317 
318     PetscCall(PetscOptionsInt("-ts_monitor_draw_solution_function", "Monitor solution provided by TSMonitorSetSolutionFunction() graphically", "TSMonitorDrawSolutionFunction", howoften, &howoften, NULL));
319     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, "Solution provided by user function", PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
320     PetscCall(TSMonitorSet(ts, TSMonitorDrawSolutionFunction, ctx, (PetscErrorCode(*)(void **))TSMonitorDrawCtxDestroy));
321   }
322 
323   opt = PETSC_FALSE;
324   PetscCall(PetscOptionsString("-ts_monitor_solution_vtk", "Save each time step to a binary file, use filename-%%03" PetscInt_FMT ".vts", "TSMonitorSolutionVTK", NULL, monfilename, sizeof(monfilename), &flg));
325   if (flg) {
326     const char *ptr = NULL, *ptr2 = NULL;
327     char       *filetemplate;
328     PetscCheck(monfilename[0], PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "-ts_monitor_solution_vtk requires a file template, e.g. filename-%%03" PetscInt_FMT ".vts");
329     /* Do some cursory validation of the input. */
330     PetscCall(PetscStrstr(monfilename, "%", (char **)&ptr));
331     PetscCheck(ptr, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "-ts_monitor_solution_vtk requires a file template, e.g. filename-%%03" PetscInt_FMT ".vts");
332     for (ptr++; ptr && *ptr; ptr++) {
333       PetscCall(PetscStrchr("DdiouxX", *ptr, (char **)&ptr2));
334       PetscCheck(ptr2 || (*ptr >= '0' && *ptr <= '9'), PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Invalid file template argument to -ts_monitor_solution_vtk, should look like filename-%%03" PetscInt_FMT ".vts");
335       if (ptr2) break;
336     }
337     PetscCall(PetscStrallocpy(monfilename, &filetemplate));
338     PetscCall(TSMonitorSet(ts, TSMonitorSolutionVTK, filetemplate, (PetscErrorCode(*)(void **))TSMonitorSolutionVTKDestroy));
339   }
340 
341   PetscCall(PetscOptionsString("-ts_monitor_dmda_ray", "Display a ray of the solution", "None", "y=0", dir, sizeof(dir), &flg));
342   if (flg) {
343     TSMonitorDMDARayCtx *rayctx;
344     int                  ray = 0;
345     DMDirection          ddir;
346     DM                   da;
347     PetscMPIInt          rank;
348 
349     PetscCheck(dir[1] == '=', PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Unknown ray %s", dir);
350     if (dir[0] == 'x') ddir = DM_X;
351     else if (dir[0] == 'y') ddir = DM_Y;
352     else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Unknown ray %s", dir);
353     sscanf(dir + 2, "%d", &ray);
354 
355     PetscCall(PetscInfo(((PetscObject)ts), "Displaying DMDA ray %c = %d\n", dir[0], ray));
356     PetscCall(PetscNew(&rayctx));
357     PetscCall(TSGetDM(ts, &da));
358     PetscCall(DMDAGetRay(da, ddir, ray, &rayctx->ray, &rayctx->scatter));
359     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ts), &rank));
360     if (rank == 0) PetscCall(PetscViewerDrawOpen(PETSC_COMM_SELF, NULL, NULL, 0, 0, 600, 300, &rayctx->viewer));
361     rayctx->lgctx = NULL;
362     PetscCall(TSMonitorSet(ts, TSMonitorDMDARay, rayctx, TSMonitorDMDARayDestroy));
363   }
364   PetscCall(PetscOptionsString("-ts_monitor_lg_dmda_ray", "Display a ray of the solution", "None", "x=0", dir, sizeof(dir), &flg));
365   if (flg) {
366     TSMonitorDMDARayCtx *rayctx;
367     int                  ray = 0;
368     DMDirection          ddir;
369     DM                   da;
370     PetscInt             howoften = 1;
371 
372     PetscCheck(dir[1] == '=', PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Malformed ray %s", dir);
373     if (dir[0] == 'x') ddir = DM_X;
374     else if (dir[0] == 'y') ddir = DM_Y;
375     else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Unknown ray direction %s", dir);
376     sscanf(dir + 2, "%d", &ray);
377 
378     PetscCall(PetscInfo(((PetscObject)ts), "Displaying LG DMDA ray %c = %d\n", dir[0], ray));
379     PetscCall(PetscNew(&rayctx));
380     PetscCall(TSGetDM(ts, &da));
381     PetscCall(DMDAGetRay(da, ddir, ray, &rayctx->ray, &rayctx->scatter));
382     PetscCall(TSMonitorLGCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 600, 400, howoften, &rayctx->lgctx));
383     PetscCall(TSMonitorSet(ts, TSMonitorLGDMDARay, rayctx, TSMonitorDMDARayDestroy));
384   }
385 
386   PetscCall(PetscOptionsName("-ts_monitor_envelope", "Monitor maximum and minimum value of each component of the solution", "TSMonitorEnvelope", &opt));
387   if (opt) {
388     TSMonitorEnvelopeCtx ctx;
389 
390     PetscCall(TSMonitorEnvelopeCtxCreate(ts, &ctx));
391     PetscCall(TSMonitorSet(ts, TSMonitorEnvelope, ctx, (PetscErrorCode(*)(void **))TSMonitorEnvelopeCtxDestroy));
392   }
393   flg = PETSC_FALSE;
394   PetscCall(PetscOptionsBool("-ts_monitor_cancel", "Remove all monitors", "TSMonitorCancel", flg, &flg, &opt));
395   if (opt && flg) PetscCall(TSMonitorCancel(ts));
396 
397   flg = PETSC_FALSE;
398   PetscCall(PetscOptionsBool("-ts_fd_color", "Use finite differences with coloring to compute IJacobian", "TSComputeIJacobianDefaultColor", flg, &flg, NULL));
399   if (flg) {
400     DM dm;
401 
402     PetscCall(TSGetDM(ts, &dm));
403     PetscCall(DMTSUnsetIJacobianContext_Internal(dm));
404     PetscCall(TSSetIJacobian(ts, NULL, NULL, TSComputeIJacobianDefaultColor, NULL));
405     PetscCall(PetscInfo(ts, "Setting default finite difference coloring Jacobian matrix\n"));
406   }
407 
408   /* Handle specific TS options */
409   PetscTryTypeMethod(ts, setfromoptions, PetscOptionsObject);
410 
411   /* Handle TSAdapt options */
412   PetscCall(TSGetAdapt(ts, &ts->adapt));
413   PetscCall(TSAdaptSetDefaultType(ts->adapt, ts->default_adapt_type));
414   PetscCall(TSAdaptSetFromOptions(ts->adapt, PetscOptionsObject));
415 
416   /* TS trajectory must be set after TS, since it may use some TS options above */
417   tflg = ts->trajectory ? PETSC_TRUE : PETSC_FALSE;
418   PetscCall(PetscOptionsBool("-ts_save_trajectory", "Save the solution at each timestep", "TSSetSaveTrajectory", tflg, &tflg, NULL));
419   if (tflg) PetscCall(TSSetSaveTrajectory(ts));
420 
421   PetscCall(TSAdjointSetFromOptions(ts, PetscOptionsObject));
422 
423   /* process any options handlers added with PetscObjectAddOptionsHandler() */
424   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)ts, PetscOptionsObject));
425   PetscOptionsEnd();
426 
427   if (ts->trajectory) PetscCall(TSTrajectorySetFromOptions(ts->trajectory, ts));
428 
429   /* why do we have to do this here and not during TSSetUp? */
430   PetscCall(TSGetSNES(ts, &ts->snes));
431   if (ts->problem_type == TS_LINEAR) {
432     PetscCall(PetscObjectTypeCompareAny((PetscObject)ts->snes, &flg, SNESKSPONLY, SNESKSPTRANSPOSEONLY, ""));
433     if (!flg) PetscCall(SNESSetType(ts->snes, SNESKSPONLY));
434   }
435   PetscCall(SNESSetFromOptions(ts->snes));
436   PetscFunctionReturn(PETSC_SUCCESS);
437 }
438 
439 /*@
440   TSGetTrajectory - Gets the trajectory from a `TS` if it exists
441 
442   Collective
443 
444   Input Parameter:
445 . ts - the `TS` context obtained from `TSCreate()`
446 
447   Output Parameter:
448 . tr - the `TSTrajectory` object, if it exists
449 
450   Level: advanced
451 
452   Note:
453   This routine should be called after all `TS` options have been set
454 
455 .seealso: [](ch_ts), `TS`, `TSTrajectory`, `TSAdjointSolve()`, `TSTrajectoryCreate()`
456 @*/
457 PetscErrorCode TSGetTrajectory(TS ts, TSTrajectory *tr)
458 {
459   PetscFunctionBegin;
460   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
461   *tr = ts->trajectory;
462   PetscFunctionReturn(PETSC_SUCCESS);
463 }
464 
465 /*@
466   TSSetSaveTrajectory - Causes the `TS` to save its solutions as it iterates forward in time in a `TSTrajectory` object
467 
468   Collective
469 
470   Input Parameter:
471 . ts - the `TS` context obtained from `TSCreate()`
472 
473   Options Database Keys:
474 + -ts_save_trajectory      - saves the trajectory to a file
475 - -ts_trajectory_type type - set trajectory type
476 
477   Level: intermediate
478 
479   Notes:
480   This routine should be called after all `TS` options have been set
481 
482   The `TSTRAJECTORYVISUALIZATION` files can be loaded into Python with $PETSC_DIR/lib/petsc/bin/PetscBinaryIOTrajectory.py and
483   MATLAB with $PETSC_DIR/share/petsc/matlab/PetscReadBinaryTrajectory.m
484 
485 .seealso: [](ch_ts), `TS`, `TSTrajectory`, `TSGetTrajectory()`, `TSAdjointSolve()`
486 @*/
487 PetscErrorCode TSSetSaveTrajectory(TS ts)
488 {
489   PetscFunctionBegin;
490   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
491   if (!ts->trajectory) PetscCall(TSTrajectoryCreate(PetscObjectComm((PetscObject)ts), &ts->trajectory));
492   PetscFunctionReturn(PETSC_SUCCESS);
493 }
494 
495 /*@
496   TSResetTrajectory - Destroys and recreates the internal `TSTrajectory` object
497 
498   Collective
499 
500   Input Parameter:
501 . ts - the `TS` context obtained from `TSCreate()`
502 
503   Level: intermediate
504 
505 .seealso: [](ch_ts), `TSTrajectory`, `TSGetTrajectory()`, `TSAdjointSolve()`, `TSRemoveTrajectory()`
506 @*/
507 PetscErrorCode TSResetTrajectory(TS ts)
508 {
509   PetscFunctionBegin;
510   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
511   if (ts->trajectory) {
512     PetscCall(TSTrajectoryDestroy(&ts->trajectory));
513     PetscCall(TSTrajectoryCreate(PetscObjectComm((PetscObject)ts), &ts->trajectory));
514   }
515   PetscFunctionReturn(PETSC_SUCCESS);
516 }
517 
518 /*@
519   TSRemoveTrajectory - Destroys and removes the internal `TSTrajectory` object from a `TS`
520 
521   Collective
522 
523   Input Parameter:
524 . ts - the `TS` context obtained from `TSCreate()`
525 
526   Level: intermediate
527 
528 .seealso: [](ch_ts), `TSTrajectory`, `TSResetTrajectory()`, `TSAdjointSolve()`
529 @*/
530 PetscErrorCode TSRemoveTrajectory(TS ts)
531 {
532   PetscFunctionBegin;
533   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
534   if (ts->trajectory) PetscCall(TSTrajectoryDestroy(&ts->trajectory));
535   PetscFunctionReturn(PETSC_SUCCESS);
536 }
537 
538 /*@
539   TSComputeRHSJacobian - Computes the Jacobian matrix that has been
540   set with `TSSetRHSJacobian()`.
541 
542   Collective
543 
544   Input Parameters:
545 + ts - the `TS` context
546 . t  - current timestep
547 - U  - input vector
548 
549   Output Parameters:
550 + A - Jacobian matrix
551 - B - optional preconditioning matrix
552 
553   Level: developer
554 
555   Note:
556   Most users should not need to explicitly call this routine, as it
557   is used internally within the nonlinear solvers.
558 
559 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `KSPSetOperators()`
560 @*/
561 PetscErrorCode TSComputeRHSJacobian(TS ts, PetscReal t, Vec U, Mat A, Mat B)
562 {
563   PetscObjectState Ustate;
564   PetscObjectId    Uid;
565   DM               dm;
566   DMTS             tsdm;
567   TSRHSJacobian    rhsjacobianfunc;
568   void            *ctx;
569   TSRHSFunction    rhsfunction;
570 
571   PetscFunctionBegin;
572   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
573   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
574   PetscCheckSameComm(ts, 1, U, 3);
575   PetscCall(TSGetDM(ts, &dm));
576   PetscCall(DMGetDMTS(dm, &tsdm));
577   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
578   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobianfunc, &ctx));
579   PetscCall(PetscObjectStateGet((PetscObject)U, &Ustate));
580   PetscCall(PetscObjectGetId((PetscObject)U, &Uid));
581 
582   if (ts->rhsjacobian.time == t && (ts->problem_type == TS_LINEAR || (ts->rhsjacobian.Xid == Uid && ts->rhsjacobian.Xstate == Ustate)) && (rhsfunction != TSComputeRHSFunctionLinear)) PetscFunctionReturn(PETSC_SUCCESS);
583 
584   PetscCheck(ts->rhsjacobian.shift == 0.0 || !ts->rhsjacobian.reuse, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Should not call TSComputeRHSJacobian() on a shifted matrix (shift=%lf) when RHSJacobian is reusable.", (double)ts->rhsjacobian.shift);
585   if (rhsjacobianfunc) {
586     PetscCall(PetscLogEventBegin(TS_JacobianEval, ts, U, A, B));
587     PetscCallBack("TS callback Jacobian", (*rhsjacobianfunc)(ts, t, U, A, B, ctx));
588     ts->rhsjacs++;
589     PetscCall(PetscLogEventEnd(TS_JacobianEval, ts, U, A, B));
590   } else {
591     PetscCall(MatZeroEntries(A));
592     if (B && A != B) PetscCall(MatZeroEntries(B));
593   }
594   ts->rhsjacobian.time  = t;
595   ts->rhsjacobian.shift = 0;
596   ts->rhsjacobian.scale = 1.;
597   PetscCall(PetscObjectGetId((PetscObject)U, &ts->rhsjacobian.Xid));
598   PetscCall(PetscObjectStateGet((PetscObject)U, &ts->rhsjacobian.Xstate));
599   PetscFunctionReturn(PETSC_SUCCESS);
600 }
601 
602 /*@
603   TSComputeRHSFunction - Evaluates the right-hand-side function for a `TS`
604 
605   Collective
606 
607   Input Parameters:
608 + ts - the `TS` context
609 . t  - current time
610 - U  - state vector
611 
612   Output Parameter:
613 . y - right hand side
614 
615   Level: developer
616 
617   Note:
618   Most users should not need to explicitly call this routine, as it
619   is used internally within the nonlinear solvers.
620 
621 .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSComputeIFunction()`
622 @*/
623 PetscErrorCode TSComputeRHSFunction(TS ts, PetscReal t, Vec U, Vec y)
624 {
625   TSRHSFunction rhsfunction;
626   TSIFunction   ifunction;
627   void         *ctx;
628   DM            dm;
629 
630   PetscFunctionBegin;
631   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
632   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
633   PetscValidHeaderSpecific(y, VEC_CLASSID, 4);
634   PetscCall(TSGetDM(ts, &dm));
635   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, &ctx));
636   PetscCall(DMTSGetIFunction(dm, &ifunction, NULL));
637 
638   PetscCheck(rhsfunction || ifunction, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSFunction() and / or TSSetIFunction()");
639 
640   if (rhsfunction) {
641     PetscCall(PetscLogEventBegin(TS_FunctionEval, ts, U, y, 0));
642     PetscCall(VecLockReadPush(U));
643     PetscCallBack("TS callback right-hand-side", (*rhsfunction)(ts, t, U, y, ctx));
644     PetscCall(VecLockReadPop(U));
645     ts->rhsfuncs++;
646     PetscCall(PetscLogEventEnd(TS_FunctionEval, ts, U, y, 0));
647   } else PetscCall(VecZeroEntries(y));
648   PetscFunctionReturn(PETSC_SUCCESS);
649 }
650 
651 /*@
652   TSComputeSolutionFunction - Evaluates the solution function.
653 
654   Collective
655 
656   Input Parameters:
657 + ts - the `TS` context
658 - t  - current time
659 
660   Output Parameter:
661 . U - the solution
662 
663   Level: developer
664 
665 .seealso: [](ch_ts), `TS`, `TSSetSolutionFunction()`, `TSSetRHSFunction()`, `TSComputeIFunction()`
666 @*/
667 PetscErrorCode TSComputeSolutionFunction(TS ts, PetscReal t, Vec U)
668 {
669   TSSolutionFunction solutionfunction;
670   void              *ctx;
671   DM                 dm;
672 
673   PetscFunctionBegin;
674   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
675   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
676   PetscCall(TSGetDM(ts, &dm));
677   PetscCall(DMTSGetSolutionFunction(dm, &solutionfunction, &ctx));
678   if (solutionfunction) PetscCallBack("TS callback solution", (*solutionfunction)(ts, t, U, ctx));
679   PetscFunctionReturn(PETSC_SUCCESS);
680 }
681 /*@
682   TSComputeForcingFunction - Evaluates the forcing function.
683 
684   Collective
685 
686   Input Parameters:
687 + ts - the `TS` context
688 - t  - current time
689 
690   Output Parameter:
691 . U - the function value
692 
693   Level: developer
694 
695 .seealso: [](ch_ts), `TS`, `TSSetSolutionFunction()`, `TSSetRHSFunction()`, `TSComputeIFunction()`
696 @*/
697 PetscErrorCode TSComputeForcingFunction(TS ts, PetscReal t, Vec U)
698 {
699   void             *ctx;
700   DM                dm;
701   TSForcingFunction forcing;
702 
703   PetscFunctionBegin;
704   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
705   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
706   PetscCall(TSGetDM(ts, &dm));
707   PetscCall(DMTSGetForcingFunction(dm, &forcing, &ctx));
708 
709   if (forcing) PetscCallBack("TS callback forcing function", (*forcing)(ts, t, U, ctx));
710   PetscFunctionReturn(PETSC_SUCCESS);
711 }
712 
713 static PetscErrorCode TSGetRHSVec_Private(TS ts, Vec *Frhs)
714 {
715   Vec F;
716 
717   PetscFunctionBegin;
718   *Frhs = NULL;
719   PetscCall(TSGetIFunction(ts, &F, NULL, NULL));
720   if (!ts->Frhs) PetscCall(VecDuplicate(F, &ts->Frhs));
721   *Frhs = ts->Frhs;
722   PetscFunctionReturn(PETSC_SUCCESS);
723 }
724 
725 PetscErrorCode TSGetRHSMats_Private(TS ts, Mat *Arhs, Mat *Brhs)
726 {
727   Mat         A, B;
728   TSIJacobian ijacobian;
729 
730   PetscFunctionBegin;
731   if (Arhs) *Arhs = NULL;
732   if (Brhs) *Brhs = NULL;
733   PetscCall(TSGetIJacobian(ts, &A, &B, &ijacobian, NULL));
734   if (Arhs) {
735     if (!ts->Arhs) {
736       if (ijacobian) {
737         PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &ts->Arhs));
738         PetscCall(TSSetMatStructure(ts, SAME_NONZERO_PATTERN));
739       } else {
740         ts->Arhs = A;
741         PetscCall(PetscObjectReference((PetscObject)A));
742       }
743     } else {
744       PetscBool flg;
745       PetscCall(SNESGetUseMatrixFree(ts->snes, NULL, &flg));
746       /* Handle case where user provided only RHSJacobian and used -snes_mf_operator */
747       if (flg && !ijacobian && ts->Arhs == ts->Brhs) {
748         PetscCall(PetscObjectDereference((PetscObject)ts->Arhs));
749         ts->Arhs = A;
750         PetscCall(PetscObjectReference((PetscObject)A));
751       }
752     }
753     *Arhs = ts->Arhs;
754   }
755   if (Brhs) {
756     if (!ts->Brhs) {
757       if (A != B) {
758         if (ijacobian) {
759           PetscCall(MatDuplicate(B, MAT_DO_NOT_COPY_VALUES, &ts->Brhs));
760         } else {
761           ts->Brhs = B;
762           PetscCall(PetscObjectReference((PetscObject)B));
763         }
764       } else {
765         PetscCall(PetscObjectReference((PetscObject)ts->Arhs));
766         ts->Brhs = ts->Arhs;
767       }
768     }
769     *Brhs = ts->Brhs;
770   }
771   PetscFunctionReturn(PETSC_SUCCESS);
772 }
773 
774 /*@
775   TSComputeIFunction - Evaluates the DAE residual written in the implicit form F(t,U,Udot)=0
776 
777   Collective
778 
779   Input Parameters:
780 + ts   - the `TS` context
781 . t    - current time
782 . U    - state vector
783 . Udot - time derivative of state vector
784 - imex - flag indicates if the method is `TSIMEX` so that the RHSFunction should be kept separate
785 
786   Output Parameter:
787 . Y - right hand side
788 
789   Level: developer
790 
791   Note:
792   Most users should not need to explicitly call this routine, as it
793   is used internally within the nonlinear solvers.
794 
795   If the user did did not write their equations in implicit form, this
796   function recasts them in implicit form.
797 
798 .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `TSComputeRHSFunction()`
799 @*/
800 PetscErrorCode TSComputeIFunction(TS ts, PetscReal t, Vec U, Vec Udot, Vec Y, PetscBool imex)
801 {
802   TSIFunction   ifunction;
803   TSRHSFunction rhsfunction;
804   void         *ctx;
805   DM            dm;
806 
807   PetscFunctionBegin;
808   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
809   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
810   PetscValidHeaderSpecific(Udot, VEC_CLASSID, 4);
811   PetscValidHeaderSpecific(Y, VEC_CLASSID, 5);
812 
813   PetscCall(TSGetDM(ts, &dm));
814   PetscCall(DMTSGetIFunction(dm, &ifunction, &ctx));
815   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
816 
817   PetscCheck(rhsfunction || ifunction, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSFunction() and / or TSSetIFunction()");
818 
819   PetscCall(PetscLogEventBegin(TS_FunctionEval, ts, U, Udot, Y));
820   if (ifunction) {
821     PetscCallBack("TS callback implicit function", (*ifunction)(ts, t, U, Udot, Y, ctx));
822     ts->ifuncs++;
823   }
824   if (imex) {
825     if (!ifunction) PetscCall(VecCopy(Udot, Y));
826   } else if (rhsfunction) {
827     if (ifunction) {
828       Vec Frhs;
829       PetscCall(TSGetRHSVec_Private(ts, &Frhs));
830       PetscCall(TSComputeRHSFunction(ts, t, U, Frhs));
831       PetscCall(VecAXPY(Y, -1, Frhs));
832     } else {
833       PetscCall(TSComputeRHSFunction(ts, t, U, Y));
834       PetscCall(VecAYPX(Y, -1, Udot));
835     }
836   }
837   PetscCall(PetscLogEventEnd(TS_FunctionEval, ts, U, Udot, Y));
838   PetscFunctionReturn(PETSC_SUCCESS);
839 }
840 
841 /*
842    TSRecoverRHSJacobian - Recover the Jacobian matrix so that one can call `TSComputeRHSJacobian()` on it.
843 
844    Note:
845    This routine is needed when one switches from `TSComputeIJacobian()` to `TSComputeRHSJacobian()` because the Jacobian matrix may be shifted or scaled in `TSComputeIJacobian()`.
846 
847 */
848 static PetscErrorCode TSRecoverRHSJacobian(TS ts, Mat A, Mat B)
849 {
850   PetscFunctionBegin;
851   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
852   PetscCheck(A == ts->Arhs, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Invalid Amat");
853   PetscCheck(B == ts->Brhs, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Invalid Bmat");
854 
855   if (ts->rhsjacobian.shift) PetscCall(MatShift(A, -ts->rhsjacobian.shift));
856   if (ts->rhsjacobian.scale == -1.) PetscCall(MatScale(A, -1));
857   if (B && B == ts->Brhs && A != B) {
858     if (ts->rhsjacobian.shift) PetscCall(MatShift(B, -ts->rhsjacobian.shift));
859     if (ts->rhsjacobian.scale == -1.) PetscCall(MatScale(B, -1));
860   }
861   ts->rhsjacobian.shift = 0;
862   ts->rhsjacobian.scale = 1.;
863   PetscFunctionReturn(PETSC_SUCCESS);
864 }
865 
866 /*@
867   TSComputeIJacobian - Evaluates the Jacobian of the DAE
868 
869   Collective
870 
871   Input Parameters:
872 + ts    - the `TS` context
873 . t     - current timestep
874 . U     - state vector
875 . Udot  - time derivative of state vector
876 . shift - shift to apply, see note below
877 - imex  - flag indicates if the method is `TSIMEX` so that the RHSJacobian should be kept separate
878 
879   Output Parameters:
880 + A - Jacobian matrix
881 - B - matrix from which the preconditioner is constructed; often the same as `A`
882 
883   Level: developer
884 
885   Notes:
886   If F(t,U,Udot)=0 is the DAE, the required Jacobian is
887 .vb
888    dF/dU + shift*dF/dUdot
889 .ve
890   Most users should not need to explicitly call this routine, as it
891   is used internally within the nonlinear solvers.
892 
893 .seealso: [](ch_ts), `TS`, `TSSetIJacobian()`
894 @*/
895 PetscErrorCode TSComputeIJacobian(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat A, Mat B, PetscBool imex)
896 {
897   TSIJacobian   ijacobian;
898   TSRHSJacobian rhsjacobian;
899   DM            dm;
900   void         *ctx;
901 
902   PetscFunctionBegin;
903   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
904   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
905   PetscValidHeaderSpecific(Udot, VEC_CLASSID, 4);
906   PetscValidPointer(A, 6);
907   PetscValidHeaderSpecific(A, MAT_CLASSID, 6);
908   PetscValidPointer(B, 7);
909   PetscValidHeaderSpecific(B, MAT_CLASSID, 7);
910 
911   PetscCall(TSGetDM(ts, &dm));
912   PetscCall(DMTSGetIJacobian(dm, &ijacobian, &ctx));
913   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobian, NULL));
914 
915   PetscCheck(rhsjacobian || ijacobian, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSJacobian() and / or TSSetIJacobian()");
916 
917   PetscCall(PetscLogEventBegin(TS_JacobianEval, ts, U, A, B));
918   if (ijacobian) {
919     PetscCallBack("TS callback implicit Jacobian", (*ijacobian)(ts, t, U, Udot, shift, A, B, ctx));
920     ts->ijacs++;
921   }
922   if (imex) {
923     if (!ijacobian) { /* system was written as Udot = G(t,U) */
924       PetscBool assembled;
925       if (rhsjacobian) {
926         Mat Arhs = NULL;
927         PetscCall(TSGetRHSMats_Private(ts, &Arhs, NULL));
928         if (A == Arhs) {
929           PetscCheck(rhsjacobian != TSComputeRHSJacobianConstant, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Unsupported operation! cannot use TSComputeRHSJacobianConstant"); /* there is no way to reconstruct shift*M-J since J cannot be reevaluated */
930           ts->rhsjacobian.time = PETSC_MIN_REAL;
931         }
932       }
933       PetscCall(MatZeroEntries(A));
934       PetscCall(MatAssembled(A, &assembled));
935       if (!assembled) {
936         PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
937         PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
938       }
939       PetscCall(MatShift(A, shift));
940       if (A != B) {
941         PetscCall(MatZeroEntries(B));
942         PetscCall(MatAssembled(B, &assembled));
943         if (!assembled) {
944           PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
945           PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
946         }
947         PetscCall(MatShift(B, shift));
948       }
949     }
950   } else {
951     Mat Arhs = NULL, Brhs = NULL;
952 
953     /* RHSJacobian needs to be converted to part of IJacobian if exists */
954     if (rhsjacobian) PetscCall(TSGetRHSMats_Private(ts, &Arhs, &Brhs));
955     if (Arhs == A) { /* No IJacobian matrix, so we only have the RHS matrix */
956       PetscObjectState Ustate;
957       PetscObjectId    Uid;
958       TSRHSFunction    rhsfunction;
959 
960       PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
961       PetscCall(PetscObjectStateGet((PetscObject)U, &Ustate));
962       PetscCall(PetscObjectGetId((PetscObject)U, &Uid));
963       if ((rhsjacobian == TSComputeRHSJacobianConstant || (ts->rhsjacobian.time == t && (ts->problem_type == TS_LINEAR || (ts->rhsjacobian.Xid == Uid && ts->rhsjacobian.Xstate == Ustate)) && rhsfunction != TSComputeRHSFunctionLinear)) &&
964           ts->rhsjacobian.scale == -1.) {                      /* No need to recompute RHSJacobian */
965         PetscCall(MatShift(A, shift - ts->rhsjacobian.shift)); /* revert the old shift and add the new shift with a single call to MatShift */
966         if (A != B) PetscCall(MatShift(B, shift - ts->rhsjacobian.shift));
967       } else {
968         PetscBool flg;
969 
970         if (ts->rhsjacobian.reuse) { /* Undo the damage */
971           /* MatScale has a short path for this case.
972              However, this code path is taken the first time TSComputeRHSJacobian is called
973              and the matrices have not been assembled yet */
974           PetscCall(TSRecoverRHSJacobian(ts, A, B));
975         }
976         PetscCall(TSComputeRHSJacobian(ts, t, U, A, B));
977         PetscCall(SNESGetUseMatrixFree(ts->snes, NULL, &flg));
978         /* since -snes_mf_operator uses the full SNES function it does not need to be shifted or scaled here */
979         if (!flg) {
980           PetscCall(MatScale(A, -1));
981           PetscCall(MatShift(A, shift));
982         }
983         if (A != B) {
984           PetscCall(MatScale(B, -1));
985           PetscCall(MatShift(B, shift));
986         }
987       }
988       ts->rhsjacobian.scale = -1;
989       ts->rhsjacobian.shift = shift;
990     } else if (Arhs) {  /* Both IJacobian and RHSJacobian */
991       if (!ijacobian) { /* No IJacobian provided, but we have a separate RHS matrix */
992         PetscCall(MatZeroEntries(A));
993         PetscCall(MatShift(A, shift));
994         if (A != B) {
995           PetscCall(MatZeroEntries(B));
996           PetscCall(MatShift(B, shift));
997         }
998       }
999       PetscCall(TSComputeRHSJacobian(ts, t, U, Arhs, Brhs));
1000       PetscCall(MatAXPY(A, -1, Arhs, ts->axpy_pattern));
1001       if (A != B) PetscCall(MatAXPY(B, -1, Brhs, ts->axpy_pattern));
1002     }
1003   }
1004   PetscCall(PetscLogEventEnd(TS_JacobianEval, ts, U, A, B));
1005   PetscFunctionReturn(PETSC_SUCCESS);
1006 }
1007 
1008 /*@C
1009   TSSetRHSFunction - Sets the routine for evaluating the function,
1010   where U_t = G(t,u).
1011 
1012   Logically Collective
1013 
1014   Input Parameters:
1015 + ts  - the `TS` context obtained from `TSCreate()`
1016 . r   - vector to put the computed right hand side (or `NULL` to have it created)
1017 . f   - routine for evaluating the right-hand-side function
1018 - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
1019 
1020   Calling sequence of `f`:
1021 $     PetscErrorCode f(TS ts, PetscReal t, Vec u, Vec F, void *ctx)
1022 + ts  - timestep context
1023 .   t - current timestep
1024 .   u - input vector
1025 .   F - function vector
1026 - ctx - [optional] user-defined function context
1027 
1028   Level: beginner
1029 
1030   Note:
1031   You must call this function or `TSSetIFunction()` to define your ODE. You cannot use this function when solving a DAE.
1032 
1033 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `TSSetIJacobian()`, `TSSetIFunction()`
1034 @*/
1035 PetscErrorCode TSSetRHSFunction(TS ts, Vec r, PetscErrorCode (*f)(TS, PetscReal, Vec, Vec, void *), void *ctx)
1036 {
1037   SNES snes;
1038   Vec  ralloc = NULL;
1039   DM   dm;
1040 
1041   PetscFunctionBegin;
1042   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1043   if (r) PetscValidHeaderSpecific(r, VEC_CLASSID, 2);
1044 
1045   PetscCall(TSGetDM(ts, &dm));
1046   PetscCall(DMTSSetRHSFunction(dm, f, ctx));
1047   PetscCall(TSGetSNES(ts, &snes));
1048   if (!r && !ts->dm && ts->vec_sol) {
1049     PetscCall(VecDuplicate(ts->vec_sol, &ralloc));
1050     r = ralloc;
1051   }
1052   PetscCall(SNESSetFunction(snes, r, SNESTSFormFunction, ts));
1053   PetscCall(VecDestroy(&ralloc));
1054   PetscFunctionReturn(PETSC_SUCCESS);
1055 }
1056 
1057 /*@C
1058   TSSetSolutionFunction - Provide a function that computes the solution of the ODE or DAE
1059 
1060   Logically Collective
1061 
1062   Input Parameters:
1063 + ts  - the `TS` context obtained from `TSCreate()`
1064 . f   - routine for evaluating the solution
1065 - ctx - [optional] user-defined context for private data for the
1066           function evaluation routine (may be `NULL`)
1067 
1068   Calling sequence of `f`:
1069 $   PetscErrorCode f(TS ts, PetscReal t, Vec u, void *ctx)
1070 + ts  - the integrator context
1071 .   t - current timestep
1072 .   u - output vector
1073 - ctx - [optional] user-defined function context
1074 
1075   Options Database Keys:
1076 + -ts_monitor_lg_error   - create a graphical monitor of error history, requires user to have provided `TSSetSolutionFunction()`
1077 - -ts_monitor_draw_error - Monitor error graphically, requires user to have provided `TSSetSolutionFunction()`
1078 
1079   Level: intermediate
1080 
1081   Notes:
1082   This routine is used for testing accuracy of time integration schemes when you already know the solution.
1083   If analytic solutions are not known for your system, consider using the Method of Manufactured Solutions to
1084   create closed-form solutions with non-physical forcing terms.
1085 
1086   For low-dimensional problems solved in serial, such as small discrete systems, `TSMonitorLGError()` can be used to monitor the error history.
1087 
1088 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `TSSetIJacobian()`, `TSComputeSolutionFunction()`, `TSSetForcingFunction()`, `TSSetSolution()`, `TSGetSolution()`, `TSMonitorLGError()`, `TSMonitorDrawError()`
1089 @*/
1090 PetscErrorCode TSSetSolutionFunction(TS ts, PetscErrorCode (*f)(TS, PetscReal, Vec, void *), void *ctx)
1091 {
1092   DM dm;
1093 
1094   PetscFunctionBegin;
1095   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1096   PetscCall(TSGetDM(ts, &dm));
1097   PetscCall(DMTSSetSolutionFunction(dm, f, ctx));
1098   PetscFunctionReturn(PETSC_SUCCESS);
1099 }
1100 
1101 /*@C
1102   TSSetForcingFunction - Provide a function that computes a forcing term for a ODE or PDE
1103 
1104   Logically Collective
1105 
1106   Input Parameters:
1107 + ts   - the `TS` context obtained from `TSCreate()`
1108 . func - routine for evaluating the forcing function
1109 - ctx  - [optional] user-defined context for private data for the
1110           function evaluation routine (may be `NULL`)
1111 
1112   Calling sequence of func:
1113 $   PetscErrorCode func(TS ts, PetscReal t, Vec f, void *ctx)
1114 + ts  - the integrator context
1115 .   t - current timestep
1116 .   f - output vector
1117 - ctx - [optional] user-defined function context
1118 
1119   Level: intermediate
1120 
1121   Notes:
1122   This routine is useful for testing accuracy of time integration schemes when using the Method of Manufactured Solutions to
1123   create closed-form solutions with a non-physical forcing term. It allows you to use the Method of Manufactored Solution without directly editing the
1124   definition of the problem you are solving and hence possibly introducing bugs.
1125 
1126   This replaces the ODE F(u,u_t,t) = 0 the TS is solving with F(u,u_t,t) - func(t) = 0
1127 
1128   This forcing function does not depend on the solution to the equations, it can only depend on spatial location, time, and possibly parameters, the
1129   parameters can be passed in the ctx variable.
1130 
1131   For low-dimensional problems solved in serial, such as small discrete systems, `TSMonitorLGError()` can be used to monitor the error history.
1132 
1133 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `TSSetIJacobian()`, `TSComputeSolutionFunction()`, `TSSetSolutionFunction()`
1134 @*/
1135 PetscErrorCode TSSetForcingFunction(TS ts, TSForcingFunction func, void *ctx)
1136 {
1137   DM dm;
1138 
1139   PetscFunctionBegin;
1140   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1141   PetscCall(TSGetDM(ts, &dm));
1142   PetscCall(DMTSSetForcingFunction(dm, func, ctx));
1143   PetscFunctionReturn(PETSC_SUCCESS);
1144 }
1145 
1146 /*@C
1147   TSSetRHSJacobian - Sets the function to compute the Jacobian of G,
1148   where U_t = G(U,t), as well as the location to store the matrix.
1149 
1150   Logically Collective
1151 
1152   Input Parameters:
1153 + ts   - the `TS` context obtained from `TSCreate()`
1154 . Amat - (approximate) location to store Jacobian matrix entries computed by `f`
1155 . Pmat - matrix from which preconditioner is to be constructed (usually the same as `Amat`)
1156 . f    - the Jacobian evaluation routine
1157 - ctx  - [optional] user-defined context for private data for the Jacobian evaluation routine (may be `NULL`)
1158 
1159   Calling sequence of `f`:
1160 $  PetscErrorCode f(TS ts, PetscReal t, Vec u, Mat A, Mat B, void *ctx)
1161 + ts   - the `TS` context obtained from `TSCreate()`
1162 .  t - current timestep
1163 .  u - input vector
1164 . Amat - (approximate) Jacobian matrix
1165 . Pmat - matrix from which preconditioner is to be constructed (usually the same as `Amat`)
1166 - ctx  - [optional] user-defined context for matrix evaluation routine
1167 
1168   Level: beginner
1169 
1170   Notes:
1171   You must set all the diagonal entries of the matrices, if they are zero you must still set them with a zero value
1172 
1173   The `TS` solver may modify the nonzero structure and the entries of the matrices Amat and Pmat between the calls to f()
1174   You should not assume the values are the same in the next call to f() as you set them in the previous call.
1175 
1176 .seealso: [](ch_ts), `TS`, `SNESComputeJacobianDefaultColor()`, `TSSetRHSFunction()`, `TSRHSJacobianSetReuse()`, `TSSetIJacobian()`
1177 @*/
1178 PetscErrorCode TSSetRHSJacobian(TS ts, Mat Amat, Mat Pmat, TSRHSJacobian f, void *ctx)
1179 {
1180   SNES        snes;
1181   DM          dm;
1182   TSIJacobian ijacobian;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1186   if (Amat) PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2);
1187   if (Pmat) PetscValidHeaderSpecific(Pmat, MAT_CLASSID, 3);
1188   if (Amat) PetscCheckSameComm(ts, 1, Amat, 2);
1189   if (Pmat) PetscCheckSameComm(ts, 1, Pmat, 3);
1190 
1191   PetscCall(TSGetDM(ts, &dm));
1192   PetscCall(DMTSSetRHSJacobian(dm, f, ctx));
1193   PetscCall(DMTSGetIJacobian(dm, &ijacobian, NULL));
1194   PetscCall(TSGetSNES(ts, &snes));
1195   if (!ijacobian) PetscCall(SNESSetJacobian(snes, Amat, Pmat, SNESTSFormJacobian, ts));
1196   if (Amat) {
1197     PetscCall(PetscObjectReference((PetscObject)Amat));
1198     PetscCall(MatDestroy(&ts->Arhs));
1199     ts->Arhs = Amat;
1200   }
1201   if (Pmat) {
1202     PetscCall(PetscObjectReference((PetscObject)Pmat));
1203     PetscCall(MatDestroy(&ts->Brhs));
1204     ts->Brhs = Pmat;
1205   }
1206   PetscFunctionReturn(PETSC_SUCCESS);
1207 }
1208 
1209 /*@C
1210   TSSetIFunction - Set the function to compute F(t,U,U_t) where F() = 0 is the DAE to be solved.
1211 
1212   Logically Collective
1213 
1214   Input Parameters:
1215 + ts  - the `TS` context obtained from `TSCreate()`
1216 . r   - vector to hold the residual (or `NULL` to have it created internally)
1217 . f   - the function evaluation routine
1218 - ctx - user-defined context for private data for the function evaluation routine (may be `NULL`)
1219 
1220   Calling sequence of `f`:
1221 $   PetscErrorCode f(TS ts, PetscReal t, Vec u, Vec u_t, Vec F, void *ctx)
1222 + ts  - the `TS` context obtained from `TSCreate()`
1223 .  t   - time at step/stage being solved
1224 .  u   - state vector
1225 .  u_t - time derivative of state vector
1226 .  F   - function vector
1227 - ctx - [optional] user-defined context for matrix evaluation routine
1228 
1229   Level: beginner
1230 
1231   Note:
1232   The user MUST call either this routine or `TSSetRHSFunction()` to define the ODE.  When solving DAEs you must use this function.
1233 
1234 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `TSSetRHSFunction()`, `TSSetIJacobian()`
1235 @*/
1236 PetscErrorCode TSSetIFunction(TS ts, Vec r, TSIFunction f, void *ctx)
1237 {
1238   SNES snes;
1239   Vec  ralloc = NULL;
1240   DM   dm;
1241 
1242   PetscFunctionBegin;
1243   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1244   if (r) PetscValidHeaderSpecific(r, VEC_CLASSID, 2);
1245 
1246   PetscCall(TSGetDM(ts, &dm));
1247   PetscCall(DMTSSetIFunction(dm, f, ctx));
1248 
1249   PetscCall(TSGetSNES(ts, &snes));
1250   if (!r && !ts->dm && ts->vec_sol) {
1251     PetscCall(VecDuplicate(ts->vec_sol, &ralloc));
1252     r = ralloc;
1253   }
1254   PetscCall(SNESSetFunction(snes, r, SNESTSFormFunction, ts));
1255   PetscCall(VecDestroy(&ralloc));
1256   PetscFunctionReturn(PETSC_SUCCESS);
1257 }
1258 
1259 /*@C
1260   TSGetIFunction - Returns the vector where the implicit residual is stored and the function/context to compute it.
1261 
1262   Not Collective
1263 
1264   Input Parameter:
1265 . ts - the `TS` context
1266 
1267   Output Parameters:
1268 + r    - vector to hold residual (or `NULL`)
1269 . func - the function to compute residual (or `NULL`)
1270 - ctx  - the function context (or `NULL`)
1271 
1272   Level: advanced
1273 
1274 .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `SNESGetFunction()`
1275 @*/
1276 PetscErrorCode TSGetIFunction(TS ts, Vec *r, TSIFunction *func, void **ctx)
1277 {
1278   SNES snes;
1279   DM   dm;
1280 
1281   PetscFunctionBegin;
1282   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1283   PetscCall(TSGetSNES(ts, &snes));
1284   PetscCall(SNESGetFunction(snes, r, NULL, NULL));
1285   PetscCall(TSGetDM(ts, &dm));
1286   PetscCall(DMTSGetIFunction(dm, func, ctx));
1287   PetscFunctionReturn(PETSC_SUCCESS);
1288 }
1289 
1290 /*@C
1291   TSGetRHSFunction - Returns the vector where the right hand side is stored and the function/context to compute it.
1292 
1293   Not Collective
1294 
1295   Input Parameter:
1296 . ts - the `TS` context
1297 
1298   Output Parameters:
1299 + r    - vector to hold computed right hand side (or `NULL`)
1300 . func - the function to compute right hand side (or `NULL`)
1301 - ctx  - the function context (or `NULL`)
1302 
1303   Level: advanced
1304 
1305 .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `SNESGetFunction()`
1306 @*/
1307 PetscErrorCode TSGetRHSFunction(TS ts, Vec *r, TSRHSFunction *func, void **ctx)
1308 {
1309   SNES snes;
1310   DM   dm;
1311 
1312   PetscFunctionBegin;
1313   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1314   PetscCall(TSGetSNES(ts, &snes));
1315   PetscCall(SNESGetFunction(snes, r, NULL, NULL));
1316   PetscCall(TSGetDM(ts, &dm));
1317   PetscCall(DMTSGetRHSFunction(dm, func, ctx));
1318   PetscFunctionReturn(PETSC_SUCCESS);
1319 }
1320 
1321 /*@C
1322   TSSetIJacobian - Set the function to compute the matrix dF/dU + a*dF/dU_t where F(t,U,U_t) is the function
1323   provided with `TSSetIFunction()`.
1324 
1325   Logically Collective
1326 
1327   Input Parameters:
1328 + ts   - the `TS` context obtained from `TSCreate()`
1329 . Amat - (approximate) matrix to store Jacobian entries computed by `f`
1330 . Pmat - matrix used to compute preconditioner (usually the same as `Amat`)
1331 . f    - the Jacobian evaluation routine
1332 - ctx  - user-defined context for private data for the Jacobian evaluation routine (may be `NULL`)
1333 
1334   Calling sequence of `f`:
1335 $    PetscErrorCode f(TS ts, PetscReal t, Vec U, Vec U_t, PetscReal a, Mat Amat, Mat Pmat, void *ctx)
1336 + ts   - the `TS` context obtained from `TSCreate()`
1337 .  t    - time at step/stage being solved
1338 .  U    - state vector
1339 .  U_t  - time derivative of state vector
1340 .  a    - shift
1341 . Amat - (approximate) Jacobian of F(t,U,W+a*U), equivalent to dF/dU + a*dF/dU_t
1342 . Pmat - matrix used for constructing preconditioner, usually the same as `Amat`
1343 - ctx  - [optional] user-defined context for matrix evaluation routine
1344 
1345   Level: beginner
1346 
1347   Notes:
1348   The matrices `Amat` and `Pmat` are exactly the matrices that are used by `SNES` for the nonlinear solve.
1349 
1350   If you know the operator Amat has a null space you can use `MatSetNullSpace()` and `MatSetTransposeNullSpace()` to supply the null
1351   space to `Amat` and the `KSP` solvers will automatically use that null space as needed during the solution process.
1352 
1353   The matrix dF/dU + a*dF/dU_t you provide turns out to be
1354   the Jacobian of F(t,U,W+a*U) where F(t,U,U_t) = 0 is the DAE to be solved.
1355   The time integrator internally approximates U_t by W+a*U where the positive "shift"
1356   a and vector W depend on the integration method, step size, and past states. For example with
1357   the backward Euler method a = 1/dt and W = -a*U(previous timestep) so
1358   W + a*U = a*(U - U(previous timestep)) = (U - U(previous timestep))/dt
1359 
1360   You must set all the diagonal entries of the matrices, if they are zero you must still set them with a zero value
1361 
1362   The TS solver may modify the nonzero structure and the entries of the matrices `Amat` and `Pmat` between the calls to `f`
1363   You should not assume the values are the same in the next call to `f` as you set them in the previous call.
1364 
1365 .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `TSSetRHSJacobian()`, `SNESComputeJacobianDefaultColor()`, `SNESComputeJacobianDefault()`, `TSSetRHSFunction()`
1366 @*/
1367 PetscErrorCode TSSetIJacobian(TS ts, Mat Amat, Mat Pmat, TSIJacobian f, void *ctx)
1368 {
1369   SNES snes;
1370   DM   dm;
1371 
1372   PetscFunctionBegin;
1373   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1374   if (Amat) PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2);
1375   if (Pmat) PetscValidHeaderSpecific(Pmat, MAT_CLASSID, 3);
1376   if (Amat) PetscCheckSameComm(ts, 1, Amat, 2);
1377   if (Pmat) PetscCheckSameComm(ts, 1, Pmat, 3);
1378 
1379   PetscCall(TSGetDM(ts, &dm));
1380   PetscCall(DMTSSetIJacobian(dm, f, ctx));
1381 
1382   PetscCall(TSGetSNES(ts, &snes));
1383   PetscCall(SNESSetJacobian(snes, Amat, Pmat, SNESTSFormJacobian, ts));
1384   PetscFunctionReturn(PETSC_SUCCESS);
1385 }
1386 
1387 /*@
1388   TSRHSJacobianSetReuse - restore RHS Jacobian before re-evaluating.  Without this flag, `TS` will change the sign and
1389   shift the RHS Jacobian for a finite-time-step implicit solve, in which case the user function will need to recompute
1390   the entire Jacobian.  The reuse flag must be set if the evaluation function will assume that the matrix entries have
1391   not been changed by the `TS`.
1392 
1393   Logically Collective
1394 
1395   Input Parameters:
1396 + ts    - `TS` context obtained from `TSCreate()`
1397 - reuse - `PETSC_TRUE` if the RHS Jacobian
1398 
1399   Level: intermediate
1400 
1401 .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `TSComputeRHSJacobianConstant()`
1402 @*/
1403 PetscErrorCode TSRHSJacobianSetReuse(TS ts, PetscBool reuse)
1404 {
1405   PetscFunctionBegin;
1406   ts->rhsjacobian.reuse = reuse;
1407   PetscFunctionReturn(PETSC_SUCCESS);
1408 }
1409 
1410 /*@C
1411   TSSetI2Function - Set the function to compute F(t,U,U_t,U_tt) where F = 0 is the DAE to be solved.
1412 
1413   Logically Collective
1414 
1415   Input Parameters:
1416 + ts  - the `TS` context obtained from `TSCreate()`
1417 . F   - vector to hold the residual (or `NULL` to have it created internally)
1418 . fun - the function evaluation routine
1419 - ctx - user-defined context for private data for the function evaluation routine (may be `NULL`)
1420 
1421   Calling sequence of `fun`:
1422 $   PetscErrorCode fun(TS ts, PetscReal t, Vec U, Vec U_t, Vec U_tt, Vec F,void *ctx);
1423 + ts  - the `TS` context obtained from `TSCreate()`
1424 .  t    - time at step/stage being solved
1425 .  U    - state vector
1426 .  U_t  - time derivative of state vector
1427 .  U_tt - second time derivative of state vector
1428 . F   - function vector
1429 - ctx - [optional] user-defined context for matrix evaluation routine (may be `NULL`)
1430 
1431   Level: beginner
1432 
1433 .seealso: [](ch_ts), `TS`, `TSSetI2Jacobian()`, `TSSetIFunction()`, `TSCreate()`, `TSSetRHSFunction()`
1434 @*/
1435 PetscErrorCode TSSetI2Function(TS ts, Vec F, TSI2Function fun, void *ctx)
1436 {
1437   DM dm;
1438 
1439   PetscFunctionBegin;
1440   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1441   if (F) PetscValidHeaderSpecific(F, VEC_CLASSID, 2);
1442   PetscCall(TSSetIFunction(ts, F, NULL, NULL));
1443   PetscCall(TSGetDM(ts, &dm));
1444   PetscCall(DMTSSetI2Function(dm, fun, ctx));
1445   PetscFunctionReturn(PETSC_SUCCESS);
1446 }
1447 
1448 /*@C
1449   TSGetI2Function - Returns the vector where the implicit residual is stored and the function/context to compute it.
1450 
1451   Not Collective
1452 
1453   Input Parameter:
1454 . ts - the `TS` context
1455 
1456   Output Parameters:
1457 + r   - vector to hold residual (or `NULL`)
1458 . fun - the function to compute residual (or `NULL`)
1459 - ctx - the function context (or `NULL`)
1460 
1461   Level: advanced
1462 
1463 .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `SNESGetFunction()`, `TSCreate()`
1464 @*/
1465 PetscErrorCode TSGetI2Function(TS ts, Vec *r, TSI2Function *fun, void **ctx)
1466 {
1467   SNES snes;
1468   DM   dm;
1469 
1470   PetscFunctionBegin;
1471   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1472   PetscCall(TSGetSNES(ts, &snes));
1473   PetscCall(SNESGetFunction(snes, r, NULL, NULL));
1474   PetscCall(TSGetDM(ts, &dm));
1475   PetscCall(DMTSGetI2Function(dm, fun, ctx));
1476   PetscFunctionReturn(PETSC_SUCCESS);
1477 }
1478 
1479 /*@C
1480   TSSetI2Jacobian - Set the function to compute the matrix dF/dU + v*dF/dU_t  + a*dF/dU_tt
1481   where F(t,U,U_t,U_tt) is the function you provided with `TSSetI2Function()`.
1482 
1483   Logically Collective
1484 
1485   Input Parameters:
1486 + ts  - the `TS` context obtained from `TSCreate()`
1487 . J   - matrix to hold the Jacobian values
1488 . P   - matrix for constructing the preconditioner (may be same as `J`)
1489 . jac - the Jacobian evaluation routine
1490 - ctx - user-defined context for private data for the Jacobian evaluation routine (may be `NULL`)
1491 
1492   Calling sequence of `jac`:
1493 $    PetscErrorCode jac(TS ts, PetscReal t, Vec U, Vec U_t, Vec U_tt, PetscReal v, PetscReal a, Mat J, Mat P, void *ctx)
1494 + ts  - the `TS` context obtained from `TSCreate()`
1495 .  t    - time at step/stage being solved
1496 .  U    - state vector
1497 .  U_t  - time derivative of state vector
1498 .  U_tt - second time derivative of state vector
1499 .  v    - shift for U_t
1500 .  a    - shift for U_tt
1501 . J   - Jacobian of G(U) = F(t,U,W+v*U,W'+a*U), equivalent to dF/dU + v*dF/dU_t  + a*dF/dU_tt
1502 . P   - preconditioning matrix for J, may be same as J
1503 - ctx - [optional] user-defined context for matrix evaluation routine
1504 
1505   Level: beginner
1506 
1507   Notes:
1508   The matrices `J` and `P` are exactly the matrices that are used by `SNES` for the nonlinear solve.
1509 
1510   The matrix dF/dU + v*dF/dU_t + a*dF/dU_tt you provide turns out to be
1511   the Jacobian of G(U) = F(t,U,W+v*U,W'+a*U) where F(t,U,U_t,U_tt) = 0 is the DAE to be solved.
1512   The time integrator internally approximates U_t by W+v*U and U_tt by W'+a*U  where the positive "shift"
1513   parameters 'v' and 'a' and vectors W, W' depend on the integration method, step size, and past states.
1514 
1515 .seealso: [](ch_ts), `TS`, `TSSetI2Function()`, `TSGetI2Jacobian()`
1516 @*/
1517 PetscErrorCode TSSetI2Jacobian(TS ts, Mat J, Mat P, TSI2Jacobian jac, void *ctx)
1518 {
1519   DM dm;
1520 
1521   PetscFunctionBegin;
1522   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1523   if (J) PetscValidHeaderSpecific(J, MAT_CLASSID, 2);
1524   if (P) PetscValidHeaderSpecific(P, MAT_CLASSID, 3);
1525   PetscCall(TSSetIJacobian(ts, J, P, NULL, NULL));
1526   PetscCall(TSGetDM(ts, &dm));
1527   PetscCall(DMTSSetI2Jacobian(dm, jac, ctx));
1528   PetscFunctionReturn(PETSC_SUCCESS);
1529 }
1530 
1531 /*@C
1532   TSGetI2Jacobian - Returns the implicit Jacobian at the present timestep.
1533 
1534   Not Collective, but parallel objects are returned if `TS` is parallel
1535 
1536   Input Parameter:
1537 . ts - The `TS` context obtained from `TSCreate()`
1538 
1539   Output Parameters:
1540 + J   - The (approximate) Jacobian of F(t,U,U_t,U_tt)
1541 . P   - The matrix from which the preconditioner is constructed, often the same as `J`
1542 . jac - The function to compute the Jacobian matrices
1543 - ctx - User-defined context for Jacobian evaluation routine
1544 
1545   Level: advanced
1546 
1547   Note:
1548   You can pass in `NULL` for any return argument you do not need.
1549 
1550 .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetMatrices()`, `TSGetTime()`, `TSGetStepNumber()`, `TSSetI2Jacobian()`, `TSGetI2Function()`, `TSCreate()`
1551 @*/
1552 PetscErrorCode TSGetI2Jacobian(TS ts, Mat *J, Mat *P, TSI2Jacobian *jac, void **ctx)
1553 {
1554   SNES snes;
1555   DM   dm;
1556 
1557   PetscFunctionBegin;
1558   PetscCall(TSGetSNES(ts, &snes));
1559   PetscCall(SNESSetUpMatrices(snes));
1560   PetscCall(SNESGetJacobian(snes, J, P, NULL, NULL));
1561   PetscCall(TSGetDM(ts, &dm));
1562   PetscCall(DMTSGetI2Jacobian(dm, jac, ctx));
1563   PetscFunctionReturn(PETSC_SUCCESS);
1564 }
1565 
1566 /*@
1567   TSComputeI2Function - Evaluates the DAE residual written in implicit form F(t,U,U_t,U_tt) = 0
1568 
1569   Collective
1570 
1571   Input Parameters:
1572 + ts - the `TS` context
1573 . t  - current time
1574 . U  - state vector
1575 . V  - time derivative of state vector (U_t)
1576 - A  - second time derivative of state vector (U_tt)
1577 
1578   Output Parameter:
1579 . F - the residual vector
1580 
1581   Level: developer
1582 
1583   Note:
1584   Most users should not need to explicitly call this routine, as it
1585   is used internally within the nonlinear solvers.
1586 
1587 .seealso: [](ch_ts), `TS`, `TSSetI2Function()`, `TSGetI2Function()`
1588 @*/
1589 PetscErrorCode TSComputeI2Function(TS ts, PetscReal t, Vec U, Vec V, Vec A, Vec F)
1590 {
1591   DM            dm;
1592   TSI2Function  I2Function;
1593   void         *ctx;
1594   TSRHSFunction rhsfunction;
1595 
1596   PetscFunctionBegin;
1597   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1598   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
1599   PetscValidHeaderSpecific(V, VEC_CLASSID, 4);
1600   PetscValidHeaderSpecific(A, VEC_CLASSID, 5);
1601   PetscValidHeaderSpecific(F, VEC_CLASSID, 6);
1602 
1603   PetscCall(TSGetDM(ts, &dm));
1604   PetscCall(DMTSGetI2Function(dm, &I2Function, &ctx));
1605   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
1606 
1607   if (!I2Function) {
1608     PetscCall(TSComputeIFunction(ts, t, U, A, F, PETSC_FALSE));
1609     PetscFunctionReturn(PETSC_SUCCESS);
1610   }
1611 
1612   PetscCall(PetscLogEventBegin(TS_FunctionEval, ts, U, V, F));
1613 
1614   PetscCallBack("TS callback implicit function", I2Function(ts, t, U, V, A, F, ctx));
1615 
1616   if (rhsfunction) {
1617     Vec Frhs;
1618     PetscCall(TSGetRHSVec_Private(ts, &Frhs));
1619     PetscCall(TSComputeRHSFunction(ts, t, U, Frhs));
1620     PetscCall(VecAXPY(F, -1, Frhs));
1621   }
1622 
1623   PetscCall(PetscLogEventEnd(TS_FunctionEval, ts, U, V, F));
1624   PetscFunctionReturn(PETSC_SUCCESS);
1625 }
1626 
1627 /*@
1628   TSComputeI2Jacobian - Evaluates the Jacobian of the DAE
1629 
1630   Collective
1631 
1632   Input Parameters:
1633 + ts     - the `TS` context
1634 . t      - current timestep
1635 . U      - state vector
1636 . V      - time derivative of state vector
1637 . A      - second time derivative of state vector
1638 . shiftV - shift to apply, see note below
1639 - shiftA - shift to apply, see note below
1640 
1641   Output Parameters:
1642 + J - Jacobian matrix
1643 - P - optional preconditioning matrix
1644 
1645   Level: developer
1646 
1647   Notes:
1648   If F(t,U,V,A)=0 is the DAE, the required Jacobian is
1649 
1650   dF/dU + shiftV*dF/dV + shiftA*dF/dA
1651 
1652   Most users should not need to explicitly call this routine, as it
1653   is used internally within the nonlinear solvers.
1654 
1655 .seealso: [](ch_ts), `TS`, `TSSetI2Jacobian()`
1656 @*/
1657 PetscErrorCode TSComputeI2Jacobian(TS ts, PetscReal t, Vec U, Vec V, Vec A, PetscReal shiftV, PetscReal shiftA, Mat J, Mat P)
1658 {
1659   DM            dm;
1660   TSI2Jacobian  I2Jacobian;
1661   void         *ctx;
1662   TSRHSJacobian rhsjacobian;
1663 
1664   PetscFunctionBegin;
1665   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1666   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
1667   PetscValidHeaderSpecific(V, VEC_CLASSID, 4);
1668   PetscValidHeaderSpecific(A, VEC_CLASSID, 5);
1669   PetscValidHeaderSpecific(J, MAT_CLASSID, 8);
1670   PetscValidHeaderSpecific(P, MAT_CLASSID, 9);
1671 
1672   PetscCall(TSGetDM(ts, &dm));
1673   PetscCall(DMTSGetI2Jacobian(dm, &I2Jacobian, &ctx));
1674   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobian, NULL));
1675 
1676   if (!I2Jacobian) {
1677     PetscCall(TSComputeIJacobian(ts, t, U, A, shiftA, J, P, PETSC_FALSE));
1678     PetscFunctionReturn(PETSC_SUCCESS);
1679   }
1680 
1681   PetscCall(PetscLogEventBegin(TS_JacobianEval, ts, U, J, P));
1682   PetscCallBack("TS callback implicit Jacobian", I2Jacobian(ts, t, U, V, A, shiftV, shiftA, J, P, ctx));
1683   if (rhsjacobian) {
1684     Mat Jrhs, Prhs;
1685     PetscCall(TSGetRHSMats_Private(ts, &Jrhs, &Prhs));
1686     PetscCall(TSComputeRHSJacobian(ts, t, U, Jrhs, Prhs));
1687     PetscCall(MatAXPY(J, -1, Jrhs, ts->axpy_pattern));
1688     if (P != J) PetscCall(MatAXPY(P, -1, Prhs, ts->axpy_pattern));
1689   }
1690 
1691   PetscCall(PetscLogEventEnd(TS_JacobianEval, ts, U, J, P));
1692   PetscFunctionReturn(PETSC_SUCCESS);
1693 }
1694 
1695 /*@C
1696   TSSetTransientVariable - sets function to transform from state to transient variables
1697 
1698   Logically Collective
1699 
1700   Input Parameters:
1701 + ts   - time stepping context on which to change the transient variable
1702 . tvar - a function that transforms to transient variables
1703 - ctx  - a context for tvar
1704 
1705   Calling sequence of `tvar`:
1706 $   PetscErrorCode tvar(TS ts, Vec p, Vec c, void *ctx)
1707 + ts  - timestep context
1708 .   p - input vector (primitive form)
1709 .   c - output vector, transient variables (conservative form)
1710 - ctx - [optional] user-defined function context
1711 
1712   Level: advanced
1713 
1714   Notes:
1715   This is typically used to transform from primitive to conservative variables so that a time integrator (e.g., `TSBDF`)
1716   can be conservative.  In this context, primitive variables P are used to model the state (e.g., because they lead to
1717   well-conditioned formulations even in limiting cases such as low-Mach or zero porosity).  The transient variable is
1718   C(P), specified by calling this function.  An IFunction thus receives arguments (P, Cdot) and the IJacobian must be
1719   evaluated via the chain rule, as in
1720 .vb
1721      dF/dP + shift * dF/dCdot dC/dP.
1722 .ve
1723 
1724 .seealso: [](ch_ts), `TS`, `TSBDF`, `DMTSSetTransientVariable()`, `DMTSGetTransientVariable()`, `TSSetIFunction()`, `TSSetIJacobian()`
1725 @*/
1726 PetscErrorCode TSSetTransientVariable(TS ts, TSTransientVariable tvar, void *ctx)
1727 {
1728   DM dm;
1729 
1730   PetscFunctionBegin;
1731   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1732   PetscCall(TSGetDM(ts, &dm));
1733   PetscCall(DMTSSetTransientVariable(dm, tvar, ctx));
1734   PetscFunctionReturn(PETSC_SUCCESS);
1735 }
1736 
1737 /*@
1738   TSComputeTransientVariable - transforms state (primitive) variables to transient (conservative) variables
1739 
1740   Logically Collective
1741 
1742   Input Parameters:
1743 + ts - TS on which to compute
1744 - U  - state vector to be transformed to transient variables
1745 
1746   Output Parameter:
1747 . C - transient (conservative) variable
1748 
1749   Level: developer
1750 
1751   Developer Notes:
1752   If `DMTSSetTransientVariable()` has not been called, then C is not modified in this routine and C = `NULL` is allowed.
1753   This makes it safe to call without a guard.  One can use `TSHasTransientVariable()` to check if transient variables are
1754   being used.
1755 
1756 .seealso: [](ch_ts), `TS`, `TSBDF`, `DMTSSetTransientVariable()`, `TSComputeIFunction()`, `TSComputeIJacobian()`
1757 @*/
1758 PetscErrorCode TSComputeTransientVariable(TS ts, Vec U, Vec C)
1759 {
1760   DM   dm;
1761   DMTS dmts;
1762 
1763   PetscFunctionBegin;
1764   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1765   PetscValidHeaderSpecific(U, VEC_CLASSID, 2);
1766   PetscCall(TSGetDM(ts, &dm));
1767   PetscCall(DMGetDMTS(dm, &dmts));
1768   if (dmts->ops->transientvar) {
1769     PetscValidHeaderSpecific(C, VEC_CLASSID, 3);
1770     PetscCall((*dmts->ops->transientvar)(ts, U, C, dmts->transientvarctx));
1771   }
1772   PetscFunctionReturn(PETSC_SUCCESS);
1773 }
1774 
1775 /*@
1776   TSHasTransientVariable - determine whether transient variables have been set
1777 
1778   Logically Collective
1779 
1780   Input Parameter:
1781 . ts - `TS` on which to compute
1782 
1783   Output Parameter:
1784 . has - `PETSC_TRUE` if transient variables have been set
1785 
1786   Level: developer
1787 
1788 .seealso: [](ch_ts), `TS`, `TSBDF`, `DMTSSetTransientVariable()`, `TSComputeTransientVariable()`
1789 @*/
1790 PetscErrorCode TSHasTransientVariable(TS ts, PetscBool *has)
1791 {
1792   DM   dm;
1793   DMTS dmts;
1794 
1795   PetscFunctionBegin;
1796   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1797   PetscCall(TSGetDM(ts, &dm));
1798   PetscCall(DMGetDMTS(dm, &dmts));
1799   *has = dmts->ops->transientvar ? PETSC_TRUE : PETSC_FALSE;
1800   PetscFunctionReturn(PETSC_SUCCESS);
1801 }
1802 
1803 /*@
1804   TS2SetSolution - Sets the initial solution and time derivative vectors
1805   for use by the `TS` routines handling second order equations.
1806 
1807   Logically Collective
1808 
1809   Input Parameters:
1810 + ts - the `TS` context obtained from `TSCreate()`
1811 . u  - the solution vector
1812 - v  - the time derivative vector
1813 
1814   Level: beginner
1815 
1816 .seealso: [](ch_ts), `TS`
1817 @*/
1818 PetscErrorCode TS2SetSolution(TS ts, Vec u, Vec v)
1819 {
1820   PetscFunctionBegin;
1821   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1822   PetscValidHeaderSpecific(u, VEC_CLASSID, 2);
1823   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
1824   PetscCall(TSSetSolution(ts, u));
1825   PetscCall(PetscObjectReference((PetscObject)v));
1826   PetscCall(VecDestroy(&ts->vec_dot));
1827   ts->vec_dot = v;
1828   PetscFunctionReturn(PETSC_SUCCESS);
1829 }
1830 
1831 /*@
1832   TS2GetSolution - Returns the solution and time derivative at the present timestep
1833   for second order equations. It is valid to call this routine inside the function
1834   that you are evaluating in order to move to the new timestep. This vector not
1835   changed until the solution at the next timestep has been calculated.
1836 
1837   Not Collective, but `u` returned is parallel if `TS` is parallel
1838 
1839   Input Parameter:
1840 . ts - the `TS` context obtained from `TSCreate()`
1841 
1842   Output Parameters:
1843 + u - the vector containing the solution
1844 - v - the vector containing the time derivative
1845 
1846   Level: intermediate
1847 
1848 .seealso: [](ch_ts), `TS`, `TS2SetSolution()`, `TSGetTimeStep()`, `TSGetTime()`
1849 @*/
1850 PetscErrorCode TS2GetSolution(TS ts, Vec *u, Vec *v)
1851 {
1852   PetscFunctionBegin;
1853   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1854   if (u) PetscValidPointer(u, 2);
1855   if (v) PetscValidPointer(v, 3);
1856   if (u) *u = ts->vec_sol;
1857   if (v) *v = ts->vec_dot;
1858   PetscFunctionReturn(PETSC_SUCCESS);
1859 }
1860 
1861 /*@C
1862   TSLoad - Loads a `TS` that has been stored in binary  with `TSView()`.
1863 
1864   Collective
1865 
1866   Input Parameters:
1867 + ts     - the newly loaded `TS`, this needs to have been created with `TSCreate()` or
1868            some related function before a call to `TSLoad()`.
1869 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()`
1870 
1871   Level: intermediate
1872 
1873   Note:
1874   The type is determined by the data in the file, any type set into the `TS` before this call is ignored.
1875 
1876 .seealso: [](ch_ts), `TS`, `PetscViewer`, `PetscViewerBinaryOpen()`, `TSView()`, `MatLoad()`, `VecLoad()`
1877 @*/
1878 PetscErrorCode TSLoad(TS ts, PetscViewer viewer)
1879 {
1880   PetscBool isbinary;
1881   PetscInt  classid;
1882   char      type[256];
1883   DMTS      sdm;
1884   DM        dm;
1885 
1886   PetscFunctionBegin;
1887   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1888   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1889   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
1890   PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");
1891 
1892   PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
1893   PetscCheck(classid == TS_FILE_CLASSID, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Not TS next in file");
1894   PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
1895   PetscCall(TSSetType(ts, type));
1896   PetscTryTypeMethod(ts, load, viewer);
1897   PetscCall(DMCreate(PetscObjectComm((PetscObject)ts), &dm));
1898   PetscCall(DMLoad(dm, viewer));
1899   PetscCall(TSSetDM(ts, dm));
1900   PetscCall(DMCreateGlobalVector(ts->dm, &ts->vec_sol));
1901   PetscCall(VecLoad(ts->vec_sol, viewer));
1902   PetscCall(DMGetDMTS(ts->dm, &sdm));
1903   PetscCall(DMTSLoad(sdm, viewer));
1904   PetscFunctionReturn(PETSC_SUCCESS);
1905 }
1906 
1907 #include <petscdraw.h>
1908 #if defined(PETSC_HAVE_SAWS)
1909   #include <petscviewersaws.h>
1910 #endif
1911 
1912 /*@C
1913   TSViewFromOptions - View a `TS` based on values in the options database
1914 
1915   Collective
1916 
1917   Input Parameters:
1918 + ts   - the `TS` context
1919 . obj  - Optional object that provides the prefix for the options database keys
1920 - name - command line option string to be passed by user
1921 
1922   Level: intermediate
1923 
1924 .seealso: [](ch_ts), `TS`, `TSView`, `PetscObjectViewFromOptions()`, `TSCreate()`
1925 @*/
1926 PetscErrorCode TSViewFromOptions(TS ts, PetscObject obj, const char name[])
1927 {
1928   PetscFunctionBegin;
1929   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1930   PetscCall(PetscObjectViewFromOptions((PetscObject)ts, obj, name));
1931   PetscFunctionReturn(PETSC_SUCCESS);
1932 }
1933 
1934 /*@C
1935   TSView - Prints the `TS` data structure.
1936 
1937   Collective
1938 
1939   Input Parameters:
1940 + ts     - the `TS` context obtained from `TSCreate()`
1941 - viewer - visualization context
1942 
1943   Options Database Key:
1944 . -ts_view - calls `TSView()` at end of `TSStep()`
1945 
1946   Level: beginner
1947 
1948   Notes:
1949   The available visualization contexts include
1950 +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
1951 -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
1952   output where only the first processor opens
1953   the file.  All other processors send their
1954   data to the first processor to print.
1955 
1956   The user can open an alternative visualization context with
1957   `PetscViewerASCIIOpen()` - output to a specified file.
1958 
1959   In the debugger you can do call `TSView`(ts,0) to display the `TS` solver. (The same holds for any PETSc object viewer).
1960 
1961 .seealso: [](ch_ts), `TS`, `PetscViewer`, `PetscViewerASCIIOpen()`
1962 @*/
1963 PetscErrorCode TSView(TS ts, PetscViewer viewer)
1964 {
1965   TSType    type;
1966   PetscBool iascii, isstring, isundials, isbinary, isdraw;
1967   DMTS      sdm;
1968 #if defined(PETSC_HAVE_SAWS)
1969   PetscBool issaws;
1970 #endif
1971 
1972   PetscFunctionBegin;
1973   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1974   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)ts), &viewer));
1975   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1976   PetscCheckSameComm(ts, 1, viewer, 2);
1977 
1978   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1979   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1980   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
1981   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1982 #if defined(PETSC_HAVE_SAWS)
1983   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1984 #endif
1985   if (iascii) {
1986     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)ts, viewer));
1987     if (ts->ops->view) {
1988       PetscCall(PetscViewerASCIIPushTab(viewer));
1989       PetscUseTypeMethod(ts, view, viewer);
1990       PetscCall(PetscViewerASCIIPopTab(viewer));
1991     }
1992     if (ts->max_steps < PETSC_MAX_INT) PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum steps=%" PetscInt_FMT "\n", ts->max_steps));
1993     if (ts->max_time < PETSC_MAX_REAL) PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum time=%g\n", (double)ts->max_time));
1994     if (ts->ifuncs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of I function evaluations=%" PetscInt_FMT "\n", ts->ifuncs));
1995     if (ts->ijacs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of I Jacobian evaluations=%" PetscInt_FMT "\n", ts->ijacs));
1996     if (ts->rhsfuncs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of RHS function evaluations=%" PetscInt_FMT "\n", ts->rhsfuncs));
1997     if (ts->rhsjacs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of RHS Jacobian evaluations=%" PetscInt_FMT "\n", ts->rhsjacs));
1998     if (ts->usessnes) {
1999       PetscBool lin;
2000       if (ts->problem_type == TS_NONLINEAR) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of nonlinear solver iterations=%" PetscInt_FMT "\n", ts->snes_its));
2001       PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of linear solver iterations=%" PetscInt_FMT "\n", ts->ksp_its));
2002       PetscCall(PetscObjectTypeCompareAny((PetscObject)ts->snes, &lin, SNESKSPONLY, SNESKSPTRANSPOSEONLY, ""));
2003       PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of %slinear solve failures=%" PetscInt_FMT "\n", lin ? "" : "non", ts->num_snes_failures));
2004     }
2005     PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of rejected steps=%" PetscInt_FMT "\n", ts->reject));
2006     if (ts->vrtol) PetscCall(PetscViewerASCIIPrintf(viewer, "  using vector of relative error tolerances, "));
2007     else PetscCall(PetscViewerASCIIPrintf(viewer, "  using relative error tolerance of %g, ", (double)ts->rtol));
2008     if (ts->vatol) PetscCall(PetscViewerASCIIPrintf(viewer, "  using vector of absolute error tolerances\n"));
2009     else PetscCall(PetscViewerASCIIPrintf(viewer, "  using absolute error tolerance of %g\n", (double)ts->atol));
2010     PetscCall(PetscViewerASCIIPushTab(viewer));
2011     PetscCall(TSAdaptView(ts->adapt, viewer));
2012     PetscCall(PetscViewerASCIIPopTab(viewer));
2013   } else if (isstring) {
2014     PetscCall(TSGetType(ts, &type));
2015     PetscCall(PetscViewerStringSPrintf(viewer, " TSType: %-7.7s", type));
2016     PetscTryTypeMethod(ts, view, viewer);
2017   } else if (isbinary) {
2018     PetscInt    classid = TS_FILE_CLASSID;
2019     MPI_Comm    comm;
2020     PetscMPIInt rank;
2021     char        type[256];
2022 
2023     PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
2024     PetscCallMPI(MPI_Comm_rank(comm, &rank));
2025     if (rank == 0) {
2026       PetscCall(PetscViewerBinaryWrite(viewer, &classid, 1, PETSC_INT));
2027       PetscCall(PetscStrncpy(type, ((PetscObject)ts)->type_name, 256));
2028       PetscCall(PetscViewerBinaryWrite(viewer, type, 256, PETSC_CHAR));
2029     }
2030     PetscTryTypeMethod(ts, view, viewer);
2031     if (ts->adapt) PetscCall(TSAdaptView(ts->adapt, viewer));
2032     PetscCall(DMView(ts->dm, viewer));
2033     PetscCall(VecView(ts->vec_sol, viewer));
2034     PetscCall(DMGetDMTS(ts->dm, &sdm));
2035     PetscCall(DMTSView(sdm, viewer));
2036   } else if (isdraw) {
2037     PetscDraw draw;
2038     char      str[36];
2039     PetscReal x, y, bottom, h;
2040 
2041     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2042     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
2043     PetscCall(PetscStrncpy(str, "TS: ", sizeof(str)));
2044     PetscCall(PetscStrlcat(str, ((PetscObject)ts)->type_name, sizeof(str)));
2045     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_BLACK, PETSC_DRAW_BLACK, str, NULL, &h));
2046     bottom = y - h;
2047     PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
2048     PetscTryTypeMethod(ts, view, viewer);
2049     if (ts->adapt) PetscCall(TSAdaptView(ts->adapt, viewer));
2050     if (ts->snes) PetscCall(SNESView(ts->snes, viewer));
2051     PetscCall(PetscDrawPopCurrentPoint(draw));
2052 #if defined(PETSC_HAVE_SAWS)
2053   } else if (issaws) {
2054     PetscMPIInt rank;
2055     const char *name;
2056 
2057     PetscCall(PetscObjectGetName((PetscObject)ts, &name));
2058     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2059     if (!((PetscObject)ts)->amsmem && rank == 0) {
2060       char dir[1024];
2061 
2062       PetscCall(PetscObjectViewSAWs((PetscObject)ts, viewer));
2063       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/time_step", name));
2064       PetscCallSAWs(SAWs_Register, (dir, &ts->steps, 1, SAWs_READ, SAWs_INT));
2065       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/time", name));
2066       PetscCallSAWs(SAWs_Register, (dir, &ts->ptime, 1, SAWs_READ, SAWs_DOUBLE));
2067     }
2068     PetscTryTypeMethod(ts, view, viewer);
2069 #endif
2070   }
2071   if (ts->snes && ts->usessnes) {
2072     PetscCall(PetscViewerASCIIPushTab(viewer));
2073     PetscCall(SNESView(ts->snes, viewer));
2074     PetscCall(PetscViewerASCIIPopTab(viewer));
2075   }
2076   PetscCall(DMGetDMTS(ts->dm, &sdm));
2077   PetscCall(DMTSView(sdm, viewer));
2078 
2079   PetscCall(PetscViewerASCIIPushTab(viewer));
2080   PetscCall(PetscObjectTypeCompare((PetscObject)ts, TSSUNDIALS, &isundials));
2081   PetscCall(PetscViewerASCIIPopTab(viewer));
2082   PetscFunctionReturn(PETSC_SUCCESS);
2083 }
2084 
2085 /*@
2086   TSSetApplicationContext - Sets an optional user-defined context for
2087   the timesteppers.
2088 
2089   Logically Collective
2090 
2091   Input Parameters:
2092 + ts   - the `TS` context obtained from `TSCreate()`
2093 - usrP - user context
2094 
2095   Level: intermediate
2096 
2097   Fortran Notes:
2098   You must write a Fortran interface definition for this
2099   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
2100 
2101 .seealso: [](ch_ts), `TS`, `TSGetApplicationContext()`
2102 @*/
2103 PetscErrorCode TSSetApplicationContext(TS ts, void *usrP)
2104 {
2105   PetscFunctionBegin;
2106   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2107   ts->user = usrP;
2108   PetscFunctionReturn(PETSC_SUCCESS);
2109 }
2110 
2111 /*@
2112   TSGetApplicationContext - Gets the user-defined context for the
2113   timestepper that was set with `TSSetApplicationContext()`
2114 
2115   Not Collective
2116 
2117   Input Parameter:
2118 . ts - the `TS` context obtained from `TSCreate()`
2119 
2120   Output Parameter:
2121 . usrP - user context
2122 
2123   Level: intermediate
2124 
2125   Fortran Notes:
2126   You must write a Fortran interface definition for this
2127   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
2128 
2129 .seealso: [](ch_ts), `TS`, `TSSetApplicationContext()`
2130 @*/
2131 PetscErrorCode TSGetApplicationContext(TS ts, void *usrP)
2132 {
2133   PetscFunctionBegin;
2134   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2135   *(void **)usrP = ts->user;
2136   PetscFunctionReturn(PETSC_SUCCESS);
2137 }
2138 
2139 /*@
2140   TSGetStepNumber - Gets the number of time steps completed.
2141 
2142   Not Collective
2143 
2144   Input Parameter:
2145 . ts - the `TS` context obtained from `TSCreate()`
2146 
2147   Output Parameter:
2148 . steps - number of steps completed so far
2149 
2150   Level: intermediate
2151 
2152 .seealso: [](ch_ts), `TS`, `TSGetTime()`, `TSGetTimeStep()`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostStage()`, `TSSetPostStep()`
2153 @*/
2154 PetscErrorCode TSGetStepNumber(TS ts, PetscInt *steps)
2155 {
2156   PetscFunctionBegin;
2157   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2158   PetscValidIntPointer(steps, 2);
2159   *steps = ts->steps;
2160   PetscFunctionReturn(PETSC_SUCCESS);
2161 }
2162 
2163 /*@
2164   TSSetStepNumber - Sets the number of steps completed.
2165 
2166   Logically Collective
2167 
2168   Input Parameters:
2169 + ts    - the `TS` context
2170 - steps - number of steps completed so far
2171 
2172   Level: developer
2173 
2174   Note:
2175   For most uses of the `TS` solvers the user need not explicitly call
2176   `TSSetStepNumber()`, as the step counter is appropriately updated in
2177   `TSSolve()`/`TSStep()`/`TSRollBack()`. Power users may call this routine to
2178   reinitialize timestepping by setting the step counter to zero (and time
2179   to the initial time) to solve a similar problem with different initial
2180   conditions or parameters. Other possible use case is to continue
2181   timestepping from a previously interrupted run in such a way that `TS`
2182   monitors will be called with a initial nonzero step counter.
2183 
2184 .seealso: [](ch_ts), `TS`, `TSGetStepNumber()`, `TSSetTime()`, `TSSetTimeStep()`, `TSSetSolution()`
2185 @*/
2186 PetscErrorCode TSSetStepNumber(TS ts, PetscInt steps)
2187 {
2188   PetscFunctionBegin;
2189   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2190   PetscValidLogicalCollectiveInt(ts, steps, 2);
2191   PetscCheck(steps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Step number must be non-negative");
2192   ts->steps = steps;
2193   PetscFunctionReturn(PETSC_SUCCESS);
2194 }
2195 
2196 /*@
2197   TSSetTimeStep - Allows one to reset the timestep at any time,
2198   useful for simple pseudo-timestepping codes.
2199 
2200   Logically Collective
2201 
2202   Input Parameters:
2203 + ts        - the `TS` context obtained from `TSCreate()`
2204 - time_step - the size of the timestep
2205 
2206   Level: intermediate
2207 
2208 .seealso: [](ch_ts), `TS`, `TSPSEUDO`, `TSGetTimeStep()`, `TSSetTime()`
2209 @*/
2210 PetscErrorCode TSSetTimeStep(TS ts, PetscReal time_step)
2211 {
2212   PetscFunctionBegin;
2213   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2214   PetscValidLogicalCollectiveReal(ts, time_step, 2);
2215   ts->time_step = time_step;
2216   PetscFunctionReturn(PETSC_SUCCESS);
2217 }
2218 
2219 /*@
2220   TSSetExactFinalTime - Determines whether to adapt the final time step to
2221   match the exact final time, interpolate solution to the exact final time,
2222   or just return at the final time `TS` computed.
2223 
2224   Logically Collective
2225 
2226   Input Parameters:
2227 + ts     - the time-step context
2228 - eftopt - exact final time option
2229 .vb
2230   TS_EXACTFINALTIME_STEPOVER    - Don't do anything if final time is exceeded
2231   TS_EXACTFINALTIME_INTERPOLATE - Interpolate back to final time
2232   TS_EXACTFINALTIME_MATCHSTEP - Adapt final time step to match the final time
2233 .ve
2234 
2235   Options Database Key:
2236 . -ts_exact_final_time <stepover,interpolate,matchstep> - select the final step at runtime
2237 
2238   Level: beginner
2239 
2240   Note:
2241   If you use the option `TS_EXACTFINALTIME_STEPOVER` the solution may be at a very different time
2242   then the final time you selected.
2243 
2244 .seealso: [](ch_ts), `TS`, `TSExactFinalTimeOption`, `TSGetExactFinalTime()`
2245 @*/
2246 PetscErrorCode TSSetExactFinalTime(TS ts, TSExactFinalTimeOption eftopt)
2247 {
2248   PetscFunctionBegin;
2249   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2250   PetscValidLogicalCollectiveEnum(ts, eftopt, 2);
2251   ts->exact_final_time = eftopt;
2252   PetscFunctionReturn(PETSC_SUCCESS);
2253 }
2254 
2255 /*@
2256   TSGetExactFinalTime - Gets the exact final time option set with `TSSetExactFinalTime()`
2257 
2258   Not Collective
2259 
2260   Input Parameter:
2261 . ts - the `TS` context
2262 
2263   Output Parameter:
2264 . eftopt - exact final time option
2265 
2266   Level: beginner
2267 
2268 .seealso: [](ch_ts), `TS`, `TSExactFinalTimeOption`, `TSSetExactFinalTime()`
2269 @*/
2270 PetscErrorCode TSGetExactFinalTime(TS ts, TSExactFinalTimeOption *eftopt)
2271 {
2272   PetscFunctionBegin;
2273   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2274   PetscValidPointer(eftopt, 2);
2275   *eftopt = ts->exact_final_time;
2276   PetscFunctionReturn(PETSC_SUCCESS);
2277 }
2278 
2279 /*@
2280   TSGetTimeStep - Gets the current timestep size.
2281 
2282   Not Collective
2283 
2284   Input Parameter:
2285 . ts - the `TS` context obtained from `TSCreate()`
2286 
2287   Output Parameter:
2288 . dt - the current timestep size
2289 
2290   Level: intermediate
2291 
2292 .seealso: [](ch_ts), `TS`, `TSSetTimeStep()`, `TSGetTime()`
2293 @*/
2294 PetscErrorCode TSGetTimeStep(TS ts, PetscReal *dt)
2295 {
2296   PetscFunctionBegin;
2297   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2298   PetscValidRealPointer(dt, 2);
2299   *dt = ts->time_step;
2300   PetscFunctionReturn(PETSC_SUCCESS);
2301 }
2302 
2303 /*@
2304   TSGetSolution - Returns the solution at the present timestep. It
2305   is valid to call this routine inside the function that you are evaluating
2306   in order to move to the new timestep. This vector not changed until
2307   the solution at the next timestep has been calculated.
2308 
2309   Not Collective, but v returned is parallel if ts is parallel
2310 
2311   Input Parameter:
2312 . ts - the `TS` context obtained from `TSCreate()`
2313 
2314   Output Parameter:
2315 . v - the vector containing the solution
2316 
2317   Level: intermediate
2318 
2319   Note:
2320   If you used `TSSetExactFinalTime`(ts,`TS_EXACTFINALTIME_MATCHSTEP`); this does not return the solution at the requested
2321   final time. It returns the solution at the next timestep.
2322 
2323 .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetTime()`, `TSGetSolveTime()`, `TSGetSolutionComponents()`, `TSSetSolutionFunction()`
2324 @*/
2325 PetscErrorCode TSGetSolution(TS ts, Vec *v)
2326 {
2327   PetscFunctionBegin;
2328   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2329   PetscValidPointer(v, 2);
2330   *v = ts->vec_sol;
2331   PetscFunctionReturn(PETSC_SUCCESS);
2332 }
2333 
2334 /*@
2335   TSGetSolutionComponents - Returns any solution components at the present
2336   timestep, if available for the time integration method being used.
2337   Solution components are quantities that share the same size and
2338   structure as the solution vector.
2339 
2340   Not Collective, but v returned is parallel if ts is parallel
2341 
2342   Input Parameters:
2343 + ts - the `TS` context obtained from `TSCreate()` (input parameter).
2344 . n  - If v is `NULL`, then the number of solution components is
2345        returned through n, else the n-th solution component is
2346        returned in v.
2347 - v  - the vector containing the n-th solution component
2348        (may be `NULL` to use this function to find out
2349         the number of solutions components).
2350 
2351   Level: advanced
2352 
2353 .seealso: [](ch_ts), `TS`, `TSGetSolution()`
2354 @*/
2355 PetscErrorCode TSGetSolutionComponents(TS ts, PetscInt *n, Vec *v)
2356 {
2357   PetscFunctionBegin;
2358   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2359   if (!ts->ops->getsolutioncomponents) *n = 0;
2360   else PetscUseTypeMethod(ts, getsolutioncomponents, n, v);
2361   PetscFunctionReturn(PETSC_SUCCESS);
2362 }
2363 
2364 /*@
2365   TSGetAuxSolution - Returns an auxiliary solution at the present
2366   timestep, if available for the time integration method being used.
2367 
2368   Not Collective, but v returned is parallel if ts is parallel
2369 
2370   Input Parameters:
2371 + ts - the `TS` context obtained from `TSCreate()` (input parameter).
2372 - v  - the vector containing the auxiliary solution
2373 
2374   Level: intermediate
2375 
2376 .seealso: [](ch_ts), `TS`, `TSGetSolution()`
2377 @*/
2378 PetscErrorCode TSGetAuxSolution(TS ts, Vec *v)
2379 {
2380   PetscFunctionBegin;
2381   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2382   if (ts->ops->getauxsolution) PetscUseTypeMethod(ts, getauxsolution, v);
2383   else PetscCall(VecZeroEntries(*v));
2384   PetscFunctionReturn(PETSC_SUCCESS);
2385 }
2386 
2387 /*@
2388   TSGetTimeError - Returns the estimated error vector, if the chosen
2389   `TSType` has an error estimation functionality and `TSSetTimeError()` was called
2390 
2391   Not Collective, but v returned is parallel if ts is parallel
2392 
2393   Input Parameters:
2394 + ts - the `TS` context obtained from `TSCreate()` (input parameter).
2395 . n  - current estimate (n=0) or previous one (n=-1)
2396 - v  - the vector containing the error (same size as the solution).
2397 
2398   Level: intermediate
2399 
2400   Note:
2401   MUST call after `TSSetUp()`
2402 
2403 .seealso: [](ch_ts), `TSGetSolution()`, `TSSetTimeError()`
2404 @*/
2405 PetscErrorCode TSGetTimeError(TS ts, PetscInt n, Vec *v)
2406 {
2407   PetscFunctionBegin;
2408   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2409   if (ts->ops->gettimeerror) PetscUseTypeMethod(ts, gettimeerror, n, v);
2410   else PetscCall(VecZeroEntries(*v));
2411   PetscFunctionReturn(PETSC_SUCCESS);
2412 }
2413 
2414 /*@
2415   TSSetTimeError - Sets the estimated error vector, if the chosen
2416   `TSType` has an error estimation functionality. This can be used
2417   to restart such a time integrator with a given error vector.
2418 
2419   Not Collective, but v returned is parallel if ts is parallel
2420 
2421   Input Parameters:
2422 + ts - the `TS` context obtained from `TSCreate()` (input parameter).
2423 - v  - the vector containing the error (same size as the solution).
2424 
2425   Level: intermediate
2426 
2427 .seealso: [](ch_ts), `TS`, `TSSetSolution()`, `TSGetTimeError()`
2428 @*/
2429 PetscErrorCode TSSetTimeError(TS ts, Vec v)
2430 {
2431   PetscFunctionBegin;
2432   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2433   PetscCheck(ts->setupcalled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetUp() first");
2434   PetscTryTypeMethod(ts, settimeerror, v);
2435   PetscFunctionReturn(PETSC_SUCCESS);
2436 }
2437 
2438 /* ----- Routines to initialize and destroy a timestepper ---- */
2439 /*@
2440   TSSetProblemType - Sets the type of problem to be solved.
2441 
2442   Not collective
2443 
2444   Input Parameters:
2445 + ts   - The `TS`
2446 - type - One of `TS_LINEAR`, `TS_NONLINEAR` where these types refer to problems of the forms
2447 .vb
2448          U_t - A U = 0      (linear)
2449          U_t - A(t) U = 0   (linear)
2450          F(t,U,U_t) = 0     (nonlinear)
2451 .ve
2452 
2453   Level: beginner
2454 
2455 .seealso: [](ch_ts), `TSSetUp()`, `TSProblemType`, `TS`
2456 @*/
2457 PetscErrorCode TSSetProblemType(TS ts, TSProblemType type)
2458 {
2459   PetscFunctionBegin;
2460   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2461   ts->problem_type = type;
2462   if (type == TS_LINEAR) {
2463     SNES snes;
2464     PetscCall(TSGetSNES(ts, &snes));
2465     PetscCall(SNESSetType(snes, SNESKSPONLY));
2466   }
2467   PetscFunctionReturn(PETSC_SUCCESS);
2468 }
2469 
2470 /*@C
2471   TSGetProblemType - Gets the type of problem to be solved.
2472 
2473   Not collective
2474 
2475   Input Parameter:
2476 . ts - The `TS`
2477 
2478   Output Parameter:
2479 . type - One of `TS_LINEAR`, `TS_NONLINEAR` where these types refer to problems of the forms
2480 .vb
2481          M U_t = A U
2482          M(t) U_t = A(t) U
2483          F(t,U,U_t)
2484 .ve
2485 
2486   Level: beginner
2487 
2488 .seealso: [](ch_ts), `TSSetUp()`, `TSProblemType`, `TS`
2489 @*/
2490 PetscErrorCode TSGetProblemType(TS ts, TSProblemType *type)
2491 {
2492   PetscFunctionBegin;
2493   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2494   PetscValidIntPointer(type, 2);
2495   *type = ts->problem_type;
2496   PetscFunctionReturn(PETSC_SUCCESS);
2497 }
2498 
2499 /*
2500     Attempt to check/preset a default value for the exact final time option. This is needed at the beginning of TSSolve() and in TSSetUp()
2501 */
2502 static PetscErrorCode TSSetExactFinalTimeDefault(TS ts)
2503 {
2504   PetscBool isnone;
2505 
2506   PetscFunctionBegin;
2507   PetscCall(TSGetAdapt(ts, &ts->adapt));
2508   PetscCall(TSAdaptSetDefaultType(ts->adapt, ts->default_adapt_type));
2509 
2510   PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &isnone));
2511   if (!isnone && ts->exact_final_time == TS_EXACTFINALTIME_UNSPECIFIED) ts->exact_final_time = TS_EXACTFINALTIME_MATCHSTEP;
2512   else if (ts->exact_final_time == TS_EXACTFINALTIME_UNSPECIFIED) ts->exact_final_time = TS_EXACTFINALTIME_INTERPOLATE;
2513   PetscFunctionReturn(PETSC_SUCCESS);
2514 }
2515 
2516 /*@
2517   TSSetUp - Sets up the internal data structures for the later use of a timestepper.
2518 
2519   Collective
2520 
2521   Input Parameter:
2522 . ts - the `TS` context obtained from `TSCreate()`
2523 
2524   Level: advanced
2525 
2526   Note:
2527   For basic use of the `TS` solvers the user need not explicitly call
2528   `TSSetUp()`, since these actions will automatically occur during
2529   the call to `TSStep()` or `TSSolve()`.  However, if one wishes to control this
2530   phase separately, `TSSetUp()` should be called after `TSCreate()`
2531   and optional routines of the form TSSetXXX(), but before `TSStep()` and `TSSolve()`.
2532 
2533 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSStep()`, `TSDestroy()`, `TSSolve()`
2534 @*/
2535 PetscErrorCode TSSetUp(TS ts)
2536 {
2537   DM dm;
2538   PetscErrorCode (*func)(SNES, Vec, Vec, void *);
2539   PetscErrorCode (*jac)(SNES, Vec, Mat, Mat, void *);
2540   TSIFunction   ifun;
2541   TSIJacobian   ijac;
2542   TSI2Jacobian  i2jac;
2543   TSRHSJacobian rhsjac;
2544 
2545   PetscFunctionBegin;
2546   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2547   if (ts->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
2548 
2549   if (!((PetscObject)ts)->type_name) {
2550     PetscCall(TSGetIFunction(ts, NULL, &ifun, NULL));
2551     PetscCall(TSSetType(ts, ifun ? TSBEULER : TSEULER));
2552   }
2553 
2554   if (!ts->vec_sol) {
2555     PetscCheck(ts->dm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetSolution() first");
2556     PetscCall(DMCreateGlobalVector(ts->dm, &ts->vec_sol));
2557   }
2558 
2559   if (ts->tspan) {
2560     if (!ts->tspan->vecs_sol) PetscCall(VecDuplicateVecs(ts->vec_sol, ts->tspan->num_span_times, &ts->tspan->vecs_sol));
2561   }
2562   if (!ts->Jacp && ts->Jacprhs) { /* IJacobianP shares the same matrix with RHSJacobianP if only RHSJacobianP is provided */
2563     PetscCall(PetscObjectReference((PetscObject)ts->Jacprhs));
2564     ts->Jacp = ts->Jacprhs;
2565   }
2566 
2567   if (ts->quadraturets) {
2568     PetscCall(TSSetUp(ts->quadraturets));
2569     PetscCall(VecDestroy(&ts->vec_costintegrand));
2570     PetscCall(VecDuplicate(ts->quadraturets->vec_sol, &ts->vec_costintegrand));
2571   }
2572 
2573   PetscCall(TSGetRHSJacobian(ts, NULL, NULL, &rhsjac, NULL));
2574   if (rhsjac == TSComputeRHSJacobianConstant) {
2575     Mat  Amat, Pmat;
2576     SNES snes;
2577     PetscCall(TSGetSNES(ts, &snes));
2578     PetscCall(SNESGetJacobian(snes, &Amat, &Pmat, NULL, NULL));
2579     /* Matching matrices implies that an IJacobian is NOT set, because if it had been set, the IJacobian's matrix would
2580      * have displaced the RHS matrix */
2581     if (Amat && Amat == ts->Arhs) {
2582       /* we need to copy the values of the matrix because for the constant Jacobian case the user will never set the numerical values in this new location */
2583       PetscCall(MatDuplicate(ts->Arhs, MAT_COPY_VALUES, &Amat));
2584       PetscCall(SNESSetJacobian(snes, Amat, NULL, NULL, NULL));
2585       PetscCall(MatDestroy(&Amat));
2586     }
2587     if (Pmat && Pmat == ts->Brhs) {
2588       PetscCall(MatDuplicate(ts->Brhs, MAT_COPY_VALUES, &Pmat));
2589       PetscCall(SNESSetJacobian(snes, NULL, Pmat, NULL, NULL));
2590       PetscCall(MatDestroy(&Pmat));
2591     }
2592   }
2593 
2594   PetscCall(TSGetAdapt(ts, &ts->adapt));
2595   PetscCall(TSAdaptSetDefaultType(ts->adapt, ts->default_adapt_type));
2596 
2597   PetscTryTypeMethod(ts, setup);
2598 
2599   PetscCall(TSSetExactFinalTimeDefault(ts));
2600 
2601   /* In the case where we've set a DMTSFunction or what have you, we need the default SNESFunction
2602      to be set right but can't do it elsewhere due to the overreliance on ctx=ts.
2603    */
2604   PetscCall(TSGetDM(ts, &dm));
2605   PetscCall(DMSNESGetFunction(dm, &func, NULL));
2606   if (!func) PetscCall(DMSNESSetFunction(dm, SNESTSFormFunction, ts));
2607 
2608   /* If the SNES doesn't have a jacobian set and the TS has an ijacobian or rhsjacobian set, set the SNES to use it.
2609      Otherwise, the SNES will use coloring internally to form the Jacobian.
2610    */
2611   PetscCall(DMSNESGetJacobian(dm, &jac, NULL));
2612   PetscCall(DMTSGetIJacobian(dm, &ijac, NULL));
2613   PetscCall(DMTSGetI2Jacobian(dm, &i2jac, NULL));
2614   PetscCall(DMTSGetRHSJacobian(dm, &rhsjac, NULL));
2615   if (!jac && (ijac || i2jac || rhsjac)) PetscCall(DMSNESSetJacobian(dm, SNESTSFormJacobian, ts));
2616 
2617   /* if time integration scheme has a starting method, call it */
2618   PetscTryTypeMethod(ts, startingmethod);
2619 
2620   ts->setupcalled = PETSC_TRUE;
2621   PetscFunctionReturn(PETSC_SUCCESS);
2622 }
2623 
2624 /*@
2625   TSReset - Resets a `TS` context and removes any allocated `Vec`s and `Mat`s.
2626 
2627   Collective
2628 
2629   Input Parameter:
2630 . ts - the `TS` context obtained from `TSCreate()`
2631 
2632   Level: beginner
2633 
2634 .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetup()`, `TSDestroy()`
2635 @*/
2636 PetscErrorCode TSReset(TS ts)
2637 {
2638   TS_RHSSplitLink ilink = ts->tsrhssplit, next;
2639 
2640   PetscFunctionBegin;
2641   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2642 
2643   PetscTryTypeMethod(ts, reset);
2644   if (ts->snes) PetscCall(SNESReset(ts->snes));
2645   if (ts->adapt) PetscCall(TSAdaptReset(ts->adapt));
2646 
2647   PetscCall(MatDestroy(&ts->Arhs));
2648   PetscCall(MatDestroy(&ts->Brhs));
2649   PetscCall(VecDestroy(&ts->Frhs));
2650   PetscCall(VecDestroy(&ts->vec_sol));
2651   PetscCall(VecDestroy(&ts->vec_dot));
2652   PetscCall(VecDestroy(&ts->vatol));
2653   PetscCall(VecDestroy(&ts->vrtol));
2654   PetscCall(VecDestroyVecs(ts->nwork, &ts->work));
2655 
2656   PetscCall(MatDestroy(&ts->Jacprhs));
2657   PetscCall(MatDestroy(&ts->Jacp));
2658   if (ts->forward_solve) PetscCall(TSForwardReset(ts));
2659   if (ts->quadraturets) {
2660     PetscCall(TSReset(ts->quadraturets));
2661     PetscCall(VecDestroy(&ts->vec_costintegrand));
2662   }
2663   while (ilink) {
2664     next = ilink->next;
2665     PetscCall(TSDestroy(&ilink->ts));
2666     PetscCall(PetscFree(ilink->splitname));
2667     PetscCall(ISDestroy(&ilink->is));
2668     PetscCall(PetscFree(ilink));
2669     ilink = next;
2670   }
2671   ts->tsrhssplit     = NULL;
2672   ts->num_rhs_splits = 0;
2673   if (ts->tspan) {
2674     PetscCall(PetscFree(ts->tspan->span_times));
2675     PetscCall(VecDestroyVecs(ts->tspan->num_span_times, &ts->tspan->vecs_sol));
2676     PetscCall(PetscFree(ts->tspan));
2677   }
2678   ts->setupcalled = PETSC_FALSE;
2679   PetscFunctionReturn(PETSC_SUCCESS);
2680 }
2681 
2682 /*@C
2683   TSDestroy - Destroys the timestepper context that was created
2684   with `TSCreate()`.
2685 
2686   Collective
2687 
2688   Input Parameter:
2689 . ts - the `TS` context obtained from `TSCreate()`
2690 
2691   Level: beginner
2692 
2693 .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetUp()`, `TSSolve()`
2694 @*/
2695 PetscErrorCode TSDestroy(TS *ts)
2696 {
2697   PetscFunctionBegin;
2698   if (!*ts) PetscFunctionReturn(PETSC_SUCCESS);
2699   PetscValidHeaderSpecific(*ts, TS_CLASSID, 1);
2700   if (--((PetscObject)(*ts))->refct > 0) {
2701     *ts = NULL;
2702     PetscFunctionReturn(PETSC_SUCCESS);
2703   }
2704 
2705   PetscCall(TSReset(*ts));
2706   PetscCall(TSAdjointReset(*ts));
2707   if ((*ts)->forward_solve) PetscCall(TSForwardReset(*ts));
2708 
2709   /* if memory was published with SAWs then destroy it */
2710   PetscCall(PetscObjectSAWsViewOff((PetscObject)*ts));
2711   PetscTryTypeMethod((*ts), destroy);
2712 
2713   PetscCall(TSTrajectoryDestroy(&(*ts)->trajectory));
2714 
2715   PetscCall(TSAdaptDestroy(&(*ts)->adapt));
2716   PetscCall(TSEventDestroy(&(*ts)->event));
2717 
2718   PetscCall(SNESDestroy(&(*ts)->snes));
2719   PetscCall(DMDestroy(&(*ts)->dm));
2720   PetscCall(TSMonitorCancel((*ts)));
2721   PetscCall(TSAdjointMonitorCancel((*ts)));
2722 
2723   PetscCall(TSDestroy(&(*ts)->quadraturets));
2724   PetscCall(PetscHeaderDestroy(ts));
2725   PetscFunctionReturn(PETSC_SUCCESS);
2726 }
2727 
2728 /*@
2729   TSGetSNES - Returns the `SNES` (nonlinear solver) associated with
2730   a `TS` (timestepper) context. Valid only for nonlinear problems.
2731 
2732   Not Collective, but snes is parallel if ts is parallel
2733 
2734   Input Parameter:
2735 . ts - the `TS` context obtained from `TSCreate()`
2736 
2737   Output Parameter:
2738 . snes - the nonlinear solver context
2739 
2740   Level: beginner
2741 
2742   Notes:
2743   The user can then directly manipulate the `SNES` context to set various
2744   options, etc.  Likewise, the user can then extract and manipulate the
2745   `KSP`, and `PC` contexts as well.
2746 
2747   `TSGetSNES()` does not work for integrators that do not use `SNES`; in
2748   this case `TSGetSNES()` returns `NULL` in `snes`.
2749 
2750 .seealso: [](ch_ts), `TS`, `SNES`, `TSCreate()`, `TSSetUp()`, `TSSolve()`
2751 @*/
2752 PetscErrorCode TSGetSNES(TS ts, SNES *snes)
2753 {
2754   PetscFunctionBegin;
2755   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2756   PetscValidPointer(snes, 2);
2757   if (!ts->snes) {
2758     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ts), &ts->snes));
2759     PetscCall(PetscObjectSetOptions((PetscObject)ts->snes, ((PetscObject)ts)->options));
2760     PetscCall(SNESSetFunction(ts->snes, NULL, SNESTSFormFunction, ts));
2761     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->snes, (PetscObject)ts, 1));
2762     if (ts->dm) PetscCall(SNESSetDM(ts->snes, ts->dm));
2763     if (ts->problem_type == TS_LINEAR) PetscCall(SNESSetType(ts->snes, SNESKSPONLY));
2764   }
2765   *snes = ts->snes;
2766   PetscFunctionReturn(PETSC_SUCCESS);
2767 }
2768 
2769 /*@
2770   TSSetSNES - Set the `SNES` (nonlinear solver) to be used by the timestepping context
2771 
2772   Collective
2773 
2774   Input Parameters:
2775 + ts   - the `TS` context obtained from `TSCreate()`
2776 - snes - the nonlinear solver context
2777 
2778   Level: developer
2779 
2780   Note:
2781   Most users should have the `TS` created by calling `TSGetSNES()`
2782 
2783 .seealso: [](ch_ts), `TS`, `SNES`, `TSCreate()`, `TSSetUp()`, `TSSolve()`, `TSGetSNES()`
2784 @*/
2785 PetscErrorCode TSSetSNES(TS ts, SNES snes)
2786 {
2787   PetscErrorCode (*func)(SNES, Vec, Mat, Mat, void *);
2788 
2789   PetscFunctionBegin;
2790   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2791   PetscValidHeaderSpecific(snes, SNES_CLASSID, 2);
2792   PetscCall(PetscObjectReference((PetscObject)snes));
2793   PetscCall(SNESDestroy(&ts->snes));
2794 
2795   ts->snes = snes;
2796 
2797   PetscCall(SNESSetFunction(ts->snes, NULL, SNESTSFormFunction, ts));
2798   PetscCall(SNESGetJacobian(ts->snes, NULL, NULL, &func, NULL));
2799   if (func == SNESTSFormJacobian) PetscCall(SNESSetJacobian(ts->snes, NULL, NULL, SNESTSFormJacobian, ts));
2800   PetscFunctionReturn(PETSC_SUCCESS);
2801 }
2802 
2803 /*@
2804   TSGetKSP - Returns the `KSP` (linear solver) associated with
2805   a `TS` (timestepper) context.
2806 
2807   Not Collective, but `ksp` is parallel if `ts` is parallel
2808 
2809   Input Parameter:
2810 . ts - the `TS` context obtained from `TSCreate()`
2811 
2812   Output Parameter:
2813 . ksp - the nonlinear solver context
2814 
2815   Level: beginner
2816 
2817   Notes:
2818   The user can then directly manipulate the `KSP` context to set various
2819   options, etc.  Likewise, the user can then extract and manipulate the
2820   `PC` context as well.
2821 
2822   `TSGetKSP()` does not work for integrators that do not use `KSP`;
2823   in this case `TSGetKSP()` returns `NULL` in `ksp`.
2824 
2825 .seealso: [](ch_ts), `TS`, `SNES`, `KSP`, `TSCreate()`, `TSSetUp()`, `TSSolve()`, `TSGetSNES()`
2826 @*/
2827 PetscErrorCode TSGetKSP(TS ts, KSP *ksp)
2828 {
2829   SNES snes;
2830 
2831   PetscFunctionBegin;
2832   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2833   PetscValidPointer(ksp, 2);
2834   PetscCheck(((PetscObject)ts)->type_name, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "KSP is not created yet. Call TSSetType() first");
2835   PetscCheck(ts->problem_type == TS_LINEAR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Linear only; use TSGetSNES()");
2836   PetscCall(TSGetSNES(ts, &snes));
2837   PetscCall(SNESGetKSP(snes, ksp));
2838   PetscFunctionReturn(PETSC_SUCCESS);
2839 }
2840 
2841 /* ----------- Routines to set solver parameters ---------- */
2842 
2843 /*@
2844   TSSetMaxSteps - Sets the maximum number of steps to use.
2845 
2846   Logically Collective
2847 
2848   Input Parameters:
2849 + ts       - the `TS` context obtained from `TSCreate()`
2850 - maxsteps - maximum number of steps to use
2851 
2852   Options Database Key:
2853 . -ts_max_steps <maxsteps> - Sets maxsteps
2854 
2855   Level: intermediate
2856 
2857   Note:
2858   The default maximum number of steps is 5000
2859 
2860 .seealso: [](ch_ts), `TS`, `TSGetMaxSteps()`, `TSSetMaxTime()`, `TSSetExactFinalTime()`
2861 @*/
2862 PetscErrorCode TSSetMaxSteps(TS ts, PetscInt maxsteps)
2863 {
2864   PetscFunctionBegin;
2865   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2866   PetscValidLogicalCollectiveInt(ts, maxsteps, 2);
2867   PetscCheck(maxsteps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of steps must be non-negative");
2868   ts->max_steps = maxsteps;
2869   PetscFunctionReturn(PETSC_SUCCESS);
2870 }
2871 
2872 /*@
2873   TSGetMaxSteps - Gets the maximum number of steps to use.
2874 
2875   Not Collective
2876 
2877   Input Parameter:
2878 . ts - the `TS` context obtained from `TSCreate()`
2879 
2880   Output Parameter:
2881 . maxsteps - maximum number of steps to use
2882 
2883   Level: advanced
2884 
2885 .seealso: [](ch_ts), `TS`, `TSSetMaxSteps()`, `TSGetMaxTime()`, `TSSetMaxTime()`
2886 @*/
2887 PetscErrorCode TSGetMaxSteps(TS ts, PetscInt *maxsteps)
2888 {
2889   PetscFunctionBegin;
2890   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2891   PetscValidIntPointer(maxsteps, 2);
2892   *maxsteps = ts->max_steps;
2893   PetscFunctionReturn(PETSC_SUCCESS);
2894 }
2895 
2896 /*@
2897   TSSetMaxTime - Sets the maximum (or final) time for timestepping.
2898 
2899   Logically Collective
2900 
2901   Input Parameters:
2902 + ts      - the `TS` context obtained from `TSCreate()`
2903 - maxtime - final time to step to
2904 
2905   Options Database Key:
2906 . -ts_max_time <maxtime> - Sets maxtime
2907 
2908   Level: intermediate
2909 
2910   Notes:
2911   The default maximum time is 5.0
2912 
2913 .seealso: [](ch_ts), `TS`, `TSGetMaxTime()`, `TSSetMaxSteps()`, `TSSetExactFinalTime()`
2914 @*/
2915 PetscErrorCode TSSetMaxTime(TS ts, PetscReal maxtime)
2916 {
2917   PetscFunctionBegin;
2918   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2919   PetscValidLogicalCollectiveReal(ts, maxtime, 2);
2920   ts->max_time = maxtime;
2921   PetscFunctionReturn(PETSC_SUCCESS);
2922 }
2923 
2924 /*@
2925   TSGetMaxTime - Gets the maximum (or final) time for timestepping.
2926 
2927   Not Collective
2928 
2929   Input Parameter:
2930 . ts - the `TS` context obtained from `TSCreate()`
2931 
2932   Output Parameter:
2933 . maxtime - final time to step to
2934 
2935   Level: advanced
2936 
2937 .seealso: [](ch_ts), `TS`, `TSSetMaxTime()`, `TSGetMaxSteps()`, `TSSetMaxSteps()`
2938 @*/
2939 PetscErrorCode TSGetMaxTime(TS ts, PetscReal *maxtime)
2940 {
2941   PetscFunctionBegin;
2942   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2943   PetscValidRealPointer(maxtime, 2);
2944   *maxtime = ts->max_time;
2945   PetscFunctionReturn(PETSC_SUCCESS);
2946 }
2947 
2948 /*@
2949   TSSetInitialTimeStep - Deprecated, use `TSSetTime()` and `TSSetTimeStep()`.
2950 
2951   Level: deprecated
2952 
2953 @*/
2954 PetscErrorCode TSSetInitialTimeStep(TS ts, PetscReal initial_time, PetscReal time_step)
2955 {
2956   PetscFunctionBegin;
2957   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2958   PetscCall(TSSetTime(ts, initial_time));
2959   PetscCall(TSSetTimeStep(ts, time_step));
2960   PetscFunctionReturn(PETSC_SUCCESS);
2961 }
2962 
2963 /*@
2964   TSGetDuration - Deprecated, use `TSGetMaxSteps()` and `TSGetMaxTime()`.
2965 
2966   Level: deprecated
2967 
2968 @*/
2969 PetscErrorCode TSGetDuration(TS ts, PetscInt *maxsteps, PetscReal *maxtime)
2970 {
2971   PetscFunctionBegin;
2972   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2973   if (maxsteps) {
2974     PetscValidIntPointer(maxsteps, 2);
2975     *maxsteps = ts->max_steps;
2976   }
2977   if (maxtime) {
2978     PetscValidRealPointer(maxtime, 3);
2979     *maxtime = ts->max_time;
2980   }
2981   PetscFunctionReturn(PETSC_SUCCESS);
2982 }
2983 
2984 /*@
2985   TSSetDuration - Deprecated, use `TSSetMaxSteps()` and `TSSetMaxTime()`.
2986 
2987   Level: deprecated
2988 
2989 @*/
2990 PetscErrorCode TSSetDuration(TS ts, PetscInt maxsteps, PetscReal maxtime)
2991 {
2992   PetscFunctionBegin;
2993   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
2994   PetscValidLogicalCollectiveInt(ts, maxsteps, 2);
2995   PetscValidLogicalCollectiveReal(ts, maxtime, 3);
2996   if (maxsteps >= 0) ts->max_steps = maxsteps;
2997   if (maxtime != (PetscReal)PETSC_DEFAULT) ts->max_time = maxtime;
2998   PetscFunctionReturn(PETSC_SUCCESS);
2999 }
3000 
3001 /*@
3002   TSGetTimeStepNumber - Deprecated, use `TSGetStepNumber()`.
3003 
3004   Level: deprecated
3005 
3006 @*/
3007 PetscErrorCode TSGetTimeStepNumber(TS ts, PetscInt *steps)
3008 {
3009   return TSGetStepNumber(ts, steps);
3010 }
3011 
3012 /*@
3013   TSGetTotalSteps - Deprecated, use `TSGetStepNumber()`.
3014 
3015   Level: deprecated
3016 
3017 @*/
3018 PetscErrorCode TSGetTotalSteps(TS ts, PetscInt *steps)
3019 {
3020   return TSGetStepNumber(ts, steps);
3021 }
3022 
3023 /*@
3024   TSSetSolution - Sets the initial solution vector
3025   for use by the `TS` routines.
3026 
3027   Logically Collective
3028 
3029   Input Parameters:
3030 + ts - the `TS` context obtained from `TSCreate()`
3031 - u  - the solution vector
3032 
3033   Level: beginner
3034 
3035 .seealso: [](ch_ts), `TS`, `TSSetSolutionFunction()`, `TSGetSolution()`, `TSCreate()`
3036 @*/
3037 PetscErrorCode TSSetSolution(TS ts, Vec u)
3038 {
3039   DM dm;
3040 
3041   PetscFunctionBegin;
3042   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3043   PetscValidHeaderSpecific(u, VEC_CLASSID, 2);
3044   PetscCall(PetscObjectReference((PetscObject)u));
3045   PetscCall(VecDestroy(&ts->vec_sol));
3046   ts->vec_sol = u;
3047 
3048   PetscCall(TSGetDM(ts, &dm));
3049   PetscCall(DMShellSetGlobalVector(dm, u));
3050   PetscFunctionReturn(PETSC_SUCCESS);
3051 }
3052 
3053 /*@C
3054   TSSetPreStep - Sets the general-purpose function
3055   called once at the beginning of each time step.
3056 
3057   Logically Collective
3058 
3059   Input Parameters:
3060 + ts   - The `TS` context obtained from `TSCreate()`
3061 - func - The function
3062 
3063   Calling sequence of `func`:
3064 .vb
3065   PetscErrorCode func (TS ts)
3066 .ve
3067 
3068   Level: intermediate
3069 
3070 .seealso: [](ch_ts), `TS`, `TSSetPreStage()`, `TSSetPostStage()`, `TSSetPostStep()`, `TSStep()`, `TSRestartStep()`
3071 @*/
3072 PetscErrorCode TSSetPreStep(TS ts, PetscErrorCode (*func)(TS))
3073 {
3074   PetscFunctionBegin;
3075   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3076   ts->prestep = func;
3077   PetscFunctionReturn(PETSC_SUCCESS);
3078 }
3079 
3080 /*@
3081   TSPreStep - Runs the user-defined pre-step function provided with `TSSetPreStep()`
3082 
3083   Collective
3084 
3085   Input Parameter:
3086 . ts - The `TS` context obtained from `TSCreate()`
3087 
3088   Level: developer
3089 
3090   Note:
3091   `TSPreStep()` is typically used within time stepping implementations,
3092   so most users would not generally call this routine themselves.
3093 
3094 .seealso: [](ch_ts), `TS`, `TSSetPreStep()`, `TSPreStage()`, `TSPostStage()`, `TSPostStep()`
3095 @*/
3096 PetscErrorCode TSPreStep(TS ts)
3097 {
3098   PetscFunctionBegin;
3099   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3100   if (ts->prestep) {
3101     Vec              U;
3102     PetscObjectId    idprev;
3103     PetscBool        sameObject;
3104     PetscObjectState sprev, spost;
3105 
3106     PetscCall(TSGetSolution(ts, &U));
3107     PetscCall(PetscObjectGetId((PetscObject)U, &idprev));
3108     PetscCall(PetscObjectStateGet((PetscObject)U, &sprev));
3109     PetscCallBack("TS callback preset", (*ts->prestep)(ts));
3110     PetscCall(TSGetSolution(ts, &U));
3111     PetscCall(PetscObjectCompareId((PetscObject)U, idprev, &sameObject));
3112     PetscCall(PetscObjectStateGet((PetscObject)U, &spost));
3113     if (!sameObject || sprev != spost) PetscCall(TSRestartStep(ts));
3114   }
3115   PetscFunctionReturn(PETSC_SUCCESS);
3116 }
3117 
3118 /*@C
3119   TSSetPreStage - Sets the general-purpose function
3120   called once at the beginning of each stage.
3121 
3122   Logically Collective
3123 
3124   Input Parameters:
3125 + ts   - The `TS` context obtained from `TSCreate()`
3126 - func - The function
3127 
3128   Calling sequence of `func`:
3129 .vb
3130   PetscErrorCode func(TS ts, PetscReal stagetime)
3131 .ve
3132 
3133   Level: intermediate
3134 
3135   Note:
3136   There may be several stages per time step. If the solve for a given stage fails, the step may be rejected and retried.
3137   The time step number being computed can be queried using `TSGetStepNumber()` and the total size of the step being
3138   attempted can be obtained using `TSGetTimeStep()`. The time at the start of the step is available via `TSGetTime()`.
3139 
3140 .seealso: [](ch_ts), `TS`, `TSSetPostStage()`, `TSSetPreStep()`, `TSSetPostStep()`, `TSGetApplicationContext()`
3141 @*/
3142 PetscErrorCode TSSetPreStage(TS ts, PetscErrorCode (*func)(TS, PetscReal))
3143 {
3144   PetscFunctionBegin;
3145   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3146   ts->prestage = func;
3147   PetscFunctionReturn(PETSC_SUCCESS);
3148 }
3149 
3150 /*@C
3151   TSSetPostStage - Sets the general-purpose function, provided with `TSSetPostStep()`,
3152   called once at the end of each stage.
3153 
3154   Logically Collective
3155 
3156   Input Parameters:
3157 + ts   - The `TS` context obtained from `TSCreate()`
3158 - func - The function
3159 
3160   Calling sequence of `func`:
3161 .vb
3162   PetscErrorCode func(TS ts, PetscReal stagetime, PetscInt stageindex, Vec* Y)
3163 .ve
3164 
3165   Level: intermediate
3166 
3167   Note:
3168   There may be several stages per time step. If the solve for a given stage fails, the step may be rejected and retried.
3169   The time step number being computed can be queried using `TSGetStepNumber()` and the total size of the step being
3170   attempted can be obtained using `TSGetTimeStep()`. The time at the start of the step is available via `TSGetTime()`.
3171 
3172 .seealso: [](ch_ts), `TS`, `TSSetPreStage()`, `TSSetPreStep()`, `TSSetPostStep()`, `TSGetApplicationContext()`
3173 @*/
3174 PetscErrorCode TSSetPostStage(TS ts, PetscErrorCode (*func)(TS, PetscReal, PetscInt, Vec *))
3175 {
3176   PetscFunctionBegin;
3177   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3178   ts->poststage = func;
3179   PetscFunctionReturn(PETSC_SUCCESS);
3180 }
3181 
3182 /*@C
3183   TSSetPostEvaluate - Sets the general-purpose function
3184   called once at the end of each step evaluation.
3185 
3186   Logically Collective
3187 
3188   Input Parameters:
3189 + ts   - The `TS` context obtained from `TSCreate()`
3190 - func - The function
3191 
3192   Calling sequence of `func`:
3193 .vb
3194   PetscErrorCode func(TS ts)
3195 .ve
3196 
3197   Level: intermediate
3198 
3199   Note:
3200   Semantically, `TSSetPostEvaluate()` differs from `TSSetPostStep()` since the function it sets is called before event-handling
3201   thus guaranteeing the same solution (computed by the time-stepper) will be passed to it. On the other hand, `TSPostStep()`
3202   may be passed a different solution, possibly changed by the event handler. `TSPostEvaluate()` is called after the next step
3203   solution is evaluated allowing to modify it, if need be. The solution can be obtained with `TSGetSolution()`, the time step
3204   with `TSGetTimeStep()`, and the time at the start of the step is available via `TSGetTime()`
3205 
3206 .seealso: [](ch_ts), `TS`, `TSSetPreStage()`, `TSSetPreStep()`, `TSSetPostStep()`, `TSGetApplicationContext()`
3207 @*/
3208 PetscErrorCode TSSetPostEvaluate(TS ts, PetscErrorCode (*func)(TS))
3209 {
3210   PetscFunctionBegin;
3211   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3212   ts->postevaluate = func;
3213   PetscFunctionReturn(PETSC_SUCCESS);
3214 }
3215 
3216 /*@
3217   TSPreStage - Runs the user-defined pre-stage function set using `TSSetPreStage()`
3218 
3219   Collective
3220 
3221   Input Parameters:
3222 . ts - The `TS` context obtained from `TSCreate()`
3223   stagetime   - The absolute time of the current stage
3224 
3225   Level: developer
3226 
3227   Note:
3228   `TSPreStage()` is typically used within time stepping implementations,
3229   most users would not generally call this routine themselves.
3230 
3231 .seealso: [](ch_ts), `TS`, `TSPostStage()`, `TSSetPreStep()`, `TSPreStep()`, `TSPostStep()`
3232 @*/
3233 PetscErrorCode TSPreStage(TS ts, PetscReal stagetime)
3234 {
3235   PetscFunctionBegin;
3236   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3237   if (ts->prestage) PetscCallBack("TS callback prestage", (*ts->prestage)(ts, stagetime));
3238   PetscFunctionReturn(PETSC_SUCCESS);
3239 }
3240 
3241 /*@
3242   TSPostStage - Runs the user-defined post-stage function set using `TSSetPostStage()`
3243 
3244   Collective
3245 
3246   Input Parameters:
3247 . ts - The `TS` context obtained from `TSCreate()`
3248   stagetime   - The absolute time of the current stage
3249   stageindex  - Stage number
3250   Y           - Array of vectors (of size = total number
3251                 of stages) with the stage solutions
3252 
3253   Level: developer
3254 
3255   Note:
3256   `TSPostStage()` is typically used within time stepping implementations,
3257   most users would not generally call this routine themselves.
3258 
3259 .seealso: [](ch_ts), `TS`, `TSPreStage()`, `TSSetPreStep()`, `TSPreStep()`, `TSPostStep()`
3260 @*/
3261 PetscErrorCode TSPostStage(TS ts, PetscReal stagetime, PetscInt stageindex, Vec *Y)
3262 {
3263   PetscFunctionBegin;
3264   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3265   if (ts->poststage) PetscCallBack("TS callback poststage", (*ts->poststage)(ts, stagetime, stageindex, Y));
3266   PetscFunctionReturn(PETSC_SUCCESS);
3267 }
3268 
3269 /*@
3270   TSPostEvaluate - Runs the user-defined post-evaluate function set using `TSSetPostEvaluate()`
3271 
3272   Collective
3273 
3274   Input Parameter:
3275 . ts - The `TS` context obtained from `TSCreate()`
3276 
3277   Level: developer
3278 
3279   Note:
3280   `TSPostEvaluate()` is typically used within time stepping implementations,
3281   most users would not generally call this routine themselves.
3282 
3283 .seealso: [](ch_ts), `TS`, `TSSetPostEvaluate()`, `TSSetPreStep()`, `TSPreStep()`, `TSPostStep()`
3284 @*/
3285 PetscErrorCode TSPostEvaluate(TS ts)
3286 {
3287   PetscFunctionBegin;
3288   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3289   if (ts->postevaluate) {
3290     Vec              U;
3291     PetscObjectState sprev, spost;
3292 
3293     PetscCall(TSGetSolution(ts, &U));
3294     PetscCall(PetscObjectStateGet((PetscObject)U, &sprev));
3295     PetscCallBack("TS callback postevaluate", (*ts->postevaluate)(ts));
3296     PetscCall(PetscObjectStateGet((PetscObject)U, &spost));
3297     if (sprev != spost) PetscCall(TSRestartStep(ts));
3298   }
3299   PetscFunctionReturn(PETSC_SUCCESS);
3300 }
3301 
3302 /*@C
3303   TSSetPostStep - Sets the general-purpose function
3304   called once at the end of each time step.
3305 
3306   Logically Collective
3307 
3308   Input Parameters:
3309 + ts   - The `TS` context obtained from `TSCreate()`
3310 - func - The function
3311 
3312   Calling sequence of `func`:
3313 $ PetscErrorCode func(TS ts)
3314 
3315   Level: intermediate
3316 
3317   Note:
3318   The function set by `TSSetPostStep()` is called after each successful step. The solution vector
3319   obtained by `TSGetSolution()` may be different than that computed at the step end if the event handler
3320   locates an event and `TSPostEvent()` modifies it. Use `TSSetPostEvaluate()` if an unmodified solution is needed instead.
3321 
3322 .seealso: [](ch_ts), `TS`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostEvaluate()`, `TSGetTimeStep()`, `TSGetStepNumber()`, `TSGetTime()`, `TSRestartStep()`
3323 @*/
3324 PetscErrorCode TSSetPostStep(TS ts, PetscErrorCode (*func)(TS))
3325 {
3326   PetscFunctionBegin;
3327   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3328   ts->poststep = func;
3329   PetscFunctionReturn(PETSC_SUCCESS);
3330 }
3331 
3332 /*@
3333   TSPostStep - Runs the user-defined post-step function that was set with `TSSetPostStep()`
3334 
3335   Collective
3336 
3337   Input Parameter:
3338 . ts - The `TS` context obtained from `TSCreate()`
3339 
3340   Note:
3341   `TSPostStep()` is typically used within time stepping implementations,
3342   so most users would not generally call this routine themselves.
3343 
3344   Level: developer
3345 
3346 .seealso: [](ch_ts), `TS`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostEvaluate()`, `TSGetTimeStep()`, `TSGetStepNumber()`, `TSGetTime()`, `TSSetPotsStep()`
3347 @*/
3348 PetscErrorCode TSPostStep(TS ts)
3349 {
3350   PetscFunctionBegin;
3351   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3352   if (ts->poststep) {
3353     Vec              U;
3354     PetscObjectId    idprev;
3355     PetscBool        sameObject;
3356     PetscObjectState sprev, spost;
3357 
3358     PetscCall(TSGetSolution(ts, &U));
3359     PetscCall(PetscObjectGetId((PetscObject)U, &idprev));
3360     PetscCall(PetscObjectStateGet((PetscObject)U, &sprev));
3361     PetscCallBack("TS callback poststep", (*ts->poststep)(ts));
3362     PetscCall(TSGetSolution(ts, &U));
3363     PetscCall(PetscObjectCompareId((PetscObject)U, idprev, &sameObject));
3364     PetscCall(PetscObjectStateGet((PetscObject)U, &spost));
3365     if (!sameObject || sprev != spost) PetscCall(TSRestartStep(ts));
3366   }
3367   PetscFunctionReturn(PETSC_SUCCESS);
3368 }
3369 
3370 /*@
3371   TSInterpolate - Interpolate the solution computed during the previous step to an arbitrary location in the interval
3372 
3373   Collective
3374 
3375   Input Parameters:
3376 + ts - time stepping context
3377 - t  - time to interpolate to
3378 
3379   Output Parameter:
3380 . U - state at given time
3381 
3382   Level: intermediate
3383 
3384   Developer Notes:
3385   `TSInterpolate()` and the storing of previous steps/stages should be generalized to support delay differential equations and continuous adjoints.
3386 
3387 .seealso: [](ch_ts), `TS`, `TSSetExactFinalTime()`, `TSSolve()`
3388 @*/
3389 PetscErrorCode TSInterpolate(TS ts, PetscReal t, Vec U)
3390 {
3391   PetscFunctionBegin;
3392   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3393   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
3394   PetscCheck(t >= ts->ptime_prev && t <= ts->ptime, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Requested time %g not in last time steps [%g,%g]", (double)t, (double)ts->ptime_prev, (double)ts->ptime);
3395   PetscUseTypeMethod(ts, interpolate, t, U);
3396   PetscFunctionReturn(PETSC_SUCCESS);
3397 }
3398 
3399 /*@
3400   TSStep - Steps one time step
3401 
3402   Collective
3403 
3404   Input Parameter:
3405 . ts - the `TS` context obtained from `TSCreate()`
3406 
3407   Level: developer
3408 
3409   Notes:
3410   The public interface for the ODE/DAE solvers is `TSSolve()`, you should almost for sure be using that routine and not this routine.
3411 
3412   The hook set using `TSSetPreStep()` is called before each attempt to take the step. In general, the time step size may
3413   be changed due to adaptive error controller or solve failures. Note that steps may contain multiple stages.
3414 
3415   This may over-step the final time provided in `TSSetMaxTime()` depending on the time-step used. `TSSolve()` interpolates to exactly the
3416   time provided in `TSSetMaxTime()`. One can use `TSInterpolate()` to determine an interpolated solution within the final timestep.
3417 
3418 .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetUp()`, `TSDestroy()`, `TSSolve()`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostStage()`, `TSInterpolate()`
3419 @*/
3420 PetscErrorCode TSStep(TS ts)
3421 {
3422   static PetscBool cite = PETSC_FALSE;
3423   PetscReal        ptime;
3424 
3425   PetscFunctionBegin;
3426   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3427   PetscCall(PetscCitationsRegister("@article{tspaper,\n"
3428                                    "  title         = {{PETSc/TS}: A Modern Scalable {DAE/ODE} Solver Library},\n"
3429                                    "  author        = {Abhyankar, Shrirang and Brown, Jed and Constantinescu, Emil and Ghosh, Debojyoti and Smith, Barry F. and Zhang, Hong},\n"
3430                                    "  journal       = {arXiv e-preprints},\n"
3431                                    "  eprint        = {1806.01437},\n"
3432                                    "  archivePrefix = {arXiv},\n"
3433                                    "  year          = {2018}\n}\n",
3434                                    &cite));
3435   PetscCall(TSSetUp(ts));
3436   PetscCall(TSTrajectorySetUp(ts->trajectory, ts));
3437 
3438   PetscCheck(ts->max_time < PETSC_MAX_REAL || ts->max_steps != PETSC_MAX_INT, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "You must call TSSetMaxTime() or TSSetMaxSteps(), or use -ts_max_time <time> or -ts_max_steps <steps>");
3439   PetscCheck(ts->exact_final_time != TS_EXACTFINALTIME_UNSPECIFIED, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "You must call TSSetExactFinalTime() or use -ts_exact_final_time <stepover,interpolate,matchstep> before calling TSStep()");
3440   PetscCheck(ts->exact_final_time != TS_EXACTFINALTIME_MATCHSTEP || ts->adapt, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Since TS is not adaptive you cannot use TS_EXACTFINALTIME_MATCHSTEP, suggest TS_EXACTFINALTIME_INTERPOLATE");
3441 
3442   if (!ts->steps) ts->ptime_prev = ts->ptime;
3443   ptime                   = ts->ptime;
3444   ts->ptime_prev_rollback = ts->ptime_prev;
3445   ts->reason              = TS_CONVERGED_ITERATING;
3446 
3447   PetscCall(PetscLogEventBegin(TS_Step, ts, 0, 0, 0));
3448   PetscUseTypeMethod(ts, step);
3449   PetscCall(PetscLogEventEnd(TS_Step, ts, 0, 0, 0));
3450 
3451   if (ts->tspan && PetscIsCloseAtTol(ts->ptime, ts->tspan->span_times[ts->tspan->spanctr], ts->tspan->reltol * ts->time_step + ts->tspan->abstol, 0) && ts->tspan->spanctr < ts->tspan->num_span_times)
3452     PetscCall(VecCopy(ts->vec_sol, ts->tspan->vecs_sol[ts->tspan->spanctr++]));
3453   if (ts->reason >= 0) {
3454     ts->ptime_prev = ptime;
3455     ts->steps++;
3456     ts->steprollback = PETSC_FALSE;
3457     ts->steprestart  = PETSC_FALSE;
3458   }
3459   if (!ts->reason) {
3460     if (ts->steps >= ts->max_steps) ts->reason = TS_CONVERGED_ITS;
3461     else if (ts->ptime >= ts->max_time) ts->reason = TS_CONVERGED_TIME;
3462   }
3463 
3464   if (ts->reason < 0 && ts->errorifstepfailed) {
3465     PetscCall(TSMonitorCancel(ts));
3466     PetscCheck(ts->reason != TS_DIVERGED_NONLINEAR_SOLVE, PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSStep has failed due to %s, increase -ts_max_snes_failures or make negative to attempt recovery", TSConvergedReasons[ts->reason]);
3467     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSStep has failed due to %s", TSConvergedReasons[ts->reason]);
3468   }
3469   PetscFunctionReturn(PETSC_SUCCESS);
3470 }
3471 
3472 /*@
3473   TSEvaluateWLTE - Evaluate the weighted local truncation error norm
3474   at the end of a time step with a given order of accuracy.
3475 
3476   Collective
3477 
3478   Input Parameters:
3479 + ts        - time stepping context
3480 - wnormtype - norm type, either `NORM_2` or `NORM_INFINITY`
3481 
3482   Input/Output Parameter:
3483 . order - optional, desired order for the error evaluation or `PETSC_DECIDE`;
3484            on output, the actual order of the error evaluation
3485 
3486   Output Parameter:
3487 . wlte - the weighted local truncation error norm
3488 
3489   Level: advanced
3490 
3491   Note:
3492   If the timestepper cannot evaluate the error in a particular step
3493   (eg. in the first step or restart steps after event handling),
3494   this routine returns wlte=-1.0 .
3495 
3496 .seealso: [](ch_ts), `TS`, `TSStep()`, `TSAdapt`, `TSErrorWeightedNorm()`
3497 @*/
3498 PetscErrorCode TSEvaluateWLTE(TS ts, NormType wnormtype, PetscInt *order, PetscReal *wlte)
3499 {
3500   PetscFunctionBegin;
3501   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3502   PetscValidType(ts, 1);
3503   PetscValidLogicalCollectiveEnum(ts, wnormtype, 2);
3504   if (order) PetscValidIntPointer(order, 3);
3505   if (order) PetscValidLogicalCollectiveInt(ts, *order, 3);
3506   PetscValidRealPointer(wlte, 4);
3507   PetscCheck(wnormtype == NORM_2 || wnormtype == NORM_INFINITY, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "No support for norm type %s", NormTypes[wnormtype]);
3508   PetscUseTypeMethod(ts, evaluatewlte, wnormtype, order, wlte);
3509   PetscFunctionReturn(PETSC_SUCCESS);
3510 }
3511 
3512 /*@
3513   TSEvaluateStep - Evaluate the solution at the end of a time step with a given order of accuracy.
3514 
3515   Collective
3516 
3517   Input Parameters:
3518 + ts    - time stepping context
3519 . order - desired order of accuracy
3520 - done  - whether the step was evaluated at this order (pass `NULL` to generate an error if not available)
3521 
3522   Output Parameter:
3523 . U - state at the end of the current step
3524 
3525   Level: advanced
3526 
3527   Notes:
3528   This function cannot be called until all stages have been evaluated.
3529 
3530   It is normally called by adaptive controllers before a step has been accepted and may also be called by the user after `TSStep()` has returned.
3531 
3532 .seealso: [](ch_ts), `TS`, `TSStep()`, `TSAdapt`
3533 @*/
3534 PetscErrorCode TSEvaluateStep(TS ts, PetscInt order, Vec U, PetscBool *done)
3535 {
3536   PetscFunctionBegin;
3537   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3538   PetscValidType(ts, 1);
3539   PetscValidHeaderSpecific(U, VEC_CLASSID, 3);
3540   PetscUseTypeMethod(ts, evaluatestep, order, U, done);
3541   PetscFunctionReturn(PETSC_SUCCESS);
3542 }
3543 
3544 /*@C
3545   TSGetComputeInitialCondition - Get the function used to automatically compute an initial condition for the timestepping.
3546 
3547   Not collective
3548 
3549   Input Parameter:
3550 . ts - time stepping context
3551 
3552   Output Parameter:
3553 . initCondition - The function which computes an initial condition
3554 
3555   Calling sequence of `initCondition`:
3556 .vb
3557   PetscErrorCode initCondition(TS ts, Vec u)
3558 .ve
3559 + ts - The timestepping context
3560 - u  - The input vector in which the initial condition is stored
3561 
3562   Level: advanced
3563 
3564 .seealso: [](ch_ts), `TS`, `TSSetComputeInitialCondition()`, `TSComputeInitialCondition()`
3565 @*/
3566 PetscErrorCode TSGetComputeInitialCondition(TS ts, PetscErrorCode (**initCondition)(TS, Vec))
3567 {
3568   PetscFunctionBegin;
3569   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3570   PetscValidPointer(initCondition, 2);
3571   *initCondition = ts->ops->initcondition;
3572   PetscFunctionReturn(PETSC_SUCCESS);
3573 }
3574 
3575 /*@C
3576   TSSetComputeInitialCondition - Set the function used to automatically compute an initial condition for the timestepping.
3577 
3578   Logically collective
3579 
3580   Input Parameters:
3581 + ts            - time stepping context
3582 - initCondition - The function which computes an initial condition
3583 
3584   Calling sequence of `initCondition`:
3585 $ PetscErrorCode initCondition(TS ts, Vec u)
3586 + ts - The timestepping context
3587 - u  - The input vector in which the initial condition is to be stored
3588 
3589   Level: advanced
3590 
3591 .seealso: [](ch_ts), `TS`, `TSGetComputeInitialCondition()`, `TSComputeInitialCondition()`
3592 @*/
3593 PetscErrorCode TSSetComputeInitialCondition(TS ts, PetscErrorCode (*initCondition)(TS, Vec))
3594 {
3595   PetscFunctionBegin;
3596   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3597   PetscValidFunction(initCondition, 2);
3598   ts->ops->initcondition = initCondition;
3599   PetscFunctionReturn(PETSC_SUCCESS);
3600 }
3601 
3602 /*@
3603   TSComputeInitialCondition - Compute an initial condition for the timestepping using the function previously set with `TSSetComputeInitialCondition()`
3604 
3605   Collective
3606 
3607   Input Parameters:
3608 + ts - time stepping context
3609 - u  - The `Vec` to store the condition in which will be used in `TSSolve()`
3610 
3611   Level: advanced
3612 
3613 .seealso: [](ch_ts), `TS`, `TSGetComputeInitialCondition()`, `TSSetComputeInitialCondition()`, `TSSolve()`
3614 @*/
3615 PetscErrorCode TSComputeInitialCondition(TS ts, Vec u)
3616 {
3617   PetscFunctionBegin;
3618   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3619   PetscValidHeaderSpecific(u, VEC_CLASSID, 2);
3620   PetscTryTypeMethod(ts, initcondition, u);
3621   PetscFunctionReturn(PETSC_SUCCESS);
3622 }
3623 
3624 /*@C
3625   TSGetComputeExactError - Get the function used to automatically compute the exact error for the timestepping.
3626 
3627   Not collective
3628 
3629   Input Parameter:
3630 . ts - time stepping context
3631 
3632   Output Parameter:
3633 . exactError - The function which computes the solution error
3634 
3635   Calling sequence of `exactError`:
3636 $ PetscErrorCode exactError(TS ts, Vec u, Vec e)
3637 + ts - The timestepping context
3638 . u  - The approximate solution vector
3639 - e  - The vector in which the error is stored
3640 
3641   Level: advanced
3642 
3643 .seealso: [](ch_ts), `TS`, `TSGetComputeExactError()`, `TSComputeExactError()`
3644 @*/
3645 PetscErrorCode TSGetComputeExactError(TS ts, PetscErrorCode (**exactError)(TS, Vec, Vec))
3646 {
3647   PetscFunctionBegin;
3648   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3649   PetscValidPointer(exactError, 2);
3650   *exactError = ts->ops->exacterror;
3651   PetscFunctionReturn(PETSC_SUCCESS);
3652 }
3653 
3654 /*@C
3655   TSSetComputeExactError - Set the function used to automatically compute the exact error for the timestepping.
3656 
3657   Logically collective
3658 
3659   Input Parameters:
3660 + ts         - time stepping context
3661 - exactError - The function which computes the solution error
3662 
3663   Calling sequence of `exactError`:
3664 $ PetscErrorCode exactError(TS ts, Vec u)
3665 + ts - The timestepping context
3666 . u  - The approximate solution vector
3667 - e  - The  vector in which the error is stored
3668 
3669   Level: advanced
3670 
3671 .seealso: [](ch_ts), `TS`, `TSGetComputeExactError()`, `TSComputeExactError()`
3672 @*/
3673 PetscErrorCode TSSetComputeExactError(TS ts, PetscErrorCode (*exactError)(TS, Vec, Vec))
3674 {
3675   PetscFunctionBegin;
3676   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3677   PetscValidFunction(exactError, 2);
3678   ts->ops->exacterror = exactError;
3679   PetscFunctionReturn(PETSC_SUCCESS);
3680 }
3681 
3682 /*@
3683   TSComputeExactError - Compute the solution error for the timestepping using the function previously set with `TSSetComputeExactError()`
3684 
3685   Collective
3686 
3687   Input Parameters:
3688 + ts - time stepping context
3689 . u  - The approximate solution
3690 - e  - The `Vec` used to store the error
3691 
3692   Level: advanced
3693 
3694 .seealso: [](ch_ts), `TS`, `TSGetComputeInitialCondition()`, `TSSetComputeInitialCondition()`, `TSSolve()`
3695 @*/
3696 PetscErrorCode TSComputeExactError(TS ts, Vec u, Vec e)
3697 {
3698   PetscFunctionBegin;
3699   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3700   PetscValidHeaderSpecific(u, VEC_CLASSID, 2);
3701   PetscValidHeaderSpecific(e, VEC_CLASSID, 3);
3702   PetscTryTypeMethod(ts, exacterror, u, e);
3703   PetscFunctionReturn(PETSC_SUCCESS);
3704 }
3705 
3706 /*@
3707   TSSolve - Steps the requested number of timesteps.
3708 
3709   Collective
3710 
3711   Input Parameters:
3712 + ts - the `TS` context obtained from `TSCreate()`
3713 - u  - the solution vector  (can be null if `TSSetSolution()` was used and `TSSetExactFinalTime`(ts,`TS_EXACTFINALTIME_MATCHSTEP`) was not used,
3714                              otherwise must contain the initial conditions and will contain the solution at the final requested time
3715 
3716   Level: beginner
3717 
3718   Notes:
3719   The final time returned by this function may be different from the time of the internally
3720   held state accessible by `TSGetSolution()` and `TSGetTime()` because the method may have
3721   stepped over the final time.
3722 
3723 .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetSolution()`, `TSStep()`, `TSGetTime()`, `TSGetSolveTime()`
3724 @*/
3725 PetscErrorCode TSSolve(TS ts, Vec u)
3726 {
3727   Vec solution;
3728 
3729   PetscFunctionBegin;
3730   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3731   if (u) PetscValidHeaderSpecific(u, VEC_CLASSID, 2);
3732 
3733   PetscCall(TSSetExactFinalTimeDefault(ts));
3734   if (ts->exact_final_time == TS_EXACTFINALTIME_INTERPOLATE && u) { /* Need ts->vec_sol to be distinct so it is not overwritten when we interpolate at the end */
3735     if (!ts->vec_sol || u == ts->vec_sol) {
3736       PetscCall(VecDuplicate(u, &solution));
3737       PetscCall(TSSetSolution(ts, solution));
3738       PetscCall(VecDestroy(&solution)); /* grant ownership */
3739     }
3740     PetscCall(VecCopy(u, ts->vec_sol));
3741     PetscCheck(!ts->forward_solve, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Sensitivity analysis does not support the mode TS_EXACTFINALTIME_INTERPOLATE");
3742   } else if (u) PetscCall(TSSetSolution(ts, u));
3743   PetscCall(TSSetUp(ts));
3744   PetscCall(TSTrajectorySetUp(ts->trajectory, ts));
3745 
3746   PetscCheck(ts->max_time < PETSC_MAX_REAL || ts->max_steps != PETSC_MAX_INT, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "You must call TSSetMaxTime() or TSSetMaxSteps(), or use -ts_max_time <time> or -ts_max_steps <steps>");
3747   PetscCheck(ts->exact_final_time != TS_EXACTFINALTIME_UNSPECIFIED, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "You must call TSSetExactFinalTime() or use -ts_exact_final_time <stepover,interpolate,matchstep> before calling TSSolve()");
3748   PetscCheck(ts->exact_final_time != TS_EXACTFINALTIME_MATCHSTEP || ts->adapt, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Since TS is not adaptive you cannot use TS_EXACTFINALTIME_MATCHSTEP, suggest TS_EXACTFINALTIME_INTERPOLATE");
3749   PetscCheck(!(ts->tspan && ts->exact_final_time != TS_EXACTFINALTIME_MATCHSTEP), PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "You must use TS_EXACTFINALTIME_MATCHSTEP when using time span");
3750 
3751   if (ts->tspan && PetscIsCloseAtTol(ts->ptime, ts->tspan->span_times[0], ts->tspan->reltol * ts->time_step + ts->tspan->abstol, 0)) { /* starting point in time span */
3752     PetscCall(VecCopy(ts->vec_sol, ts->tspan->vecs_sol[0]));
3753     ts->tspan->spanctr = 1;
3754   }
3755 
3756   if (ts->forward_solve) PetscCall(TSForwardSetUp(ts));
3757 
3758   /* reset number of steps only when the step is not restarted. ARKIMEX
3759      restarts the step after an event. Resetting these counters in such case causes
3760      TSTrajectory to incorrectly save the output files
3761   */
3762   /* reset time step and iteration counters */
3763   if (!ts->steps) {
3764     ts->ksp_its           = 0;
3765     ts->snes_its          = 0;
3766     ts->num_snes_failures = 0;
3767     ts->reject            = 0;
3768     ts->steprestart       = PETSC_TRUE;
3769     ts->steprollback      = PETSC_FALSE;
3770     ts->rhsjacobian.time  = PETSC_MIN_REAL;
3771   }
3772 
3773   /* make sure initial time step does not overshoot final time or the next point in tspan */
3774   if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
3775     PetscReal maxdt;
3776     PetscReal dt = ts->time_step;
3777 
3778     if (ts->tspan) maxdt = ts->tspan->span_times[ts->tspan->spanctr] - ts->ptime;
3779     else maxdt = ts->max_time - ts->ptime;
3780     ts->time_step = dt >= maxdt ? maxdt : (PetscIsCloseAtTol(dt, maxdt, 10 * PETSC_MACHINE_EPSILON, 0) ? maxdt : dt);
3781   }
3782   ts->reason = TS_CONVERGED_ITERATING;
3783 
3784   {
3785     PetscViewer       viewer;
3786     PetscViewerFormat format;
3787     PetscBool         flg;
3788     static PetscBool  incall = PETSC_FALSE;
3789 
3790     if (!incall) {
3791       /* Estimate the convergence rate of the time discretization */
3792       PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts), ((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_convergence_estimate", &viewer, &format, &flg));
3793       if (flg) {
3794         PetscConvEst conv;
3795         DM           dm;
3796         PetscReal   *alpha; /* Convergence rate of the solution error for each field in the L_2 norm */
3797         PetscInt     Nf;
3798         PetscBool    checkTemporal = PETSC_TRUE;
3799 
3800         incall = PETSC_TRUE;
3801         PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_convergence_temporal", &checkTemporal, &flg));
3802         PetscCall(TSGetDM(ts, &dm));
3803         PetscCall(DMGetNumFields(dm, &Nf));
3804         PetscCall(PetscCalloc1(PetscMax(Nf, 1), &alpha));
3805         PetscCall(PetscConvEstCreate(PetscObjectComm((PetscObject)ts), &conv));
3806         PetscCall(PetscConvEstUseTS(conv, checkTemporal));
3807         PetscCall(PetscConvEstSetSolver(conv, (PetscObject)ts));
3808         PetscCall(PetscConvEstSetFromOptions(conv));
3809         PetscCall(PetscConvEstSetUp(conv));
3810         PetscCall(PetscConvEstGetConvRate(conv, alpha));
3811         PetscCall(PetscViewerPushFormat(viewer, format));
3812         PetscCall(PetscConvEstRateView(conv, alpha, viewer));
3813         PetscCall(PetscViewerPopFormat(viewer));
3814         PetscCall(PetscViewerDestroy(&viewer));
3815         PetscCall(PetscConvEstDestroy(&conv));
3816         PetscCall(PetscFree(alpha));
3817         incall = PETSC_FALSE;
3818       }
3819     }
3820   }
3821 
3822   PetscCall(TSViewFromOptions(ts, NULL, "-ts_view_pre"));
3823 
3824   if (ts->ops->solve) { /* This private interface is transitional and should be removed when all implementations are updated. */
3825     PetscUseTypeMethod(ts, solve);
3826     if (u) PetscCall(VecCopy(ts->vec_sol, u));
3827     ts->solvetime = ts->ptime;
3828     solution      = ts->vec_sol;
3829   } else { /* Step the requested number of timesteps. */
3830     if (ts->steps >= ts->max_steps) ts->reason = TS_CONVERGED_ITS;
3831     else if (ts->ptime >= ts->max_time) ts->reason = TS_CONVERGED_TIME;
3832 
3833     if (!ts->steps) {
3834       PetscCall(TSTrajectorySet(ts->trajectory, ts, ts->steps, ts->ptime, ts->vec_sol));
3835       PetscCall(TSEventInitialize(ts->event, ts, ts->ptime, ts->vec_sol));
3836     }
3837 
3838     while (!ts->reason) {
3839       PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
3840       if (!ts->steprollback) PetscCall(TSPreStep(ts));
3841       PetscCall(TSStep(ts));
3842       if (ts->testjacobian) PetscCall(TSRHSJacobianTest(ts, NULL));
3843       if (ts->testjacobiantranspose) PetscCall(TSRHSJacobianTestTranspose(ts, NULL));
3844       if (ts->quadraturets && ts->costintegralfwd) { /* Must evaluate the cost integral before event is handled. The cost integral value can also be rolled back. */
3845         if (ts->reason >= 0) ts->steps--;            /* Revert the step number changed by TSStep() */
3846         PetscCall(TSForwardCostIntegral(ts));
3847         if (ts->reason >= 0) ts->steps++;
3848       }
3849       if (ts->forward_solve) {            /* compute forward sensitivities before event handling because postevent() may change RHS and jump conditions may have to be applied */
3850         if (ts->reason >= 0) ts->steps--; /* Revert the step number changed by TSStep() */
3851         PetscCall(TSForwardStep(ts));
3852         if (ts->reason >= 0) ts->steps++;
3853       }
3854       PetscCall(TSPostEvaluate(ts));
3855       PetscCall(TSEventHandler(ts)); /* The right-hand side may be changed due to event. Be careful with Any computation using the RHS information after this point. */
3856       if (ts->steprollback) PetscCall(TSPostEvaluate(ts));
3857       if (!ts->steprollback) {
3858         PetscCall(TSTrajectorySet(ts->trajectory, ts, ts->steps, ts->ptime, ts->vec_sol));
3859         PetscCall(TSPostStep(ts));
3860       }
3861     }
3862     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
3863 
3864     if (ts->exact_final_time == TS_EXACTFINALTIME_INTERPOLATE && ts->ptime > ts->max_time) {
3865       PetscCall(TSInterpolate(ts, ts->max_time, u));
3866       ts->solvetime = ts->max_time;
3867       solution      = u;
3868       PetscCall(TSMonitor(ts, -1, ts->solvetime, solution));
3869     } else {
3870       if (u) PetscCall(VecCopy(ts->vec_sol, u));
3871       ts->solvetime = ts->ptime;
3872       solution      = ts->vec_sol;
3873     }
3874   }
3875 
3876   PetscCall(TSViewFromOptions(ts, NULL, "-ts_view"));
3877   PetscCall(VecViewFromOptions(solution, (PetscObject)ts, "-ts_view_solution"));
3878   PetscCall(PetscObjectSAWsBlock((PetscObject)ts));
3879   if (ts->adjoint_solve) PetscCall(TSAdjointSolve(ts));
3880   PetscFunctionReturn(PETSC_SUCCESS);
3881 }
3882 
3883 /*@
3884   TSGetTime - Gets the time of the most recently completed step.
3885 
3886   Not Collective
3887 
3888   Input Parameter:
3889 . ts - the `TS` context obtained from `TSCreate()`
3890 
3891   Output Parameter:
3892 . t - the current time. This time may not corresponds to the final time set with `TSSetMaxTime()`, use `TSGetSolveTime()`.
3893 
3894   Level: beginner
3895 
3896   Note:
3897   When called during time step evaluation (e.g. during residual evaluation or via hooks set using `TSSetPreStep()`,
3898   `TSSetPreStage()`, `TSSetPostStage()`, or `TSSetPostStep()`), the time is the time at the start of the step being evaluated.
3899 
3900 .seealso: [](ch_ts), `TS`, ``TSGetSolveTime()`, `TSSetTime()`, `TSGetTimeStep()`, `TSGetStepNumber()`
3901 @*/
3902 PetscErrorCode TSGetTime(TS ts, PetscReal *t)
3903 {
3904   PetscFunctionBegin;
3905   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3906   PetscValidRealPointer(t, 2);
3907   *t = ts->ptime;
3908   PetscFunctionReturn(PETSC_SUCCESS);
3909 }
3910 
3911 /*@
3912   TSGetPrevTime - Gets the starting time of the previously completed step.
3913 
3914   Not Collective
3915 
3916   Input Parameter:
3917 . ts - the `TS` context obtained from `TSCreate()`
3918 
3919   Output Parameter:
3920 . t - the previous time
3921 
3922   Level: beginner
3923 
3924 .seealso: [](ch_ts), `TS`, ``TSGetTime()`, `TSGetSolveTime()`, `TSGetTimeStep()`
3925 @*/
3926 PetscErrorCode TSGetPrevTime(TS ts, PetscReal *t)
3927 {
3928   PetscFunctionBegin;
3929   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3930   PetscValidRealPointer(t, 2);
3931   *t = ts->ptime_prev;
3932   PetscFunctionReturn(PETSC_SUCCESS);
3933 }
3934 
3935 /*@
3936   TSSetTime - Allows one to reset the time.
3937 
3938   Logically Collective
3939 
3940   Input Parameters:
3941 + ts - the `TS` context obtained from `TSCreate()`
3942 - t  - the time
3943 
3944   Level: intermediate
3945 
3946 .seealso: [](ch_ts), `TS`, `TSGetTime()`, `TSSetMaxSteps()`
3947 @*/
3948 PetscErrorCode TSSetTime(TS ts, PetscReal t)
3949 {
3950   PetscFunctionBegin;
3951   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3952   PetscValidLogicalCollectiveReal(ts, t, 2);
3953   ts->ptime = t;
3954   PetscFunctionReturn(PETSC_SUCCESS);
3955 }
3956 
3957 /*@C
3958   TSSetOptionsPrefix - Sets the prefix used for searching for all
3959   TS options in the database.
3960 
3961   Logically Collective
3962 
3963   Input Parameters:
3964 + ts     - The `TS` context
3965 - prefix - The prefix to prepend to all option names
3966 
3967   Level: advanced
3968 
3969   Note:
3970   A hyphen (-) must NOT be given at the beginning of the prefix name.
3971   The first character of all runtime options is AUTOMATICALLY the
3972   hyphen.
3973 
3974 .seealso: [](ch_ts), `TS`, `TSSetFromOptions()`, `TSAppendOptionsPrefix()`
3975 @*/
3976 PetscErrorCode TSSetOptionsPrefix(TS ts, const char prefix[])
3977 {
3978   SNES snes;
3979 
3980   PetscFunctionBegin;
3981   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
3982   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ts, prefix));
3983   PetscCall(TSGetSNES(ts, &snes));
3984   PetscCall(SNESSetOptionsPrefix(snes, prefix));
3985   PetscFunctionReturn(PETSC_SUCCESS);
3986 }
3987 
3988 /*@C
3989   TSAppendOptionsPrefix - Appends to the prefix used for searching for all
3990   TS options in the database.
3991 
3992   Logically Collective
3993 
3994   Input Parameters:
3995 + ts     - The `TS` context
3996 - prefix - The prefix to prepend to all option names
3997 
3998   Level: advanced
3999 
4000   Note:
4001   A hyphen (-) must NOT be given at the beginning of the prefix name.
4002   The first character of all runtime options is AUTOMATICALLY the
4003   hyphen.
4004 
4005 .seealso: [](ch_ts), `TS`, `TSGetOptionsPrefix()`, `TSSetOptionsPrefix()`, `TSSetFromOptions()`
4006 @*/
4007 PetscErrorCode TSAppendOptionsPrefix(TS ts, const char prefix[])
4008 {
4009   SNES snes;
4010 
4011   PetscFunctionBegin;
4012   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4013   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)ts, prefix));
4014   PetscCall(TSGetSNES(ts, &snes));
4015   PetscCall(SNESAppendOptionsPrefix(snes, prefix));
4016   PetscFunctionReturn(PETSC_SUCCESS);
4017 }
4018 
4019 /*@C
4020   TSGetOptionsPrefix - Sets the prefix used for searching for all
4021   `TS` options in the database.
4022 
4023   Not Collective
4024 
4025   Input Parameter:
4026 . ts - The `TS` context
4027 
4028   Output Parameter:
4029 . prefix - A pointer to the prefix string used
4030 
4031   Level: intermediate
4032 
4033   Fortran Notes:
4034   The user should pass in a string 'prefix' of
4035   sufficient length to hold the prefix.
4036 
4037 .seealso: [](ch_ts), `TS`, `TSAppendOptionsPrefix()`, `TSSetFromOptions()`
4038 @*/
4039 PetscErrorCode TSGetOptionsPrefix(TS ts, const char *prefix[])
4040 {
4041   PetscFunctionBegin;
4042   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4043   PetscValidPointer(prefix, 2);
4044   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)ts, prefix));
4045   PetscFunctionReturn(PETSC_SUCCESS);
4046 }
4047 
4048 /*@C
4049   TSGetRHSJacobian - Returns the Jacobian J at the present timestep.
4050 
4051   Not Collective, but parallel objects are returned if ts is parallel
4052 
4053   Input Parameter:
4054 . ts - The `TS` context obtained from `TSCreate()`
4055 
4056   Output Parameters:
4057 + Amat - The (approximate) Jacobian J of G, where U_t = G(U,t)  (or `NULL`)
4058 . Pmat - The matrix from which the preconditioner is constructed, usually the same as `Amat`  (or `NULL`)
4059 . func - Function to compute the Jacobian of the RHS  (or `NULL`)
4060 - ctx  - User-defined context for Jacobian evaluation routine  (or `NULL`)
4061 
4062   Level: intermediate
4063 
4064   Note:
4065   You can pass in `NULL` for any return argument you do not need.
4066 
4067 .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetMatrices()`, `TSGetTime()`, `TSGetStepNumber()`
4068 
4069 @*/
4070 PetscErrorCode TSGetRHSJacobian(TS ts, Mat *Amat, Mat *Pmat, TSRHSJacobian *func, void **ctx)
4071 {
4072   DM dm;
4073 
4074   PetscFunctionBegin;
4075   if (Amat || Pmat) {
4076     SNES snes;
4077     PetscCall(TSGetSNES(ts, &snes));
4078     PetscCall(SNESSetUpMatrices(snes));
4079     PetscCall(SNESGetJacobian(snes, Amat, Pmat, NULL, NULL));
4080   }
4081   PetscCall(TSGetDM(ts, &dm));
4082   PetscCall(DMTSGetRHSJacobian(dm, func, ctx));
4083   PetscFunctionReturn(PETSC_SUCCESS);
4084 }
4085 
4086 /*@C
4087   TSGetIJacobian - Returns the implicit Jacobian at the present timestep.
4088 
4089   Not Collective, but parallel objects are returned if ts is parallel
4090 
4091   Input Parameter:
4092 . ts - The `TS` context obtained from `TSCreate()`
4093 
4094   Output Parameters:
4095 + Amat - The (approximate) Jacobian of F(t,U,U_t)
4096 . Pmat - The matrix from which the preconditioner is constructed, often the same as `Amat`
4097 . f    - The function to compute the matrices
4098 - ctx  - User-defined context for Jacobian evaluation routine
4099 
4100   Level: advanced
4101 
4102   Note:
4103   You can pass in `NULL` for any return argument you do not need.
4104 
4105 .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetRHSJacobian()`, `TSGetMatrices()`, `TSGetTime()`, `TSGetStepNumber()`
4106 @*/
4107 PetscErrorCode TSGetIJacobian(TS ts, Mat *Amat, Mat *Pmat, TSIJacobian *f, void **ctx)
4108 {
4109   DM dm;
4110 
4111   PetscFunctionBegin;
4112   if (Amat || Pmat) {
4113     SNES snes;
4114     PetscCall(TSGetSNES(ts, &snes));
4115     PetscCall(SNESSetUpMatrices(snes));
4116     PetscCall(SNESGetJacobian(snes, Amat, Pmat, NULL, NULL));
4117   }
4118   PetscCall(TSGetDM(ts, &dm));
4119   PetscCall(DMTSGetIJacobian(dm, f, ctx));
4120   PetscFunctionReturn(PETSC_SUCCESS);
4121 }
4122 
4123 #include <petsc/private/dmimpl.h>
4124 /*@
4125   TSSetDM - Sets the `DM` that may be used by some nonlinear solvers or preconditioners under the `TS`
4126 
4127   Logically Collective
4128 
4129   Input Parameters:
4130 + ts - the `TS` integrator object
4131 - dm - the dm, cannot be `NULL`
4132 
4133   Level: intermediate
4134 
4135   Notes:
4136   A `DM` can only be used for solving one problem at a time because information about the problem is stored on the `DM`,
4137   even when not using interfaces like `DMTSSetIFunction()`.  Use `DMClone()` to get a distinct `DM` when solving
4138   different problems using the same function space.
4139 
4140 .seealso: [](ch_ts), `TS`, `DM`, `TSGetDM()`, `SNESSetDM()`, `SNESGetDM()`
4141 @*/
4142 PetscErrorCode TSSetDM(TS ts, DM dm)
4143 {
4144   SNES snes;
4145   DMTS tsdm;
4146 
4147   PetscFunctionBegin;
4148   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4149   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
4150   PetscCall(PetscObjectReference((PetscObject)dm));
4151   if (ts->dm) { /* Move the DMTS context over to the new DM unless the new DM already has one */
4152     if (ts->dm->dmts && !dm->dmts) {
4153       PetscCall(DMCopyDMTS(ts->dm, dm));
4154       PetscCall(DMGetDMTS(ts->dm, &tsdm));
4155       /* Grant write privileges to the replacement DM */
4156       if (tsdm->originaldm == ts->dm) tsdm->originaldm = dm;
4157     }
4158     PetscCall(DMDestroy(&ts->dm));
4159   }
4160   ts->dm = dm;
4161 
4162   PetscCall(TSGetSNES(ts, &snes));
4163   PetscCall(SNESSetDM(snes, dm));
4164   PetscFunctionReturn(PETSC_SUCCESS);
4165 }
4166 
4167 /*@
4168   TSGetDM - Gets the `DM` that may be used by some preconditioners
4169 
4170   Not Collective
4171 
4172   Input Parameter:
4173 . ts - the `TS`
4174 
4175   Output Parameter:
4176 . dm - the `DM`
4177 
4178   Level: intermediate
4179 
4180 .seealso: [](ch_ts), `TS`, `DM`, `TSSetDM()`, `SNESSetDM()`, `SNESGetDM()`
4181 @*/
4182 PetscErrorCode TSGetDM(TS ts, DM *dm)
4183 {
4184   PetscFunctionBegin;
4185   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4186   if (!ts->dm) {
4187     PetscCall(DMShellCreate(PetscObjectComm((PetscObject)ts), &ts->dm));
4188     if (ts->snes) PetscCall(SNESSetDM(ts->snes, ts->dm));
4189   }
4190   *dm = ts->dm;
4191   PetscFunctionReturn(PETSC_SUCCESS);
4192 }
4193 
4194 /*@
4195   SNESTSFormFunction - Function to evaluate nonlinear residual
4196 
4197   Logically Collective
4198 
4199   Input Parameters:
4200 + snes - nonlinear solver
4201 . U    - the current state at which to evaluate the residual
4202 - ctx  - user context, must be a TS
4203 
4204   Output Parameter:
4205 . F - the nonlinear residual
4206 
4207   Level: advanced
4208 
4209   Note:
4210   This function is not normally called by users and is automatically registered with the `SNES` used by `TS`.
4211   It is most frequently passed to `MatFDColoringSetFunction()`.
4212 
4213 .seealso: [](ch_ts), `SNESSetFunction()`, `MatFDColoringSetFunction()`
4214 @*/
4215 PetscErrorCode SNESTSFormFunction(SNES snes, Vec U, Vec F, void *ctx)
4216 {
4217   TS ts = (TS)ctx;
4218 
4219   PetscFunctionBegin;
4220   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4221   PetscValidHeaderSpecific(U, VEC_CLASSID, 2);
4222   PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
4223   PetscValidHeaderSpecific(ts, TS_CLASSID, 4);
4224   PetscCall((ts->ops->snesfunction)(snes, U, F, ts));
4225   PetscFunctionReturn(PETSC_SUCCESS);
4226 }
4227 
4228 /*@
4229   SNESTSFormJacobian - Function to evaluate the Jacobian
4230 
4231   Collective
4232 
4233   Input Parameters:
4234 + snes - nonlinear solver
4235 . U    - the current state at which to evaluate the residual
4236 - ctx  - user context, must be a `TS`
4237 
4238   Output Parameters:
4239 + A - the Jacobian
4240 - B - the preconditioning matrix (may be the same as A)
4241 
4242   Level: developer
4243 
4244   Note:
4245   This function is not normally called by users and is automatically registered with the `SNES` used by `TS`.
4246 
4247 .seealso: [](ch_ts), `SNESSetJacobian()`
4248 @*/
4249 PetscErrorCode SNESTSFormJacobian(SNES snes, Vec U, Mat A, Mat B, void *ctx)
4250 {
4251   TS ts = (TS)ctx;
4252 
4253   PetscFunctionBegin;
4254   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4255   PetscValidHeaderSpecific(U, VEC_CLASSID, 2);
4256   PetscValidPointer(A, 3);
4257   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
4258   PetscValidPointer(B, 4);
4259   PetscValidHeaderSpecific(B, MAT_CLASSID, 4);
4260   PetscValidHeaderSpecific(ts, TS_CLASSID, 5);
4261   PetscCall((ts->ops->snesjacobian)(snes, U, A, B, ts));
4262   PetscFunctionReturn(PETSC_SUCCESS);
4263 }
4264 
4265 /*@C
4266   TSComputeRHSFunctionLinear - Evaluate the right hand side via the user-provided Jacobian, for linear problems Udot = A U only
4267 
4268   Collective
4269 
4270   Input Parameters:
4271 + ts  - time stepping context
4272 . t   - time at which to evaluate
4273 . U   - state at which to evaluate
4274 - ctx - context
4275 
4276   Output Parameter:
4277 . F - right hand side
4278 
4279   Level: intermediate
4280 
4281   Note:
4282   This function is intended to be passed to `TSSetRHSFunction()` to evaluate the right hand side for linear problems.
4283   The matrix (and optionally the evaluation context) should be passed to `TSSetRHSJacobian()`.
4284 
4285 .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSSetRHSJacobian()`, `TSComputeRHSJacobianConstant()`
4286 @*/
4287 PetscErrorCode TSComputeRHSFunctionLinear(TS ts, PetscReal t, Vec U, Vec F, void *ctx)
4288 {
4289   Mat Arhs, Brhs;
4290 
4291   PetscFunctionBegin;
4292   PetscCall(TSGetRHSMats_Private(ts, &Arhs, &Brhs));
4293   /* undo the damage caused by shifting */
4294   PetscCall(TSRecoverRHSJacobian(ts, Arhs, Brhs));
4295   PetscCall(TSComputeRHSJacobian(ts, t, U, Arhs, Brhs));
4296   PetscCall(MatMult(Arhs, U, F));
4297   PetscFunctionReturn(PETSC_SUCCESS);
4298 }
4299 
4300 /*@C
4301   TSComputeRHSJacobianConstant - Reuses a Jacobian that is time-independent.
4302 
4303   Collective
4304 
4305   Input Parameters:
4306 + ts  - time stepping context
4307 . t   - time at which to evaluate
4308 . U   - state at which to evaluate
4309 - ctx - context
4310 
4311   Output Parameters:
4312 + A - pointer to operator
4313 - B - pointer to preconditioning matrix
4314 
4315   Level: intermediate
4316 
4317   Note:
4318   This function is intended to be passed to `TSSetRHSJacobian()` to evaluate the Jacobian for linear time-independent problems.
4319 
4320 .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSSetRHSJacobian()`, `TSComputeRHSFunctionLinear()`
4321 @*/
4322 PetscErrorCode TSComputeRHSJacobianConstant(TS ts, PetscReal t, Vec U, Mat A, Mat B, void *ctx)
4323 {
4324   PetscFunctionBegin;
4325   PetscFunctionReturn(PETSC_SUCCESS);
4326 }
4327 
4328 /*@C
4329   TSComputeIFunctionLinear - Evaluate the left hand side via the user-provided Jacobian, for linear problems only
4330 
4331   Collective
4332 
4333   Input Parameters:
4334 + ts   - time stepping context
4335 . t    - time at which to evaluate
4336 . U    - state at which to evaluate
4337 . Udot - time derivative of state vector
4338 - ctx  - context
4339 
4340   Output Parameter:
4341 . F - left hand side
4342 
4343   Level: intermediate
4344 
4345   Notes:
4346   The assumption here is that the left hand side is of the form A*Udot (and not A*Udot + B*U). For other cases, the
4347   user is required to write their own `TSComputeIFunction()`.
4348   This function is intended to be passed to `TSSetIFunction()` to evaluate the left hand side for linear problems.
4349   The matrix (and optionally the evaluation context) should be passed to `TSSetIJacobian()`.
4350 
4351   Note that using this function is NOT equivalent to using `TSComputeRHSFunctionLinear()` since that solves Udot = A U
4352 
4353 .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `TSSetIJacobian()`, `TSComputeIJacobianConstant()`, `TSComputeRHSFunctionLinear()`
4354 @*/
4355 PetscErrorCode TSComputeIFunctionLinear(TS ts, PetscReal t, Vec U, Vec Udot, Vec F, void *ctx)
4356 {
4357   Mat A, B;
4358 
4359   PetscFunctionBegin;
4360   PetscCall(TSGetIJacobian(ts, &A, &B, NULL, NULL));
4361   PetscCall(TSComputeIJacobian(ts, t, U, Udot, 1.0, A, B, PETSC_TRUE));
4362   PetscCall(MatMult(A, Udot, F));
4363   PetscFunctionReturn(PETSC_SUCCESS);
4364 }
4365 
4366 /*@C
4367   TSComputeIJacobianConstant - Reuses a time-independent for a semi-implicit DAE or ODE
4368 
4369   Collective
4370 
4371   Input Parameters:
4372 + ts    - time stepping context
4373 . t     - time at which to evaluate
4374 . U     - state at which to evaluate
4375 . Udot  - time derivative of state vector
4376 . shift - shift to apply
4377 - ctx   - context
4378 
4379   Output Parameters:
4380 + A - pointer to operator
4381 - B - pointer to preconditioning matrix
4382 
4383   Level: advanced
4384 
4385   Notes:
4386   This function is intended to be passed to `TSSetIJacobian()` to evaluate the Jacobian for linear time-independent problems.
4387 
4388   It is only appropriate for problems of the form
4389 
4390 $     M Udot = F(U,t)
4391 
4392   where M is constant and F is non-stiff.  The user must pass M to `TSSetIJacobian()`.  The current implementation only
4393   works with IMEX time integration methods such as `TSROSW` and `TSARKIMEX`, since there is no support for de-constructing
4394   an implicit operator of the form
4395 
4396 $    shift*M + J
4397 
4398   where J is the Jacobian of -F(U).  Support may be added in a future version of PETSc, but for now, the user must store
4399   a copy of M or reassemble it when requested.
4400 
4401 .seealso: [](ch_ts), `TS`, `TSROSW`, `TSARKIMEX`, `TSSetIFunction()`, `TSSetIJacobian()`, `TSComputeIFunctionLinear()`
4402 @*/
4403 PetscErrorCode TSComputeIJacobianConstant(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat A, Mat B, void *ctx)
4404 {
4405   PetscFunctionBegin;
4406   PetscCall(MatScale(A, shift / ts->ijacobian.shift));
4407   ts->ijacobian.shift = shift;
4408   PetscFunctionReturn(PETSC_SUCCESS);
4409 }
4410 
4411 /*@
4412   TSGetEquationType - Gets the type of the equation that `TS` is solving.
4413 
4414   Not Collective
4415 
4416   Input Parameter:
4417 . ts - the `TS` context
4418 
4419   Output Parameter:
4420 . equation_type - see `TSEquationType`
4421 
4422   Level: beginner
4423 
4424 .seealso: [](ch_ts), `TS`, `TSSetEquationType()`, `TSEquationType`
4425 @*/
4426 PetscErrorCode TSGetEquationType(TS ts, TSEquationType *equation_type)
4427 {
4428   PetscFunctionBegin;
4429   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4430   PetscValidPointer(equation_type, 2);
4431   *equation_type = ts->equation_type;
4432   PetscFunctionReturn(PETSC_SUCCESS);
4433 }
4434 
4435 /*@
4436   TSSetEquationType - Sets the type of the equation that `TS` is solving.
4437 
4438   Not Collective
4439 
4440   Input Parameters:
4441 + ts            - the `TS` context
4442 - equation_type - see `TSEquationType`
4443 
4444   Level: advanced
4445 
4446 .seealso: [](ch_ts), `TS`, `TSGetEquationType()`, `TSEquationType`
4447 @*/
4448 PetscErrorCode TSSetEquationType(TS ts, TSEquationType equation_type)
4449 {
4450   PetscFunctionBegin;
4451   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4452   ts->equation_type = equation_type;
4453   PetscFunctionReturn(PETSC_SUCCESS);
4454 }
4455 
4456 /*@
4457   TSGetConvergedReason - Gets the reason the `TS` iteration was stopped.
4458 
4459   Not Collective
4460 
4461   Input Parameter:
4462 . ts - the `TS` context
4463 
4464   Output Parameter:
4465 . reason - negative value indicates diverged, positive value converged, see `TSConvergedReason` or the
4466             manual pages for the individual convergence tests for complete lists
4467 
4468   Level: beginner
4469 
4470   Note:
4471   Can only be called after the call to `TSSolve()` is complete.
4472 
4473 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSSetConvergenceTest()`, `TSConvergedReason`
4474 @*/
4475 PetscErrorCode TSGetConvergedReason(TS ts, TSConvergedReason *reason)
4476 {
4477   PetscFunctionBegin;
4478   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4479   PetscValidPointer(reason, 2);
4480   *reason = ts->reason;
4481   PetscFunctionReturn(PETSC_SUCCESS);
4482 }
4483 
4484 /*@
4485   TSSetConvergedReason - Sets the reason for handling the convergence of `TSSolve()`.
4486 
4487   Logically Collective; reason must contain common value
4488 
4489   Input Parameters:
4490 + ts     - the `TS` context
4491 - reason - negative value indicates diverged, positive value converged, see `TSConvergedReason` or the
4492             manual pages for the individual convergence tests for complete lists
4493 
4494   Level: advanced
4495 
4496   Note:
4497   Can only be called while `TSSolve()` is active.
4498 
4499 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSConvergedReason`
4500 @*/
4501 PetscErrorCode TSSetConvergedReason(TS ts, TSConvergedReason reason)
4502 {
4503   PetscFunctionBegin;
4504   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4505   ts->reason = reason;
4506   PetscFunctionReturn(PETSC_SUCCESS);
4507 }
4508 
4509 /*@
4510   TSGetSolveTime - Gets the time after a call to `TSSolve()`
4511 
4512   Not Collective
4513 
4514   Input Parameter:
4515 . ts - the `TS` context
4516 
4517   Output Parameter:
4518 . ftime - the final time. This time corresponds to the final time set with `TSSetMaxTime()`
4519 
4520   Level: beginner
4521 
4522   Note:
4523   Can only be called after the call to `TSSolve()` is complete.
4524 
4525 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSSetConvergenceTest()`, `TSConvergedReason`
4526 @*/
4527 PetscErrorCode TSGetSolveTime(TS ts, PetscReal *ftime)
4528 {
4529   PetscFunctionBegin;
4530   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4531   PetscValidRealPointer(ftime, 2);
4532   *ftime = ts->solvetime;
4533   PetscFunctionReturn(PETSC_SUCCESS);
4534 }
4535 
4536 /*@
4537   TSGetSNESIterations - Gets the total number of nonlinear iterations
4538   used by the time integrator.
4539 
4540   Not Collective
4541 
4542   Input Parameter:
4543 . ts - `TS` context
4544 
4545   Output Parameter:
4546 . nits - number of nonlinear iterations
4547 
4548   Level: intermediate
4549 
4550   Note:
4551   This counter is reset to zero for each successive call to `TSSolve()`.
4552 
4553 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetKSPIterations()`
4554 @*/
4555 PetscErrorCode TSGetSNESIterations(TS ts, PetscInt *nits)
4556 {
4557   PetscFunctionBegin;
4558   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4559   PetscValidIntPointer(nits, 2);
4560   *nits = ts->snes_its;
4561   PetscFunctionReturn(PETSC_SUCCESS);
4562 }
4563 
4564 /*@
4565   TSGetKSPIterations - Gets the total number of linear iterations
4566   used by the time integrator.
4567 
4568   Not Collective
4569 
4570   Input Parameter:
4571 . ts - `TS` context
4572 
4573   Output Parameter:
4574 . lits - number of linear iterations
4575 
4576   Level: intermediate
4577 
4578   Note:
4579   This counter is reset to zero for each successive call to `TSSolve()`.
4580 
4581 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetSNESIterations()`, `SNESGetKSPIterations()`
4582 @*/
4583 PetscErrorCode TSGetKSPIterations(TS ts, PetscInt *lits)
4584 {
4585   PetscFunctionBegin;
4586   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4587   PetscValidIntPointer(lits, 2);
4588   *lits = ts->ksp_its;
4589   PetscFunctionReturn(PETSC_SUCCESS);
4590 }
4591 
4592 /*@
4593   TSGetStepRejections - Gets the total number of rejected steps.
4594 
4595   Not Collective
4596 
4597   Input Parameter:
4598 . ts - `TS` context
4599 
4600   Output Parameter:
4601 . rejects - number of steps rejected
4602 
4603   Level: intermediate
4604 
4605   Note:
4606   This counter is reset to zero for each successive call to `TSSolve()`.
4607 
4608 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetSNESFailures()`, `TSSetMaxSNESFailures()`, `TSSetErrorIfStepFails()`
4609 @*/
4610 PetscErrorCode TSGetStepRejections(TS ts, PetscInt *rejects)
4611 {
4612   PetscFunctionBegin;
4613   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4614   PetscValidIntPointer(rejects, 2);
4615   *rejects = ts->reject;
4616   PetscFunctionReturn(PETSC_SUCCESS);
4617 }
4618 
4619 /*@
4620   TSGetSNESFailures - Gets the total number of failed `SNES` solves in a `TS`
4621 
4622   Not Collective
4623 
4624   Input Parameter:
4625 . ts - `TS` context
4626 
4627   Output Parameter:
4628 . fails - number of failed nonlinear solves
4629 
4630   Level: intermediate
4631 
4632   Note:
4633   This counter is reset to zero for each successive call to `TSSolve()`.
4634 
4635 .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetStepRejections()`, `TSSetMaxSNESFailures()`
4636 @*/
4637 PetscErrorCode TSGetSNESFailures(TS ts, PetscInt *fails)
4638 {
4639   PetscFunctionBegin;
4640   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4641   PetscValidIntPointer(fails, 2);
4642   *fails = ts->num_snes_failures;
4643   PetscFunctionReturn(PETSC_SUCCESS);
4644 }
4645 
4646 /*@
4647   TSSetMaxStepRejections - Sets the maximum number of step rejections before a time step fails
4648 
4649   Not Collective
4650 
4651   Input Parameters:
4652 + ts      - `TS` context
4653 - rejects - maximum number of rejected steps, pass -1 for unlimited
4654 
4655   Options Database Key:
4656 . -ts_max_reject - Maximum number of step rejections before a step fails
4657 
4658   Level: intermediate
4659 
4660 .seealso: [](ch_ts), `TS`, `SNES`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxSNESFailures()`, `TSGetStepRejections()`, `TSGetSNESFailures()`, `TSSetErrorIfStepFails()`, `TSGetConvergedReason()`
4661 @*/
4662 PetscErrorCode TSSetMaxStepRejections(TS ts, PetscInt rejects)
4663 {
4664   PetscFunctionBegin;
4665   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4666   ts->max_reject = rejects;
4667   PetscFunctionReturn(PETSC_SUCCESS);
4668 }
4669 
4670 /*@
4671   TSSetMaxSNESFailures - Sets the maximum number of failed `SNES` solves
4672 
4673   Not Collective
4674 
4675   Input Parameters:
4676 + ts    - `TS` context
4677 - fails - maximum number of failed nonlinear solves, pass -1 for unlimited
4678 
4679   Options Database Key:
4680 . -ts_max_snes_failures - Maximum number of nonlinear solve failures
4681 
4682   Level: intermediate
4683 
4684 .seealso: [](ch_ts), `TS`, `SNES`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetStepRejections()`, `TSGetSNESFailures()`, `SNESGetConvergedReason()`, `TSGetConvergedReason()`
4685 @*/
4686 PetscErrorCode TSSetMaxSNESFailures(TS ts, PetscInt fails)
4687 {
4688   PetscFunctionBegin;
4689   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4690   ts->max_snes_failures = fails;
4691   PetscFunctionReturn(PETSC_SUCCESS);
4692 }
4693 
4694 /*@
4695   TSSetErrorIfStepFails - Immediately error if no step succeeds during `TSSolve()`
4696 
4697   Not Collective
4698 
4699   Input Parameters:
4700 + ts  - `TS` context
4701 - err - `PETSC_TRUE` to error if no step succeeds, `PETSC_FALSE` to return without failure
4702 
4703   Options Database Key:
4704 . -ts_error_if_step_fails - Error if no step succeeds
4705 
4706   Level: intermediate
4707 
4708 .seealso: [](ch_ts), `TS`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetStepRejections()`, `TSGetSNESFailures()`, `TSSetErrorIfStepFails()`, `TSGetConvergedReason()`
4709 @*/
4710 PetscErrorCode TSSetErrorIfStepFails(TS ts, PetscBool err)
4711 {
4712   PetscFunctionBegin;
4713   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4714   ts->errorifstepfailed = err;
4715   PetscFunctionReturn(PETSC_SUCCESS);
4716 }
4717 
4718 /*@
4719   TSGetAdapt - Get the adaptive controller context for the current method
4720 
4721   Collective on `ts` if controller has not been created yet
4722 
4723   Input Parameter:
4724 . ts - time stepping context
4725 
4726   Output Parameter:
4727 . adapt - adaptive controller
4728 
4729   Level: intermediate
4730 
4731 .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSAdaptSetType()`, `TSAdaptChoose()`
4732 @*/
4733 PetscErrorCode TSGetAdapt(TS ts, TSAdapt *adapt)
4734 {
4735   PetscFunctionBegin;
4736   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4737   PetscValidPointer(adapt, 2);
4738   if (!ts->adapt) {
4739     PetscCall(TSAdaptCreate(PetscObjectComm((PetscObject)ts), &ts->adapt));
4740     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->adapt, (PetscObject)ts, 1));
4741   }
4742   *adapt = ts->adapt;
4743   PetscFunctionReturn(PETSC_SUCCESS);
4744 }
4745 
4746 /*@
4747   TSSetTolerances - Set tolerances for local truncation error when using an adaptive controller
4748 
4749   Logically Collective
4750 
4751   Input Parameters:
4752 + ts    - time integration context
4753 . atol  - scalar absolute tolerances, `PETSC_DECIDE` to leave current value
4754 . vatol - vector of absolute tolerances or `NULL`, used in preference to atol if present
4755 . rtol  - scalar relative tolerances, `PETSC_DECIDE` to leave current value
4756 - vrtol - vector of relative tolerances or `NULL`, used in preference to atol if present
4757 
4758   Options Database Keys:
4759 + -ts_rtol <rtol> - relative tolerance for local truncation error
4760 - -ts_atol <atol> - Absolute tolerance for local truncation error
4761 
4762   Level: beginner
4763 
4764   Notes:
4765   With PETSc's implicit schemes for DAE problems, the calculation of the local truncation error
4766   (LTE) includes both the differential and the algebraic variables. If one wants the LTE to be
4767   computed only for the differential or the algebraic part then this can be done using the vector of
4768   tolerances vatol. For example, by setting the tolerance vector with the desired tolerance for the
4769   differential part and infinity for the algebraic part, the LTE calculation will include only the
4770   differential variables.
4771 
4772 .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSErrorWeightedNorm()`, `TSGetTolerances()`
4773 @*/
4774 PetscErrorCode TSSetTolerances(TS ts, PetscReal atol, Vec vatol, PetscReal rtol, Vec vrtol)
4775 {
4776   PetscFunctionBegin;
4777   if (atol != (PetscReal)PETSC_DECIDE && atol != (PetscReal)PETSC_DEFAULT) ts->atol = atol;
4778   if (vatol) {
4779     PetscCall(PetscObjectReference((PetscObject)vatol));
4780     PetscCall(VecDestroy(&ts->vatol));
4781     ts->vatol = vatol;
4782   }
4783   if (rtol != (PetscReal)PETSC_DECIDE && rtol != (PetscReal)PETSC_DEFAULT) ts->rtol = rtol;
4784   if (vrtol) {
4785     PetscCall(PetscObjectReference((PetscObject)vrtol));
4786     PetscCall(VecDestroy(&ts->vrtol));
4787     ts->vrtol = vrtol;
4788   }
4789   PetscFunctionReturn(PETSC_SUCCESS);
4790 }
4791 
4792 /*@
4793   TSGetTolerances - Get tolerances for local truncation error when using adaptive controller
4794 
4795   Logically Collective
4796 
4797   Input Parameter:
4798 . ts - time integration context
4799 
4800   Output Parameters:
4801 + atol  - scalar absolute tolerances, `NULL` to ignore
4802 . vatol - vector of absolute tolerances, `NULL` to ignore
4803 . rtol  - scalar relative tolerances, `NULL` to ignore
4804 - vrtol - vector of relative tolerances, `NULL` to ignore
4805 
4806   Level: beginner
4807 
4808 .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSErrorWeightedNorm()`, `TSSetTolerances()`
4809 @*/
4810 PetscErrorCode TSGetTolerances(TS ts, PetscReal *atol, Vec *vatol, PetscReal *rtol, Vec *vrtol)
4811 {
4812   PetscFunctionBegin;
4813   if (atol) *atol = ts->atol;
4814   if (vatol) *vatol = ts->vatol;
4815   if (rtol) *rtol = ts->rtol;
4816   if (vrtol) *vrtol = ts->vrtol;
4817   PetscFunctionReturn(PETSC_SUCCESS);
4818 }
4819 
4820 /*@
4821   TSErrorWeightedNorm - compute a weighted norm of the difference between two state vectors based on supplied absolute and relative tolerances
4822 
4823   Collective
4824 
4825   Input Parameters:
4826 + ts        - time stepping context
4827 . U         - state vector, usually ts->vec_sol
4828 . Y         - state vector to be compared to U
4829 - wnormtype - norm type, either `NORM_2` or `NORM_INFINITY`
4830 
4831   Output Parameters:
4832 + norm  - weighted norm, a value of 1.0 achieves a balance between absolute and relative tolerances
4833 . norma - weighted norm, a value of 1.0 means that the error meets the absolute tolerance set by the user
4834 - normr - weighted norm, a value of 1.0 means that the error meets the relative tolerance set by the user
4835 
4836   Options Database Key:
4837 . -ts_adapt_wnormtype <wnormtype> - 2, INFINITY
4838 
4839   Level: developer
4840 
4841 .seealso: [](ch_ts), `TS`, `VecErrorWeightedNorms()`, `TSErrorWeightedENorm()`
4842 @*/
4843 PetscErrorCode TSErrorWeightedNorm(TS ts, Vec U, Vec Y, NormType wnormtype, PetscReal *norm, PetscReal *norma, PetscReal *normr)
4844 {
4845   PetscInt norma_loc, norm_loc, normr_loc;
4846 
4847   PetscFunctionBegin;
4848   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4849   PetscCall(VecErrorWeightedNorms(U, Y, NULL, wnormtype, ts->atol, ts->vatol, ts->rtol, ts->vrtol, ts->adapt->ignore_max, norm, &norm_loc, norma, &norma_loc, normr, &normr_loc));
4850   if (wnormtype == NORM_2) {
4851     if (norm_loc) *norm = PetscSqrtReal(PetscSqr(*norm) / norm_loc);
4852     if (norma_loc) *norma = PetscSqrtReal(PetscSqr(*norma) / norma_loc);
4853     if (normr_loc) *normr = PetscSqrtReal(PetscSqr(*normr) / normr_loc);
4854   }
4855   PetscCheck(!PetscIsInfOrNanScalar(*norm), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
4856   PetscCheck(!PetscIsInfOrNanScalar(*norma), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norma");
4857   PetscCheck(!PetscIsInfOrNanScalar(*normr), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in normr");
4858   PetscFunctionReturn(PETSC_SUCCESS);
4859 }
4860 
4861 /*@
4862   TSErrorWeightedENorm - compute a weighted error norm based on supplied absolute and relative tolerances
4863 
4864   Collective
4865 
4866   Input Parameters:
4867 + ts        - time stepping context
4868 . E         - error vector
4869 . U         - state vector, usually ts->vec_sol
4870 . Y         - state vector, previous time step
4871 - wnormtype - norm type, either `NORM_2` or `NORM_INFINITY`
4872 
4873   Output Parameters:
4874 + norm  - weighted norm, a value of 1.0 achieves a balance between absolute and relative tolerances
4875 . norma - weighted norm, a value of 1.0 means that the error meets the absolute tolerance set by the user
4876 - normr - weighted norm, a value of 1.0 means that the error meets the relative tolerance set by the user
4877 
4878   Options Database Key:
4879 . -ts_adapt_wnormtype <wnormtype> - 2, INFINITY
4880 
4881   Level: developer
4882 
4883 .seealso: [](ch_ts), `TS`, `VecErrorWeightedNorms()`, `TSErrorWeightedNorm()`
4884 @*/
4885 PetscErrorCode TSErrorWeightedENorm(TS ts, Vec E, Vec U, Vec Y, NormType wnormtype, PetscReal *norm, PetscReal *norma, PetscReal *normr)
4886 {
4887   PetscInt norma_loc, norm_loc, normr_loc;
4888 
4889   PetscFunctionBegin;
4890   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4891   PetscCall(VecErrorWeightedNorms(U, Y, E, wnormtype, ts->atol, ts->vatol, ts->rtol, ts->vrtol, ts->adapt->ignore_max, norm, &norm_loc, norma, &norma_loc, normr, &normr_loc));
4892   if (wnormtype == NORM_2) {
4893     if (norm_loc) *norm = PetscSqrtReal(PetscSqr(*norm) / norm_loc);
4894     if (norma_loc) *norma = PetscSqrtReal(PetscSqr(*norma) / norma_loc);
4895     if (normr_loc) *normr = PetscSqrtReal(PetscSqr(*normr) / normr_loc);
4896   }
4897   PetscCheck(!PetscIsInfOrNanScalar(*norm), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
4898   PetscCheck(!PetscIsInfOrNanScalar(*norma), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norma");
4899   PetscCheck(!PetscIsInfOrNanScalar(*normr), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in normr");
4900   PetscFunctionReturn(PETSC_SUCCESS);
4901 }
4902 
4903 /*@
4904   TSSetCFLTimeLocal - Set the local CFL constraint relative to forward Euler
4905 
4906   Logically Collective
4907 
4908   Input Parameters:
4909 + ts      - time stepping context
4910 - cfltime - maximum stable time step if using forward Euler (value can be different on each process)
4911 
4912   Note:
4913   After calling this function, the global CFL time can be obtained by calling TSGetCFLTime()
4914 
4915   Level: intermediate
4916 
4917 .seealso: [](ch_ts), `TSGetCFLTime()`, `TSADAPTCFL`
4918 @*/
4919 PetscErrorCode TSSetCFLTimeLocal(TS ts, PetscReal cfltime)
4920 {
4921   PetscFunctionBegin;
4922   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4923   ts->cfltime_local = cfltime;
4924   ts->cfltime       = -1.;
4925   PetscFunctionReturn(PETSC_SUCCESS);
4926 }
4927 
4928 /*@
4929   TSGetCFLTime - Get the maximum stable time step according to CFL criteria applied to forward Euler
4930 
4931   Collective
4932 
4933   Input Parameter:
4934 . ts - time stepping context
4935 
4936   Output Parameter:
4937 . cfltime - maximum stable time step for forward Euler
4938 
4939   Level: advanced
4940 
4941 .seealso: [](ch_ts), `TSSetCFLTimeLocal()`
4942 @*/
4943 PetscErrorCode TSGetCFLTime(TS ts, PetscReal *cfltime)
4944 {
4945   PetscFunctionBegin;
4946   if (ts->cfltime < 0) PetscCall(MPIU_Allreduce(&ts->cfltime_local, &ts->cfltime, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)ts)));
4947   *cfltime = ts->cfltime;
4948   PetscFunctionReturn(PETSC_SUCCESS);
4949 }
4950 
4951 /*@
4952   TSVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu
4953 
4954   Input Parameters:
4955 + ts - the `TS` context.
4956 . xl - lower bound.
4957 - xu - upper bound.
4958 
4959   Level: advanced
4960 
4961   Note:
4962   If this routine is not called then the lower and upper bounds are set to
4963   `PETSC_NINFINITY` and `PETSC_INFINITY` respectively during `SNESSetUp()`.
4964 
4965 .seealso: [](ch_ts), `TS`
4966 @*/
4967 PetscErrorCode TSVISetVariableBounds(TS ts, Vec xl, Vec xu)
4968 {
4969   SNES snes;
4970 
4971   PetscFunctionBegin;
4972   PetscCall(TSGetSNES(ts, &snes));
4973   PetscCall(SNESVISetVariableBounds(snes, xl, xu));
4974   PetscFunctionReturn(PETSC_SUCCESS);
4975 }
4976 
4977 /*@
4978   TSComputeLinearStability - computes the linear stability function at a point
4979 
4980   Collective
4981 
4982   Input Parameters:
4983 + ts - the `TS` context
4984 . xr - real part of input argument
4985 - xi - imaginary part of input argument
4986 
4987   Output Parameters:
4988 + yr - real part of function value
4989 - yi - imaginary part of function value
4990 
4991   Level: developer
4992 
4993 .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSComputeIFunction()`
4994 @*/
4995 PetscErrorCode TSComputeLinearStability(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi)
4996 {
4997   PetscFunctionBegin;
4998   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4999   PetscUseTypeMethod(ts, linearstability, xr, xi, yr, yi);
5000   PetscFunctionReturn(PETSC_SUCCESS);
5001 }
5002 
5003 /*@
5004   TSRestartStep - Flags the solver to restart the next step
5005 
5006   Collective
5007 
5008   Input Parameter:
5009 . ts - the `TS` context obtained from `TSCreate()`
5010 
5011   Level: advanced
5012 
5013   Notes:
5014   Multistep methods like `TSBDF` or Runge-Kutta methods with FSAL property require restarting the solver in the event of
5015   discontinuities. These discontinuities may be introduced as a consequence of explicitly modifications to the solution
5016   vector (which PETSc attempts to detect and handle) or problem coefficients (which PETSc is not able to detect). For
5017   the sake of correctness and maximum safety, users are expected to call `TSRestart()` whenever they introduce
5018   discontinuities in callback routines (e.g. prestep and poststep routines, or implicit/rhs function routines with
5019   discontinuous source terms).
5020 
5021 .seealso: [](ch_ts), `TS`, `TSBDF`, `TSSolve()`, `TSSetPreStep()`, `TSSetPostStep()`
5022 @*/
5023 PetscErrorCode TSRestartStep(TS ts)
5024 {
5025   PetscFunctionBegin;
5026   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5027   ts->steprestart = PETSC_TRUE;
5028   PetscFunctionReturn(PETSC_SUCCESS);
5029 }
5030 
5031 /*@
5032   TSRollBack - Rolls back one time step
5033 
5034   Collective
5035 
5036   Input Parameter:
5037 . ts - the `TS` context obtained from `TSCreate()`
5038 
5039   Level: advanced
5040 
5041 .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetUp()`, `TSDestroy()`, `TSSolve()`, `TSSetPreStep()`, `TSSetPreStage()`, `TSInterpolate()`
5042 @*/
5043 PetscErrorCode TSRollBack(TS ts)
5044 {
5045   PetscFunctionBegin;
5046   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5047   PetscCheck(!ts->steprollback, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "TSRollBack already called");
5048   PetscUseTypeMethod(ts, rollback);
5049   ts->time_step  = ts->ptime - ts->ptime_prev;
5050   ts->ptime      = ts->ptime_prev;
5051   ts->ptime_prev = ts->ptime_prev_rollback;
5052   ts->steps--;
5053   ts->steprollback = PETSC_TRUE;
5054   PetscFunctionReturn(PETSC_SUCCESS);
5055 }
5056 
5057 /*@
5058   TSGetStages - Get the number of stages and stage values
5059 
5060   Input Parameter:
5061 . ts - the `TS` context obtained from `TSCreate()`
5062 
5063   Output Parameters:
5064 + ns - the number of stages
5065 - Y  - the current stage vectors
5066 
5067   Level: advanced
5068 
5069   Note:
5070   Both `ns` and `Y` can be `NULL`.
5071 
5072 .seealso: [](ch_ts), `TS`, `TSCreate()`
5073 @*/
5074 PetscErrorCode TSGetStages(TS ts, PetscInt *ns, Vec **Y)
5075 {
5076   PetscFunctionBegin;
5077   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5078   if (ns) PetscValidIntPointer(ns, 2);
5079   if (Y) PetscValidPointer(Y, 3);
5080   if (!ts->ops->getstages) {
5081     if (ns) *ns = 0;
5082     if (Y) *Y = NULL;
5083   } else PetscUseTypeMethod(ts, getstages, ns, Y);
5084   PetscFunctionReturn(PETSC_SUCCESS);
5085 }
5086 
5087 /*@C
5088   TSComputeIJacobianDefaultColor - Computes the Jacobian using finite differences and coloring to exploit matrix sparsity.
5089 
5090   Collective
5091 
5092   Input Parameters:
5093 + ts    - the `TS` context
5094 . t     - current timestep
5095 . U     - state vector
5096 . Udot  - time derivative of state vector
5097 . shift - shift to apply, see note below
5098 - ctx   - an optional user context
5099 
5100   Output Parameters:
5101 + J - Jacobian matrix (not altered in this routine)
5102 - B - newly computed Jacobian matrix to use with preconditioner (generally the same as `J`)
5103 
5104   Level: intermediate
5105 
5106   Notes:
5107   If F(t,U,Udot)=0 is the DAE, the required Jacobian is
5108 
5109   dF/dU + shift*dF/dUdot
5110 
5111   Most users should not need to explicitly call this routine, as it
5112   is used internally within the nonlinear solvers.
5113 
5114   This will first try to get the coloring from the `DM`.  If the `DM` type has no coloring
5115   routine, then it will try to get the coloring from the matrix.  This requires that the
5116   matrix have nonzero entries precomputed.
5117 
5118 .seealso: [](ch_ts), `TS`, `TSSetIJacobian()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
5119 @*/
5120 PetscErrorCode TSComputeIJacobianDefaultColor(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat J, Mat B, void *ctx)
5121 {
5122   SNES          snes;
5123   MatFDColoring color;
5124   PetscBool     hascolor, matcolor = PETSC_FALSE;
5125 
5126   PetscFunctionBegin;
5127   PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_fd_color_use_mat", &matcolor, NULL));
5128   PetscCall(PetscObjectQuery((PetscObject)B, "TSMatFDColoring", (PetscObject *)&color));
5129   if (!color) {
5130     DM         dm;
5131     ISColoring iscoloring;
5132 
5133     PetscCall(TSGetDM(ts, &dm));
5134     PetscCall(DMHasColoring(dm, &hascolor));
5135     if (hascolor && !matcolor) {
5136       PetscCall(DMCreateColoring(dm, IS_COLORING_GLOBAL, &iscoloring));
5137       PetscCall(MatFDColoringCreate(B, iscoloring, &color));
5138       PetscCall(MatFDColoringSetFunction(color, (PetscErrorCode(*)(void))SNESTSFormFunction, (void *)ts));
5139       PetscCall(MatFDColoringSetFromOptions(color));
5140       PetscCall(MatFDColoringSetUp(B, iscoloring, color));
5141       PetscCall(ISColoringDestroy(&iscoloring));
5142     } else {
5143       MatColoring mc;
5144 
5145       PetscCall(MatColoringCreate(B, &mc));
5146       PetscCall(MatColoringSetDistance(mc, 2));
5147       PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
5148       PetscCall(MatColoringSetFromOptions(mc));
5149       PetscCall(MatColoringApply(mc, &iscoloring));
5150       PetscCall(MatColoringDestroy(&mc));
5151       PetscCall(MatFDColoringCreate(B, iscoloring, &color));
5152       PetscCall(MatFDColoringSetFunction(color, (PetscErrorCode(*)(void))SNESTSFormFunction, (void *)ts));
5153       PetscCall(MatFDColoringSetFromOptions(color));
5154       PetscCall(MatFDColoringSetUp(B, iscoloring, color));
5155       PetscCall(ISColoringDestroy(&iscoloring));
5156     }
5157     PetscCall(PetscObjectCompose((PetscObject)B, "TSMatFDColoring", (PetscObject)color));
5158     PetscCall(PetscObjectDereference((PetscObject)color));
5159   }
5160   PetscCall(TSGetSNES(ts, &snes));
5161   PetscCall(MatFDColoringApply(B, color, U, snes));
5162   if (J != B) {
5163     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
5164     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
5165   }
5166   PetscFunctionReturn(PETSC_SUCCESS);
5167 }
5168 
5169 /*@C
5170   TSSetFunctionDomainError - Set a function that tests if the current state vector is valid
5171 
5172   Input Parameters:
5173 + ts   - the `TS` context
5174 - func - function called within `TSFunctionDomainError()`
5175 
5176   Calling sequence of `func`:
5177 $   PetscErrorCode func(TS ts, PetscReal time, Vec state, PetscBool reject)
5178 + ts - the TS context
5179 .   time - the current time (of the stage)
5180 .   state - the state to check if it is valid
5181 -   reject - (output parameter) `PETSC_FALSE` if the state is acceptable, `PETSC_TRUE` if not acceptable
5182 
5183   Level: intermediate
5184 
5185   Notes:
5186   If an implicit ODE solver is being used then, in addition to providing this routine, the
5187   user's code should call `SNESSetFunctionDomainError()` when domain errors occur during
5188   function evaluations where the functions are provided by `TSSetIFunction()` or `TSSetRHSFunction()`.
5189   Use `TSGetSNES()` to obtain the `SNES` object
5190 
5191   Developer Notes:
5192   The naming of this function is inconsistent with the `SNESSetFunctionDomainError()`
5193   since one takes a function pointer and the other does not.
5194 
5195 .seealso: [](ch_ts), `TSAdaptCheckStage()`, `TSFunctionDomainError()`, `SNESSetFunctionDomainError()`, `TSGetSNES()`
5196 @*/
5197 PetscErrorCode TSSetFunctionDomainError(TS ts, PetscErrorCode (*func)(TS, PetscReal, Vec, PetscBool *))
5198 {
5199   PetscFunctionBegin;
5200   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5201   ts->functiondomainerror = func;
5202   PetscFunctionReturn(PETSC_SUCCESS);
5203 }
5204 
5205 /*@
5206   TSFunctionDomainError - Checks if the current state is valid
5207 
5208   Input Parameters:
5209 + ts        - the `TS` context
5210 . stagetime - time of the simulation
5211 - Y         - state vector to check.
5212 
5213   Output Parameter:
5214 . accept - Set to `PETSC_FALSE` if the current state vector is valid.
5215 
5216   Level: developer
5217 
5218   Note:
5219   This function is called by the `TS` integration routines and calls the user provided function (set with `TSSetFunctionDomainError()`)
5220   to check if the current state is valid.
5221 
5222 .seealso: [](ch_ts), `TS`, `TSSetFunctionDomainError()`
5223 @*/
5224 PetscErrorCode TSFunctionDomainError(TS ts, PetscReal stagetime, Vec Y, PetscBool *accept)
5225 {
5226   PetscFunctionBegin;
5227   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5228   *accept = PETSC_TRUE;
5229   if (ts->functiondomainerror) PetscCall((*ts->functiondomainerror)(ts, stagetime, Y, accept));
5230   PetscFunctionReturn(PETSC_SUCCESS);
5231 }
5232 
5233 /*@C
5234   TSClone - This function clones a time step `TS` object.
5235 
5236   Collective
5237 
5238   Input Parameter:
5239 . tsin - The input `TS`
5240 
5241   Output Parameter:
5242 . tsout - The output `TS` (cloned)
5243 
5244   Level: developer
5245 
5246   Notes:
5247   This function is used to create a clone of a `TS` object. It is used in `TSARKIMEX` for initializing the slope for first stage explicit methods.
5248   It will likely be replaced in the future with a mechanism of switching methods on the fly.
5249 
5250   When using `TSDestroy()` on a clone the user has to first reset the correct `TS` reference in the embedded `SNES` object: e.g., by running
5251 .vb
5252  SNES snes_dup = NULL;
5253  TSGetSNES(ts,&snes_dup);
5254  TSSetSNES(ts,snes_dup);
5255 .ve
5256 
5257 .seealso: [](ch_ts), `TS`, `SNES`, `TSCreate()`, `TSSetType()`, `TSSetUp()`, `TSDestroy()`, `TSSetProblemType()`
5258 @*/
5259 PetscErrorCode TSClone(TS tsin, TS *tsout)
5260 {
5261   TS     t;
5262   SNES   snes_start;
5263   DM     dm;
5264   TSType type;
5265 
5266   PetscFunctionBegin;
5267   PetscValidPointer(tsin, 1);
5268   *tsout = NULL;
5269 
5270   PetscCall(PetscHeaderCreate(t, TS_CLASSID, "TS", "Time stepping", "TS", PetscObjectComm((PetscObject)tsin), TSDestroy, TSView));
5271 
5272   /* General TS description */
5273   t->numbermonitors    = 0;
5274   t->monitorFrequency  = 1;
5275   t->setupcalled       = 0;
5276   t->ksp_its           = 0;
5277   t->snes_its          = 0;
5278   t->nwork             = 0;
5279   t->rhsjacobian.time  = PETSC_MIN_REAL;
5280   t->rhsjacobian.scale = 1.;
5281   t->ijacobian.shift   = 1.;
5282 
5283   PetscCall(TSGetSNES(tsin, &snes_start));
5284   PetscCall(TSSetSNES(t, snes_start));
5285 
5286   PetscCall(TSGetDM(tsin, &dm));
5287   PetscCall(TSSetDM(t, dm));
5288 
5289   t->adapt = tsin->adapt;
5290   PetscCall(PetscObjectReference((PetscObject)t->adapt));
5291 
5292   t->trajectory = tsin->trajectory;
5293   PetscCall(PetscObjectReference((PetscObject)t->trajectory));
5294 
5295   t->event = tsin->event;
5296   if (t->event) t->event->refct++;
5297 
5298   t->problem_type      = tsin->problem_type;
5299   t->ptime             = tsin->ptime;
5300   t->ptime_prev        = tsin->ptime_prev;
5301   t->time_step         = tsin->time_step;
5302   t->max_time          = tsin->max_time;
5303   t->steps             = tsin->steps;
5304   t->max_steps         = tsin->max_steps;
5305   t->equation_type     = tsin->equation_type;
5306   t->atol              = tsin->atol;
5307   t->rtol              = tsin->rtol;
5308   t->max_snes_failures = tsin->max_snes_failures;
5309   t->max_reject        = tsin->max_reject;
5310   t->errorifstepfailed = tsin->errorifstepfailed;
5311 
5312   PetscCall(TSGetType(tsin, &type));
5313   PetscCall(TSSetType(t, type));
5314 
5315   t->vec_sol = NULL;
5316 
5317   t->cfltime          = tsin->cfltime;
5318   t->cfltime_local    = tsin->cfltime_local;
5319   t->exact_final_time = tsin->exact_final_time;
5320 
5321   t->ops[0] = tsin->ops[0];
5322 
5323   if (((PetscObject)tsin)->fortran_func_pointers) {
5324     PetscInt i;
5325     PetscCall(PetscMalloc((10) * sizeof(void (*)(void)), &((PetscObject)t)->fortran_func_pointers));
5326     for (i = 0; i < 10; i++) ((PetscObject)t)->fortran_func_pointers[i] = ((PetscObject)tsin)->fortran_func_pointers[i];
5327   }
5328   *tsout = t;
5329   PetscFunctionReturn(PETSC_SUCCESS);
5330 }
5331 
5332 static PetscErrorCode RHSWrapperFunction_TSRHSJacobianTest(void *ctx, Vec x, Vec y)
5333 {
5334   TS ts = (TS)ctx;
5335 
5336   PetscFunctionBegin;
5337   PetscCall(TSComputeRHSFunction(ts, 0, x, y));
5338   PetscFunctionReturn(PETSC_SUCCESS);
5339 }
5340 
5341 /*@
5342   TSRHSJacobianTest - Compares the multiply routine provided to the `MATSHELL` with differencing on the `TS` given RHS function.
5343 
5344   Logically Collective
5345 
5346   Input Parameter:
5347 . ts - the time stepping routine
5348 
5349   Output Parameter:
5350 . flg - `PETSC_TRUE` if the multiply is likely correct
5351 
5352   Options Database Key:
5353 . -ts_rhs_jacobian_test_mult -mat_shell_test_mult_view - run the test at each timestep of the integrator
5354 
5355   Level: advanced
5356 
5357   Note:
5358   This only works for problems defined using `TSSetRHSFunction()` and Jacobian NOT `TSSetIFunction()` and Jacobian
5359 
5360 .seealso: [](ch_ts), `TS`, `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`, `TSRHSJacobianTestTranspose()`
5361 @*/
5362 PetscErrorCode TSRHSJacobianTest(TS ts, PetscBool *flg)
5363 {
5364   Mat           J, B;
5365   TSRHSJacobian func;
5366   void         *ctx;
5367 
5368   PetscFunctionBegin;
5369   PetscCall(TSGetRHSJacobian(ts, &J, &B, &func, &ctx));
5370   PetscCall((*func)(ts, 0.0, ts->vec_sol, J, B, ctx));
5371   PetscCall(MatShellTestMult(J, RHSWrapperFunction_TSRHSJacobianTest, ts->vec_sol, ts, flg));
5372   PetscFunctionReturn(PETSC_SUCCESS);
5373 }
5374 
5375 /*@C
5376   TSRHSJacobianTestTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on the `TS` given RHS function.
5377 
5378   Logically Collective
5379 
5380   Input Parameter:
5381 . ts - the time stepping routine
5382 
5383   Output Parameter:
5384 . flg - `PETSC_TRUE` if the multiply is likely correct
5385 
5386   Options Database Key:
5387 . -ts_rhs_jacobian_test_mult_transpose -mat_shell_test_mult_transpose_view - run the test at each timestep of the integrator
5388 
5389   Level: advanced
5390 
5391   Notes:
5392   This only works for problems defined using `TSSetRHSFunction()` and Jacobian NOT `TSSetIFunction()` and Jacobian
5393 
5394 .seealso: [](ch_ts), `TS`, `Mat`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`, `TSRHSJacobianTest()`
5395 @*/
5396 PetscErrorCode TSRHSJacobianTestTranspose(TS ts, PetscBool *flg)
5397 {
5398   Mat           J, B;
5399   void         *ctx;
5400   TSRHSJacobian func;
5401 
5402   PetscFunctionBegin;
5403   PetscCall(TSGetRHSJacobian(ts, &J, &B, &func, &ctx));
5404   PetscCall((*func)(ts, 0.0, ts->vec_sol, J, B, ctx));
5405   PetscCall(MatShellTestMultTranspose(J, RHSWrapperFunction_TSRHSJacobianTest, ts->vec_sol, ts, flg));
5406   PetscFunctionReturn(PETSC_SUCCESS);
5407 }
5408 
5409 /*@
5410   TSSetUseSplitRHSFunction - Use the split RHSFunction when a multirate method is used.
5411 
5412   Logically Collective
5413 
5414   Input Parameters:
5415 + ts                   - timestepping context
5416 - use_splitrhsfunction - `PETSC_TRUE` indicates that the split RHSFunction will be used
5417 
5418   Options Database Key:
5419 . -ts_use_splitrhsfunction - <true,false>
5420 
5421   Level: intermediate
5422 
5423   Note:
5424   This is only for multirate methods
5425 
5426 .seealso: [](ch_ts), `TS`, `TSGetUseSplitRHSFunction()`
5427 @*/
5428 PetscErrorCode TSSetUseSplitRHSFunction(TS ts, PetscBool use_splitrhsfunction)
5429 {
5430   PetscFunctionBegin;
5431   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5432   ts->use_splitrhsfunction = use_splitrhsfunction;
5433   PetscFunctionReturn(PETSC_SUCCESS);
5434 }
5435 
5436 /*@
5437   TSGetUseSplitRHSFunction - Gets whether to use the split RHSFunction when a multirate method is used.
5438 
5439   Not Collective
5440 
5441   Input Parameter:
5442 . ts - timestepping context
5443 
5444   Output Parameter:
5445 . use_splitrhsfunction - `PETSC_TRUE` indicates that the split RHSFunction will be used
5446 
5447   Level: intermediate
5448 
5449 .seealso: [](ch_ts), `TS`, `TSSetUseSplitRHSFunction()`
5450 @*/
5451 PetscErrorCode TSGetUseSplitRHSFunction(TS ts, PetscBool *use_splitrhsfunction)
5452 {
5453   PetscFunctionBegin;
5454   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5455   *use_splitrhsfunction = ts->use_splitrhsfunction;
5456   PetscFunctionReturn(PETSC_SUCCESS);
5457 }
5458 
5459 /*@
5460   TSSetMatStructure - sets the relationship between the nonzero structure of the RHS Jacobian matrix to the IJacobian matrix.
5461 
5462   Logically  Collective
5463 
5464   Input Parameters:
5465 + ts  - the time-stepper
5466 - str - the structure (the default is `UNKNOWN_NONZERO_PATTERN`)
5467 
5468   Level: intermediate
5469 
5470   Note:
5471   When the relationship between the nonzero structures is known and supplied the solution process can be much faster
5472 
5473 .seealso: [](ch_ts), `TS`, `MatAXPY()`, `MatStructure`
5474  @*/
5475 PetscErrorCode TSSetMatStructure(TS ts, MatStructure str)
5476 {
5477   PetscFunctionBegin;
5478   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5479   ts->axpy_pattern = str;
5480   PetscFunctionReturn(PETSC_SUCCESS);
5481 }
5482 
5483 /*@
5484   TSSetTimeSpan - sets the time span. The solution will be computed and stored for each time requested in the span
5485 
5486   Collective
5487 
5488   Input Parameters:
5489 + ts         - the time-stepper
5490 . n          - number of the time points (>=2)
5491 - span_times - array of the time points. The first element and the last element are the initial time and the final time respectively.
5492 
5493   Options Database Key:
5494 . -ts_time_span <t0,...tf> - Sets the time span
5495 
5496   Level: intermediate
5497 
5498   Notes:
5499   The elements in tspan must be all increasing. They correspond to the intermediate points for time integration.
5500   `TS_EXACTFINALTIME_MATCHSTEP` must be used to make the last time step in each sub-interval match the intermediate points specified.
5501   The intermediate solutions are saved in a vector array that can be accessed with `TSGetTimeSpanSolutions()`. Thus using time span may
5502   pressure the memory system when using a large number of span points.
5503 
5504 .seealso: [](ch_ts), `TS`, `TSGetTimeSpan()`, `TSGetTimeSpanSolutions()`
5505  @*/
5506 PetscErrorCode TSSetTimeSpan(TS ts, PetscInt n, PetscReal *span_times)
5507 {
5508   PetscFunctionBegin;
5509   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5510   PetscCheck(n >= 2, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Minimum time span size is 2 but %" PetscInt_FMT " is provided", n);
5511   if (ts->tspan && n != ts->tspan->num_span_times) {
5512     PetscCall(PetscFree(ts->tspan->span_times));
5513     PetscCall(VecDestroyVecs(ts->tspan->num_span_times, &ts->tspan->vecs_sol));
5514     PetscCall(PetscMalloc1(n, &ts->tspan->span_times));
5515   }
5516   if (!ts->tspan) {
5517     TSTimeSpan tspan;
5518     PetscCall(PetscNew(&tspan));
5519     PetscCall(PetscMalloc1(n, &tspan->span_times));
5520     tspan->reltol = 1e-6;
5521     tspan->abstol = 10 * PETSC_MACHINE_EPSILON;
5522     ts->tspan     = tspan;
5523   }
5524   ts->tspan->num_span_times = n;
5525   PetscCall(PetscArraycpy(ts->tspan->span_times, span_times, n));
5526   PetscCall(TSSetTime(ts, ts->tspan->span_times[0]));
5527   PetscCall(TSSetMaxTime(ts, ts->tspan->span_times[n - 1]));
5528   PetscFunctionReturn(PETSC_SUCCESS);
5529 }
5530 
5531 /*@C
5532   TSGetTimeSpan - gets the time span set with `TSSetTimeSpan()`
5533 
5534   Not Collective
5535 
5536   Input Parameter:
5537 . ts - the time-stepper
5538 
5539   Output Parameters:
5540 + n          - number of the time points (>=2)
5541 - span_times - array of the time points. The first element and the last element are the initial time and the final time respectively.
5542 
5543   Level: beginner
5544 
5545   Note:
5546   The values obtained are valid until the `TS` object is destroyed.
5547 
5548   Both `n` and `span_times` can be `NULL`.
5549 
5550 .seealso: [](ch_ts), `TS`, `TSSetTimeSpan()`, `TSGetTimeSpanSolutions()`
5551  @*/
5552 PetscErrorCode TSGetTimeSpan(TS ts, PetscInt *n, const PetscReal **span_times)
5553 {
5554   PetscFunctionBegin;
5555   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5556   if (n) PetscValidIntPointer(n, 2);
5557   if (span_times) PetscValidPointer(span_times, 3);
5558   if (!ts->tspan) {
5559     if (n) *n = 0;
5560     if (span_times) *span_times = NULL;
5561   } else {
5562     if (n) *n = ts->tspan->num_span_times;
5563     if (span_times) *span_times = ts->tspan->span_times;
5564   }
5565   PetscFunctionReturn(PETSC_SUCCESS);
5566 }
5567 
5568 /*@
5569   TSGetTimeSpanSolutions - Get the number of solutions and the solutions at the time points specified by the time span.
5570 
5571   Input Parameter:
5572 . ts - the `TS` context obtained from `TSCreate()`
5573 
5574   Output Parameters:
5575 + nsol - the number of solutions
5576 - Sols - the solution vectors
5577 
5578   Level: intermediate
5579 
5580   Notes:
5581   Both `nsol` and `Sols` can be `NULL`.
5582 
5583   Some time points in the time span may be skipped by `TS` so that `nsol` is less than the number of points specified by `TSSetTimeSpan()`.
5584   For example, manipulating the step size, especially with a reduced precision, may cause `TS` to step over certain points in the span.
5585 
5586 .seealso: [](ch_ts), `TS`, `TSSetTimeSpan()`
5587 @*/
5588 PetscErrorCode TSGetTimeSpanSolutions(TS ts, PetscInt *nsol, Vec **Sols)
5589 {
5590   PetscFunctionBegin;
5591   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5592   if (nsol) PetscValidIntPointer(nsol, 2);
5593   if (Sols) PetscValidPointer(Sols, 3);
5594   if (!ts->tspan) {
5595     if (nsol) *nsol = 0;
5596     if (Sols) *Sols = NULL;
5597   } else {
5598     if (nsol) *nsol = ts->tspan->spanctr;
5599     if (Sols) *Sols = ts->tspan->vecs_sol;
5600   }
5601   PetscFunctionReturn(PETSC_SUCCESS);
5602 }
5603 
5604 /*@C
5605   TSPruneIJacobianColor - Remove nondiagonal zeros in the Jacobian matrix and update the `MatMFFD` coloring information.
5606 
5607   Collective
5608 
5609   Input Parameters:
5610 + ts - the `TS` context
5611 . J  - Jacobian matrix (not altered in this routine)
5612 - B  - newly computed Jacobian matrix to use with preconditioner
5613 
5614   Level: intermediate
5615 
5616   Notes:
5617   This function improves the `MatFDColoring` performance when the Jacobian matrix was over-allocated or contains
5618   many constant zeros entries, which is typically the case when the matrix is generated by a `DM`
5619   and multiple fields are involved.
5620 
5621   Users need to make sure that the Jacobian matrix is properly filled to reflect the sparsity
5622   structure. For `MatFDColoring`, the values of nonzero entries are not important. So one can
5623   usually call `TSComputeIJacobian()` with randomized input vectors to generate a dummy Jacobian.
5624   `TSComputeIJacobian()` should be called before `TSSolve()` but after `TSSetUp()`.
5625 
5626 .seealso: [](ch_ts), `TS`, `MatFDColoring`, `TSComputeIJacobianDefaultColor()`, `MatEliminateZeros()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
5627 @*/
5628 PetscErrorCode TSPruneIJacobianColor(TS ts, Mat J, Mat B)
5629 {
5630   MatColoring   mc            = NULL;
5631   ISColoring    iscoloring    = NULL;
5632   MatFDColoring matfdcoloring = NULL;
5633 
5634   PetscFunctionBegin;
5635   /* Generate new coloring after eliminating zeros in the matrix */
5636   PetscCall(MatEliminateZeros(B));
5637   PetscCall(MatColoringCreate(B, &mc));
5638   PetscCall(MatColoringSetDistance(mc, 2));
5639   PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
5640   PetscCall(MatColoringSetFromOptions(mc));
5641   PetscCall(MatColoringApply(mc, &iscoloring));
5642   PetscCall(MatColoringDestroy(&mc));
5643   /* Replace the old coloring with the new one */
5644   PetscCall(MatFDColoringCreate(B, iscoloring, &matfdcoloring));
5645   PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode(*)(void))SNESTSFormFunction, (void *)ts));
5646   PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
5647   PetscCall(MatFDColoringSetUp(B, iscoloring, matfdcoloring));
5648   PetscCall(PetscObjectCompose((PetscObject)B, "TSMatFDColoring", (PetscObject)matfdcoloring));
5649   PetscCall(PetscObjectDereference((PetscObject)matfdcoloring));
5650   PetscCall(ISColoringDestroy(&iscoloring));
5651   PetscFunctionReturn(PETSC_SUCCESS);
5652 }
5653