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