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