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