Date: 2026-06-01T23:13:48+00:00

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: /* Logging support */
     11: PetscClassId  TS_CLASSID, DMTS_CLASSID;
     12: PetscLogEvent TS_Step, TS_PseudoComputeTimeStep, TS_FunctionEval, TS_JacobianEval;

     14: const char *const TSExactFinalTimeOptions[] = {"UNSPECIFIED", "STEPOVER", "INTERPOLATE", "MATCHSTEP", "TSExactFinalTimeOption", "TS_EXACTFINALTIME_", NULL};

     16: static PetscErrorCode TSAdaptSetDefaultType(TSAdapt adapt, TSAdaptType default_type)
     17: {
     18:   PetscFunctionBegin;
     20:   PetscAssertPointer(default_type, 2);
     21:   if (!((PetscObject)adapt)->type_name) PetscCall(TSAdaptSetType(adapt, default_type));
     22:   PetscFunctionReturn(PETSC_SUCCESS);
     23: }

     25: /*@
     26:   TSSetFromOptions - Sets various `TS` parameters from the options database

     28:   Collective

     30:   Input Parameter:
     31: . ts - the `TS` context obtained from `TSCreate()`

     33:   Options Database Keys:
     34: + -ts_type type                                                      - EULER, BEULER, SUNDIALS, PSEUDO, CN, RK, THETA, ALPHA, GLLE,  SSP, GLEE, BSYMP, IRK, see `TSType`
     35: . -ts_save_trajectory                                                - checkpoint the solution at each time-step
     36: . -ts_max_time time                                                  - maximum time to compute to
     37: . -ts_time_span t0,...,tf                                            - sets the time span, solutions are computed and stored for each indicated time, init_time and max_time are set
     38: . -ts_eval_times t0,...,tn                                           - time points where solutions are computed and stored for each indicated time
     39: . -ts_max_steps steps                                                - maximum time-step number to execute until (possibly with nonzero starting value)
     40: . -ts_run_steps steps                                                - maximum number of time steps for `TSSolve()` to take on each call
     41: . -ts_init_time time                                                 - initial time to start computation
     42: . -ts_final_time time                                                - final time to compute to (deprecated: use `-ts_max_time`)
     43: . -ts_time_step dt                                                   - initial time step (only a suggestion, the actual initial time step used differ)
     44: . -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
     45: . -ts_max_snes_failures maxfailures                                  - Maximum number of nonlinear solve failures allowed
     46: . -ts_max_step_rejections maxrejects                                 - Maximum number of step rejections before step fails
     47: . -ts_error_if_step_fails (true|false)                               - Error if no step succeeds
     48: . -ts_rtol rtol                                                      - relative tolerance for local truncation error
     49: . -ts_atol atol                                                      - Absolute tolerance for local truncation error
     50: . -ts_rhs_jacobian_test_mult -mat_shell_test_mult_view               - test the Jacobian at each iteration against finite difference with RHS function
     51: . -ts_rhs_jacobian_test_mult_transpose                               - test the Jacobian at each iteration against finite difference with RHS function
     52: . -ts_adjoint_solve (true|false)                                     - After solving the ODE/DAE solve the adjoint problem (requires `-ts_save_trajectory`)
     53: . -ts_fd_color                                                       - Use finite differences with coloring to compute IJacobian
     54: . -ts_monitor                                                        - print information at each timestep
     55: . -ts_monitor_cancel                                                 - Cancel all monitors
     56: . -ts_monitor_wall_clock_time                                        - Monitor wall-clock time, KSP iterations, and SNES iterations per step
     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. Use -1 to only output at the end of the simulation
     70: . -ts_monitor_solution_skip_initial                                  - skip writing of initial condition
     71: . -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)
     72: . -ts_monitor_solution_vtk_interval interval                         - output once every interval (default=1) time steps. Use -1 to only output at the end of the simulation
     73: - -ts_monitor_envelope                                               - determine maximum and minimum value of each component of the solution over the solution time

     75:   Level: beginner

     77:   Notes:
     78:   See `SNESSetFromOptions()` and `KSPSetFromOptions()` for how to control the nonlinear and linear solves used by the time-stepper.

     80:   Certain `SNES` options get reset for each new nonlinear solver, for example `-snes_lag_jacobian its` and `-snes_lag_preconditioner its`, in order
     81:   to retain them over the multiple nonlinear solves that `TS` uses you must also provide `-snes_lag_jacobian_persists true` and
     82:   `-snes_lag_preconditioner_persists true`

     84:   Developer Notes:
     85:   We should unify all the -ts_monitor options in the way that -xxx_view has been unified

     87: .seealso: [](ch_ts), `TS`, `TSGetType()`
     88: @*/
     89: PetscErrorCode TSSetFromOptions(TS ts)
     90: {
     91:   PetscBool              opt, flg, tflg;
     92:   char                   monfilename[PETSC_MAX_PATH_LEN];
     93:   PetscReal              time_step, eval_times[100] = {0};
     94:   PetscInt               num_eval_times = PETSC_STATIC_ARRAY_LENGTH(eval_times);
     95:   TSExactFinalTimeOption eftopt;
     96:   char                   dir[16];
     97:   TSIFunctionFn         *ifun;
     98:   const char            *defaultType;
     99:   char                   typeName[256];

    101:   PetscFunctionBegin;

    104:   PetscCall(TSRegisterAll());
    105:   PetscCall(TSGetIFunction(ts, NULL, &ifun, NULL));

    107:   PetscObjectOptionsBegin((PetscObject)ts);
    108:   if (((PetscObject)ts)->type_name) defaultType = ((PetscObject)ts)->type_name;
    109:   else defaultType = ifun ? TSBEULER : TSEULER;
    110:   PetscCall(PetscOptionsFList("-ts_type", "TS method", "TSSetType", TSList, defaultType, typeName, 256, &opt));
    111:   if (opt) PetscCall(TSSetType(ts, typeName));
    112:   else PetscCall(TSSetType(ts, defaultType));

    114:   /* Handle generic TS options */
    115:   PetscCall(PetscOptionsDeprecated("-ts_final_time", "-ts_max_time", "3.10", NULL));
    116:   PetscCall(PetscOptionsReal("-ts_max_time", "Maximum time to run to", "TSSetMaxTime", ts->max_time, &ts->max_time, NULL));
    117:   PetscCall(PetscOptionsRealArray("-ts_time_span", "Time span", "TSSetTimeSpan", eval_times, &num_eval_times, &flg));
    118:   if (flg) PetscCall(TSSetTimeSpan(ts, num_eval_times, eval_times));
    119:   num_eval_times = PETSC_STATIC_ARRAY_LENGTH(eval_times);
    120:   PetscCall(PetscOptionsRealArray("-ts_eval_times", "Evaluation time points", "TSSetEvaluationTimes", eval_times, &num_eval_times, &opt));
    121:   PetscCheck(flg != opt || (!flg && !opt), PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "May not provide -ts_time_span and -ts_eval_times simultaneously");
    122:   if (opt) PetscCall(TSSetEvaluationTimes(ts, num_eval_times, eval_times));
    123:   PetscCall(PetscOptionsInt("-ts_max_steps", "Maximum time step number to execute to (possibly with non-zero starting value)", "TSSetMaxSteps", ts->max_steps, &ts->max_steps, NULL));
    124:   PetscCall(PetscOptionsInt("-ts_run_steps", "Maximum number of time steps to take on each call to TSSolve()", "TSSetRunSteps", ts->run_steps, &ts->run_steps, NULL));
    125:   PetscCall(PetscOptionsReal("-ts_init_time", "Initial time", "TSSetTime", ts->ptime, &ts->ptime, NULL));
    126:   PetscCall(PetscOptionsDeprecated("-ts_dt", "-ts_time_step", "3.25", NULL));
    127:   PetscCall(PetscOptionsReal("-ts_time_step", "Initial time step", "TSSetTimeStep", ts->time_step, &time_step, &flg));
    128:   if (flg) PetscCall(TSSetTimeStep(ts, time_step));
    129:   PetscCall(PetscOptionsEnum("-ts_exact_final_time", "Option for handling of final time step", "TSSetExactFinalTime", TSExactFinalTimeOptions, (PetscEnum)ts->exact_final_time, (PetscEnum *)&eftopt, &flg));
    130:   if (flg) PetscCall(TSSetExactFinalTime(ts, eftopt));
    131:   PetscCall(PetscOptionsInt("-ts_max_snes_failures", "Maximum number of nonlinear solve failures", "TSSetMaxSNESFailures", ts->max_snes_failures, &ts->max_snes_failures, &flg));
    132:   if (flg) PetscCall(TSSetMaxSNESFailures(ts, ts->max_snes_failures));
    133:   PetscCall(PetscOptionsDeprecated("-ts_max_reject", "-ts_max_step_rejections", "3.25", NULL));
    134:   PetscCall(PetscOptionsInt("-ts_max_step_rejections", "Maximum number of step rejections before step fails", "TSSetMaxStepRejections", ts->max_reject, &ts->max_reject, &flg));
    135:   if (flg) PetscCall(TSSetMaxStepRejections(ts, ts->max_reject));
    136:   PetscCall(PetscOptionsBool("-ts_error_if_step_fails", "Error if no step succeeds", "TSSetErrorIfStepFails", ts->errorifstepfailed, &ts->errorifstepfailed, NULL));
    137:   PetscCall(PetscOptionsBoundedReal("-ts_rtol", "Relative tolerance for local truncation error", "TSSetTolerances", ts->rtol, &ts->rtol, NULL, 0));
    138:   PetscCall(PetscOptionsBoundedReal("-ts_atol", "Absolute tolerance for local truncation error", "TSSetTolerances", ts->atol, &ts->atol, NULL, 0));

    140:   PetscCall(PetscOptionsBool("-ts_rhs_jacobian_test_mult", "Test the RHS Jacobian for consistency with RHS at each solve ", "None", ts->testjacobian, &ts->testjacobian, NULL));
    141:   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));
    142:   PetscCall(PetscOptionsBool("-ts_use_splitrhsfunction", "Use the split RHS function for multirate solvers ", "TSSetUseSplitRHSFunction", ts->use_splitrhsfunction, &ts->use_splitrhsfunction, NULL));
    143: #if defined(PETSC_HAVE_SAWS)
    144:   {
    145:     PetscBool set;
    146:     flg = PETSC_FALSE;
    147:     PetscCall(PetscOptionsBool("-ts_saws_block", "Block for SAWs memory snooper at end of TSSolve", "PetscObjectSAWsBlock", ((PetscObject)ts)->amspublishblock, &flg, &set));
    148:     if (set) PetscCall(PetscObjectSAWsSetBlock((PetscObject)ts, flg));
    149:   }
    150: #endif

    152:   /* Monitor options */
    153:   PetscCall(PetscOptionsDeprecated("-ts_monitor_frequency", "-ts_dmswarm_monitor_moments_interval", "3.24", "Retired in favor of monitor-specific intervals (ts_dmswarm_monitor_moments was the only monitor to use ts_monitor_frequency)"));
    154:   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor", "Monitor time and timestep size", "TSMonitorDefault", TSMonitorDefault, NULL));
    155:   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_wall_clock_time", "Monitor wall-clock time, KSP iterations, and SNES iterations per step", "TSMonitorWallClockTime", TSMonitorWallClockTime, TSMonitorWallClockTimeSetUp));
    156:   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_extreme", "Monitor extreme values of the solution", "TSMonitorExtreme", TSMonitorExtreme, NULL));
    157:   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_solution", "View the solution at each timestep", "TSMonitorSolution", TSMonitorSolution, TSMonitorSolutionSetup));
    158:   PetscCall(TSMonitorSetFromOptions(ts, "-ts_dmswarm_monitor_moments", "Monitor moments of particle distribution", "TSDMSwarmMonitorMoments", TSDMSwarmMonitorMoments, NULL));
    159:   PetscCall(PetscOptionsString("-ts_monitor_python", "Use Python function", "TSMonitorSet", NULL, monfilename, sizeof(monfilename), &flg));
    160:   if (flg) PetscCall(PetscPythonMonitorSet((PetscObject)ts, monfilename));

    162:   PetscCall(PetscOptionsName("-ts_monitor_lg_solution", "Monitor solution graphically", "TSMonitorLGSolution", &opt));
    163:   if (opt) {
    164:     PetscInt  howoften = 1;
    165:     DM        dm;
    166:     PetscBool net;

    168:     PetscCall(PetscOptionsInt("-ts_monitor_lg_solution", "Monitor solution graphically", "TSMonitorLGSolution", howoften, &howoften, NULL));
    169:     PetscCall(TSGetDM(ts, &dm));
    170:     PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMNETWORK, &net));
    171:     if (net) {
    172:       TSMonitorLGCtxNetwork ctx;
    173:       PetscCall(TSMonitorLGCtxNetworkCreate(ts, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 600, 400, howoften, &ctx));
    174:       PetscCall(TSMonitorSet(ts, TSMonitorLGCtxNetworkSolution, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxNetworkDestroy));
    175:       PetscCall(PetscOptionsBool("-ts_monitor_lg_solution_semilogy", "Plot the solution with a semi-log axis", "", ctx->semilogy, &ctx->semilogy, NULL));
    176:     } else {
    177:       TSMonitorLGCtx ctx;
    178:       PetscCall(TSMonitorLGCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
    179:       PetscCall(TSMonitorSet(ts, TSMonitorLGSolution, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxDestroy));
    180:     }
    181:   }

    183:   PetscCall(PetscOptionsName("-ts_monitor_lg_error", "Monitor error graphically", "TSMonitorLGError", &opt));
    184:   if (opt) {
    185:     TSMonitorLGCtx ctx;
    186:     PetscInt       howoften = 1;

    188:     PetscCall(PetscOptionsInt("-ts_monitor_lg_error", "Monitor error graphically", "TSMonitorLGError", howoften, &howoften, NULL));
    189:     PetscCall(TSMonitorLGCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
    190:     PetscCall(TSMonitorSet(ts, TSMonitorLGError, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxDestroy));
    191:   }
    192:   PetscCall(TSMonitorSetFromOptions(ts, "-ts_monitor_error", "View the error at each timestep", "TSMonitorError", TSMonitorError, NULL));

    194:   PetscCall(PetscOptionsName("-ts_monitor_lg_timestep", "Monitor timestep size graphically", "TSMonitorLGTimeStep", &opt));
    195:   if (opt) {
    196:     TSMonitorLGCtx ctx;
    197:     PetscInt       howoften = 1;

    199:     PetscCall(PetscOptionsInt("-ts_monitor_lg_timestep", "Monitor timestep size graphically", "TSMonitorLGTimeStep", howoften, &howoften, NULL));
    200:     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
    201:     PetscCall(TSMonitorSet(ts, TSMonitorLGTimeStep, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxDestroy));
    202:   }
    203:   PetscCall(PetscOptionsName("-ts_monitor_lg_timestep_log", "Monitor log timestep size graphically", "TSMonitorLGTimeStep", &opt));
    204:   if (opt) {
    205:     TSMonitorLGCtx ctx;
    206:     PetscInt       howoften = 1;

    208:     PetscCall(PetscOptionsInt("-ts_monitor_lg_timestep_log", "Monitor log timestep size graphically", "TSMonitorLGTimeStep", howoften, &howoften, NULL));
    209:     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
    210:     PetscCall(TSMonitorSet(ts, TSMonitorLGTimeStep, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxDestroy));
    211:     ctx->semilogy = PETSC_TRUE;
    212:   }

    214:   PetscCall(PetscOptionsName("-ts_monitor_lg_snes_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGSNESIterations", &opt));
    215:   if (opt) {
    216:     TSMonitorLGCtx ctx;
    217:     PetscInt       howoften = 1;

    219:     PetscCall(PetscOptionsInt("-ts_monitor_lg_snes_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGSNESIterations", howoften, &howoften, NULL));
    220:     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
    221:     PetscCall(TSMonitorSet(ts, TSMonitorLGSNESIterations, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxDestroy));
    222:   }
    223:   PetscCall(PetscOptionsName("-ts_monitor_lg_ksp_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGKSPIterations", &opt));
    224:   if (opt) {
    225:     TSMonitorLGCtx ctx;
    226:     PetscInt       howoften = 1;

    228:     PetscCall(PetscOptionsInt("-ts_monitor_lg_ksp_iterations", "Monitor number nonlinear iterations for each timestep graphically", "TSMonitorLGKSPIterations", howoften, &howoften, NULL));
    229:     PetscCall(TSMonitorLGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, howoften, &ctx));
    230:     PetscCall(TSMonitorSet(ts, TSMonitorLGKSPIterations, ctx, (PetscCtxDestroyFn *)TSMonitorLGCtxDestroy));
    231:   }
    232:   PetscCall(PetscOptionsName("-ts_monitor_sp_eig", "Monitor eigenvalues of linearized operator graphically", "TSMonitorSPEig", &opt));
    233:   if (opt) {
    234:     TSMonitorSPEigCtx ctx;
    235:     PetscInt          howoften = 1;

    237:     PetscCall(PetscOptionsInt("-ts_monitor_sp_eig", "Monitor eigenvalues of linearized operator graphically", "TSMonitorSPEig", howoften, &howoften, NULL));
    238:     PetscCall(TSMonitorSPEigCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
    239:     PetscCall(TSMonitorSet(ts, TSMonitorSPEig, ctx, (PetscCtxDestroyFn *)TSMonitorSPEigCtxDestroy));
    240:   }
    241:   PetscCall(PetscOptionsName("-ts_monitor_sp_swarm", "Display particle phase space from the DMSwarm", "TSMonitorSPSwarm", &opt));
    242:   if (opt) {
    243:     TSMonitorSPCtx ctx;
    244:     PetscInt       howoften = 1, retain = 0;
    245:     PetscBool      phase = PETSC_TRUE, create = PETSC_TRUE, multispecies = PETSC_FALSE;

    247:     for (PetscInt i = 0; i < ts->numbermonitors; ++i)
    248:       if (ts->monitor[i] == TSMonitorSPSwarmSolution) {
    249:         create = PETSC_FALSE;
    250:         break;
    251:       }
    252:     if (create) {
    253:       PetscCall(PetscOptionsInt("-ts_monitor_sp_swarm", "Display particles phase space from the DMSwarm", "TSMonitorSPSwarm", howoften, &howoften, NULL));
    254:       PetscCall(PetscOptionsInt("-ts_monitor_sp_swarm_retain", "Retain n points plotted to show trajectory, -1 for all points", "TSMonitorSPSwarm", retain, &retain, NULL));
    255:       PetscCall(PetscOptionsBool("-ts_monitor_sp_swarm_phase", "Plot in phase space rather than coordinate space", "TSMonitorSPSwarm", phase, &phase, NULL));
    256:       PetscCall(PetscOptionsBool("-ts_monitor_sp_swarm_multi_species", "Color particles by particle species", "TSMonitorSPSwarm", multispecies, &multispecies, NULL));
    257:       PetscCall(TSMonitorSPCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, retain, phase, multispecies, &ctx));
    258:       PetscCall(TSMonitorSet(ts, TSMonitorSPSwarmSolution, ctx, (PetscCtxDestroyFn *)TSMonitorSPCtxDestroy));
    259:     }
    260:   }
    261:   PetscCall(PetscOptionsName("-ts_monitor_hg_swarm", "Display particle histogram from the DMSwarm", "TSMonitorHGSwarm", &opt));
    262:   if (opt) {
    263:     TSMonitorHGCtx ctx;
    264:     PetscInt       howoften = 1, Ns = 1;
    265:     PetscBool      velocity = PETSC_FALSE, create = PETSC_TRUE;

    267:     for (PetscInt i = 0; i < ts->numbermonitors; ++i)
    268:       if (ts->monitor[i] == TSMonitorHGSwarmSolution) {
    269:         create = PETSC_FALSE;
    270:         break;
    271:       }
    272:     if (create) {
    273:       DM       sw, dm;
    274:       PetscInt Nc, Nb;

    276:       PetscCall(TSGetDM(ts, &sw));
    277:       PetscCall(DMSwarmGetCellDM(sw, &dm));
    278:       PetscCall(DMPlexGetHeightStratum(dm, 0, NULL, &Nc));
    279:       Nb = PetscMin(20, PetscMax(10, Nc));
    280:       PetscCall(PetscOptionsInt("-ts_monitor_hg_swarm", "Display particles histogram from the DMSwarm", "TSMonitorHGSwarm", howoften, &howoften, NULL));
    281:       PetscCall(PetscOptionsBool("-ts_monitor_hg_swarm_velocity", "Plot in velocity space rather than coordinate space", "TSMonitorHGSwarm", velocity, &velocity, NULL));
    282:       PetscCall(PetscOptionsInt("-ts_monitor_hg_swarm_species", "Number of species to histogram", "TSMonitorHGSwarm", Ns, &Ns, NULL));
    283:       PetscCall(PetscOptionsInt("-ts_monitor_hg_swarm_bins", "Number of histogram bins", "TSMonitorHGSwarm", Nb, &Nb, NULL));
    284:       PetscCall(TSMonitorHGCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, Ns, Nb, velocity, &ctx));
    285:       PetscCall(TSMonitorSet(ts, TSMonitorHGSwarmSolution, ctx, (PetscCtxDestroyFn *)TSMonitorHGCtxDestroy));
    286:     }
    287:   }
    288:   opt = PETSC_FALSE;
    289:   PetscCall(PetscOptionsName("-ts_monitor_draw_solution", "Monitor solution graphically", "TSMonitorDrawSolution", &opt));
    290:   if (opt) {
    291:     TSMonitorDrawCtx ctx;
    292:     PetscInt         howoften = 1;

    294:     PetscCall(PetscOptionsInt("-ts_monitor_draw_solution", "Monitor solution graphically", "TSMonitorDrawSolution", howoften, &howoften, NULL));
    295:     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, "Computed Solution", PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
    296:     PetscCall(TSMonitorSet(ts, TSMonitorDrawSolution, ctx, (PetscCtxDestroyFn *)TSMonitorDrawCtxDestroy));
    297:   }
    298:   opt = PETSC_FALSE;
    299:   PetscCall(PetscOptionsName("-ts_monitor_draw_solution_phase", "Monitor solution graphically", "TSMonitorDrawSolutionPhase", &opt));
    300:   if (opt) {
    301:     TSMonitorDrawCtx ctx;
    302:     PetscReal        bounds[4];
    303:     PetscInt         n = 4;
    304:     PetscDraw        draw;
    305:     PetscDrawAxis    axis;

    307:     PetscCall(PetscOptionsRealArray("-ts_monitor_draw_solution_phase", "Monitor solution graphically", "TSMonitorDrawSolutionPhase", bounds, &n, NULL));
    308:     PetscCheck(n == 4, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Must provide bounding box of phase field");
    309:     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, 1, &ctx));
    310:     PetscCall(PetscViewerDrawGetDraw(ctx->viewer, 0, &draw));
    311:     PetscCall(PetscViewerDrawGetDrawAxis(ctx->viewer, 0, &axis));
    312:     PetscCall(PetscDrawAxisSetLimits(axis, bounds[0], bounds[2], bounds[1], bounds[3]));
    313:     PetscCall(PetscDrawAxisSetLabels(axis, "Phase Diagram", "Variable 1", "Variable 2"));
    314:     PetscCall(TSMonitorSet(ts, TSMonitorDrawSolutionPhase, ctx, (PetscCtxDestroyFn *)TSMonitorDrawCtxDestroy));
    315:   }
    316:   opt = PETSC_FALSE;
    317:   PetscCall(PetscOptionsName("-ts_monitor_draw_error", "Monitor error graphically", "TSMonitorDrawError", &opt));
    318:   if (opt) {
    319:     TSMonitorDrawCtx ctx;
    320:     PetscInt         howoften = 1;

    322:     PetscCall(PetscOptionsInt("-ts_monitor_draw_error", "Monitor error graphically", "TSMonitorDrawError", howoften, &howoften, NULL));
    323:     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, "Error", PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
    324:     PetscCall(TSMonitorSet(ts, TSMonitorDrawError, ctx, (PetscCtxDestroyFn *)TSMonitorDrawCtxDestroy));
    325:   }
    326:   opt = PETSC_FALSE;
    327:   PetscCall(PetscOptionsName("-ts_monitor_draw_solution_function", "Monitor solution provided by TSMonitorSetSolutionFunction() graphically", "TSMonitorDrawSolutionFunction", &opt));
    328:   if (opt) {
    329:     TSMonitorDrawCtx ctx;
    330:     PetscInt         howoften = 1;

    332:     PetscCall(PetscOptionsInt("-ts_monitor_draw_solution_function", "Monitor solution provided by TSMonitorSetSolutionFunction() graphically", "TSMonitorDrawSolutionFunction", howoften, &howoften, NULL));
    333:     PetscCall(TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts), NULL, "Solution provided by user function", PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &ctx));
    334:     PetscCall(TSMonitorSet(ts, TSMonitorDrawSolutionFunction, ctx, (PetscCtxDestroyFn *)TSMonitorDrawCtxDestroy));
    335:   }

    337:   opt = PETSC_FALSE;
    338:   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));
    339:   if (flg) {
    340:     TSMonitorVTKCtx ctx;

    342:     PetscCall(TSMonitorSolutionVTKCtxCreate(monfilename, &ctx));
    343:     PetscCall(PetscOptionsInt("-ts_monitor_solution_vtk_interval", "Save every interval time step (-1 for last step only)", NULL, ctx->interval, &ctx->interval, NULL));
    344:     PetscCall(TSMonitorSet(ts, (PetscErrorCode (*)(TS, PetscInt, PetscReal, Vec, PetscCtx))TSMonitorSolutionVTK, ctx, (PetscCtxDestroyFn *)TSMonitorSolutionVTKDestroy));
    345:   }

    347:   PetscCall(PetscOptionsString("-ts_monitor_dmda_ray", "Display a ray of the solution", "None", "y=0", dir, sizeof(dir), &flg));
    348:   if (flg) {
    349:     TSMonitorDMDARayCtx *rayctx;
    350:     int                  ray = 0;
    351:     DMDirection          ddir;
    352:     DM                   da;
    353:     PetscMPIInt          rank;

    355:     PetscCheck(dir[1] == '=', PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Unknown ray %s", dir);
    356:     if (dir[0] == 'x') ddir = DM_X;
    357:     else if (dir[0] == 'y') ddir = DM_Y;
    358:     else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Unknown ray %s", dir);
    359:     sscanf(dir + 2, "%d", &ray);

    361:     PetscCall(PetscInfo(ts, "Displaying DMDA ray %c = %d\n", dir[0], ray));
    362:     PetscCall(PetscNew(&rayctx));
    363:     PetscCall(TSGetDM(ts, &da));
    364:     PetscCall(DMDAGetRay(da, ddir, ray, &rayctx->ray, &rayctx->scatter));
    365:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ts), &rank));
    366:     if (rank == 0) PetscCall(PetscViewerDrawOpen(PETSC_COMM_SELF, NULL, NULL, 0, 0, 600, 300, &rayctx->viewer));
    367:     rayctx->lgctx = NULL;
    368:     PetscCall(TSMonitorSet(ts, TSMonitorDMDARay, rayctx, TSMonitorDMDARayDestroy));
    369:   }
    370:   PetscCall(PetscOptionsString("-ts_monitor_lg_dmda_ray", "Display a ray of the solution", "None", "x=0", dir, sizeof(dir), &flg));
    371:   if (flg) {
    372:     TSMonitorDMDARayCtx *rayctx;
    373:     int                  ray = 0;
    374:     DMDirection          ddir;
    375:     DM                   da;
    376:     PetscInt             howoften = 1;

    378:     PetscCheck(dir[1] == '=', PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Malformed ray %s", dir);
    379:     if (dir[0] == 'x') ddir = DM_X;
    380:     else if (dir[0] == 'y') ddir = DM_Y;
    381:     else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Unknown ray direction %s", dir);
    382:     sscanf(dir + 2, "%d", &ray);

    384:     PetscCall(PetscInfo(ts, "Displaying LG DMDA ray %c = %d\n", dir[0], ray));
    385:     PetscCall(PetscNew(&rayctx));
    386:     PetscCall(TSGetDM(ts, &da));
    387:     PetscCall(DMDAGetRay(da, ddir, ray, &rayctx->ray, &rayctx->scatter));
    388:     PetscCall(TSMonitorLGCtxCreate(PETSC_COMM_SELF, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 600, 400, howoften, &rayctx->lgctx));
    389:     PetscCall(TSMonitorSet(ts, TSMonitorLGDMDARay, rayctx, TSMonitorDMDARayDestroy));
    390:   }

    392:   PetscCall(PetscOptionsName("-ts_monitor_envelope", "Monitor maximum and minimum value of each component of the solution", "TSMonitorEnvelope", &opt));
    393:   if (opt) {
    394:     TSMonitorEnvelopeCtx ctx;

    396:     PetscCall(TSMonitorEnvelopeCtxCreate(ts, &ctx));
    397:     PetscCall(TSMonitorSet(ts, TSMonitorEnvelope, ctx, (PetscCtxDestroyFn *)TSMonitorEnvelopeCtxDestroy));
    398:   }
    399:   flg = PETSC_FALSE;
    400:   PetscCall(PetscOptionsBool("-ts_monitor_cancel", "Remove all monitors", "TSMonitorCancel", flg, &flg, &opt));
    401:   if (opt && flg) PetscCall(TSMonitorCancel(ts));

    403:   flg = PETSC_FALSE;
    404:   PetscCall(PetscOptionsBool("-ts_fd_color", "Use finite differences with coloring to compute IJacobian", "TSComputeIJacobianDefaultColor", flg, &flg, NULL));
    405:   if (flg) {
    406:     DM dm;

    408:     PetscCall(TSGetDM(ts, &dm));
    409:     PetscCall(DMTSUnsetIJacobianContext_Internal(dm));
    410:     PetscCall(TSSetIJacobian(ts, NULL, NULL, TSComputeIJacobianDefaultColor, NULL));
    411:     PetscCall(PetscInfo(ts, "Setting default finite difference coloring Jacobian matrix\n"));
    412:   }

    414:   /* Handle specific TS options */
    415:   PetscTryTypeMethod(ts, setfromoptions, PetscOptionsObject);

    417:   /* Handle TSAdapt options */
    418:   PetscCall(TSGetAdapt(ts, &ts->adapt));
    419:   PetscCall(TSAdaptSetDefaultType(ts->adapt, ts->default_adapt_type));
    420:   PetscCall(TSAdaptSetFromOptions(ts->adapt, PetscOptionsObject));

    422:   /* TS trajectory must be set after TS, since it may use some TS options above */
    423:   tflg = ts->trajectory ? PETSC_TRUE : PETSC_FALSE;
    424:   PetscCall(PetscOptionsBool("-ts_save_trajectory", "Save the solution at each timestep", "TSSetSaveTrajectory", tflg, &tflg, NULL));
    425:   if (tflg) PetscCall(TSSetSaveTrajectory(ts));

    427:   PetscCall(TSAdjointSetFromOptions(ts, PetscOptionsObject));

    429:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    430:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)ts, PetscOptionsObject));
    431:   PetscOptionsEnd();

    433:   if (ts->trajectory) PetscCall(TSTrajectorySetFromOptions(ts->trajectory, ts));

    435:   /* why do we have to do this here and not during TSSetUp? */
    436:   PetscCall(TSGetSNES(ts, &ts->snes));
    437:   if (ts->problem_type == TS_LINEAR) {
    438:     PetscCall(PetscObjectTypeCompareAny((PetscObject)ts->snes, &flg, SNESKSPONLY, SNESKSPTRANSPOSEONLY, ""));
    439:     if (!flg) PetscCall(SNESSetType(ts->snes, SNESKSPONLY));
    440:   }
    441:   PetscCall(SNESSetFromOptions(ts->snes));
    442:   PetscFunctionReturn(PETSC_SUCCESS);
    443: }

    445: /*@
    446:   TSGetTrajectory - Gets the trajectory from a `TS` if it exists

    448:   Collective

    450:   Input Parameter:
    451: . ts - the `TS` context obtained from `TSCreate()`

    453:   Output Parameter:
    454: . tr - the `TSTrajectory` object, if it exists

    456:   Level: advanced

    458:   Note:
    459:   This routine should be called after all `TS` options have been set

    461: .seealso: [](ch_ts), `TS`, `TSTrajectory`, `TSAdjointSolve()`, `TSTrajectoryCreate()`
    462: @*/
    463: PetscErrorCode TSGetTrajectory(TS ts, TSTrajectory *tr)
    464: {
    465:   PetscFunctionBegin;
    467:   *tr = ts->trajectory;
    468:   PetscFunctionReturn(PETSC_SUCCESS);
    469: }

    471: /*@
    472:   TSSetSaveTrajectory - Causes the `TS` to save its solutions as it iterates forward in time in a `TSTrajectory` object

    474:   Collective

    476:   Input Parameter:
    477: . ts - the `TS` context obtained from `TSCreate()`

    479:   Options Database Keys:
    480: + -ts_save_trajectory                                         - saves the trajectory to a file
    481: - -ts_trajectory_type (basic|singlefile|memory|visualization) - set trajectory type

    483:   Level: intermediate

    485:   Notes:
    486:   This routine should be called after all `TS` options have been set

    488:   The `TSTRAJECTORYVISUALIZATION` files can be loaded into Python with $PETSC_DIR/lib/petsc/bin/PetscBinaryIOTrajectory.py and
    489:   MATLAB with $PETSC_DIR/share/petsc/matlab/PetscReadBinaryTrajectory.m

    491: .seealso: [](ch_ts), `TS`, `TSTrajectoryType`, `TSTrajectory`, `TSGetTrajectory()`, `TSAdjointSolve()`
    492: @*/
    493: PetscErrorCode TSSetSaveTrajectory(TS ts)
    494: {
    495:   PetscFunctionBegin;
    497:   if (!ts->trajectory) PetscCall(TSTrajectoryCreate(PetscObjectComm((PetscObject)ts), &ts->trajectory));
    498:   PetscFunctionReturn(PETSC_SUCCESS);
    499: }

    501: /*@
    502:   TSResetTrajectory - Destroys and recreates the internal `TSTrajectory` object

    504:   Collective

    506:   Input Parameter:
    507: . ts - the `TS` context obtained from `TSCreate()`

    509:   Level: intermediate

    511: .seealso: [](ch_ts), `TSTrajectory`, `TSGetTrajectory()`, `TSAdjointSolve()`, `TSRemoveTrajectory()`
    512: @*/
    513: PetscErrorCode TSResetTrajectory(TS ts)
    514: {
    515:   PetscFunctionBegin;
    517:   if (ts->trajectory) {
    518:     PetscCall(TSTrajectoryDestroy(&ts->trajectory));
    519:     PetscCall(TSTrajectoryCreate(PetscObjectComm((PetscObject)ts), &ts->trajectory));
    520:   }
    521:   PetscFunctionReturn(PETSC_SUCCESS);
    522: }

    524: /*@
    525:   TSRemoveTrajectory - Destroys and removes the internal `TSTrajectory` object from a `TS`

    527:   Collective

    529:   Input Parameter:
    530: . ts - the `TS` context obtained from `TSCreate()`

    532:   Level: intermediate

    534: .seealso: [](ch_ts), `TSTrajectory`, `TSResetTrajectory()`, `TSAdjointSolve()`
    535: @*/
    536: PetscErrorCode TSRemoveTrajectory(TS ts)
    537: {
    538:   PetscFunctionBegin;
    540:   PetscCall(TSTrajectoryDestroy(&ts->trajectory));
    541:   PetscFunctionReturn(PETSC_SUCCESS);
    542: }

    544: /*@
    545:   TSComputeRHSJacobian - Computes the Jacobian matrix that has been
    546:   set with `TSSetRHSJacobian()`.

    548:   Collective

    550:   Input Parameters:
    551: + ts - the `TS` context
    552: . t  - current timestep
    553: - U  - input vector

    555:   Output Parameters:
    556: + A - Jacobian matrix
    557: - B - optional matrix used to compute the preconditioner, often the same as `A`

    559:   Level: developer

    561:   Note:
    562:   Most users should not need to explicitly call this routine, as it
    563:   is used internally within the ODE integrators.

    565: .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `KSPSetOperators()`
    566: @*/
    567: PetscErrorCode TSComputeRHSJacobian(TS ts, PetscReal t, Vec U, Mat A, Mat B)
    568: {
    569:   PetscObjectState Ustate;
    570:   PetscObjectId    Uid;
    571:   DM               dm;
    572:   DMTS             tsdm;
    573:   TSRHSJacobianFn *rhsjacobianfunc;
    574:   void            *ctx;
    575:   TSRHSFunctionFn *rhsfunction;

    577:   PetscFunctionBegin;
    580:   PetscCheckSameComm(ts, 1, U, 3);
    581:   PetscCall(TSGetDM(ts, &dm));
    582:   PetscCall(DMGetDMTS(dm, &tsdm));
    583:   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
    584:   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobianfunc, &ctx));
    585:   PetscCall(PetscObjectStateGet((PetscObject)U, &Ustate));
    586:   PetscCall(PetscObjectGetId((PetscObject)U, &Uid));

    588:   if (ts->rhsjacobian.time == t && (ts->problem_type == TS_LINEAR || (ts->rhsjacobian.Xid == Uid && ts->rhsjacobian.Xstate == Ustate)) && (rhsfunction != TSComputeRHSFunctionLinear)) PetscFunctionReturn(PETSC_SUCCESS);

    590:   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);
    591:   if (rhsjacobianfunc) {
    592:     PetscCall(PetscLogEventBegin(TS_JacobianEval, U, ts, A, B));
    593:     PetscCallBack("TS callback Jacobian", (*rhsjacobianfunc)(ts, t, U, A, B, ctx));
    594:     ts->rhsjacs++;
    595:     PetscCall(PetscLogEventEnd(TS_JacobianEval, U, ts, A, B));
    596:   } else {
    597:     PetscCall(MatZeroEntries(A));
    598:     if (B && A != B) PetscCall(MatZeroEntries(B));
    599:   }
    600:   ts->rhsjacobian.time  = t;
    601:   ts->rhsjacobian.shift = 0;
    602:   ts->rhsjacobian.scale = 1.;
    603:   PetscCall(PetscObjectGetId((PetscObject)U, &ts->rhsjacobian.Xid));
    604:   PetscCall(PetscObjectStateGet((PetscObject)U, &ts->rhsjacobian.Xstate));
    605:   PetscFunctionReturn(PETSC_SUCCESS);
    606: }

    608: /*@
    609:   TSComputeRHSFunction - Evaluates the right-hand-side function for a `TS`

    611:   Collective

    613:   Input Parameters:
    614: + ts - the `TS` context
    615: . t  - current time
    616: - U  - state vector

    618:   Output Parameter:
    619: . y - right-hand side

    621:   Level: developer

    623:   Note:
    624:   Most users should not need to explicitly call this routine, as it
    625:   is used internally within the nonlinear solvers.

    627: .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSComputeIFunction()`
    628: @*/
    629: PetscErrorCode TSComputeRHSFunction(TS ts, PetscReal t, Vec U, Vec y)
    630: {
    631:   TSRHSFunctionFn *rhsfunction;
    632:   TSIFunctionFn   *ifunction;
    633:   void            *ctx;
    634:   DM               dm;

    636:   PetscFunctionBegin;
    640:   PetscCall(TSGetDM(ts, &dm));
    641:   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, &ctx));
    642:   PetscCall(DMTSGetIFunction(dm, &ifunction, NULL));

    644:   PetscCheck(rhsfunction || ifunction, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSFunction() and / or TSSetIFunction()");

    646:   if (rhsfunction) {
    647:     PetscCall(PetscLogEventBegin(TS_FunctionEval, U, ts, y, 0));
    648:     PetscCall(VecLockReadPush(U));
    649:     PetscCallBack("TS callback right-hand-side", (*rhsfunction)(ts, t, U, y, ctx));
    650:     PetscCall(VecLockReadPop(U));
    651:     ts->rhsfuncs++;
    652:     PetscCall(PetscLogEventEnd(TS_FunctionEval, U, ts, y, 0));
    653:   } else PetscCall(VecZeroEntries(y));
    654:   PetscFunctionReturn(PETSC_SUCCESS);
    655: }

    657: /*@
    658:   TSComputeSolutionFunction - Evaluates the solution function.

    660:   Collective

    662:   Input Parameters:
    663: + ts - the `TS` context
    664: - t  - current time

    666:   Output Parameter:
    667: . U - the solution

    669:   Level: developer

    671: .seealso: [](ch_ts), `TS`, `TSSetSolutionFunction()`, `TSSetRHSFunction()`, `TSComputeIFunction()`
    672: @*/
    673: PetscErrorCode TSComputeSolutionFunction(TS ts, PetscReal t, Vec U)
    674: {
    675:   TSSolutionFn *solutionfunction;
    676:   void         *ctx;
    677:   DM            dm;

    679:   PetscFunctionBegin;
    682:   PetscCall(TSGetDM(ts, &dm));
    683:   PetscCall(DMTSGetSolutionFunction(dm, &solutionfunction, &ctx));
    684:   if (solutionfunction) PetscCallBack("TS callback solution", (*solutionfunction)(ts, t, U, ctx));
    685:   PetscFunctionReturn(PETSC_SUCCESS);
    686: }
    687: /*@
    688:   TSComputeForcingFunction - Evaluates the forcing function.

    690:   Collective

    692:   Input Parameters:
    693: + ts - the `TS` context
    694: - t  - current time

    696:   Output Parameter:
    697: . U - the function value

    699:   Level: developer

    701: .seealso: [](ch_ts), `TS`, `TSSetSolutionFunction()`, `TSSetRHSFunction()`, `TSComputeIFunction()`
    702: @*/
    703: PetscErrorCode TSComputeForcingFunction(TS ts, PetscReal t, Vec U)
    704: {
    705:   void        *ctx;
    706:   DM           dm;
    707:   TSForcingFn *forcing;

    709:   PetscFunctionBegin;
    712:   PetscCall(TSGetDM(ts, &dm));
    713:   PetscCall(DMTSGetForcingFunction(dm, &forcing, &ctx));

    715:   if (forcing) PetscCallBack("TS callback forcing function", (*forcing)(ts, t, U, ctx));
    716:   PetscFunctionReturn(PETSC_SUCCESS);
    717: }

    719: PetscErrorCode TSGetRHSMats_Private(TS ts, Mat *Arhs, Mat *Brhs)
    720: {
    721:   Mat            A, B;
    722:   TSIJacobianFn *ijacobian;

    724:   PetscFunctionBegin;
    725:   if (Arhs) *Arhs = NULL;
    726:   if (Brhs) *Brhs = NULL;
    727:   PetscCall(TSGetIJacobian(ts, &A, &B, &ijacobian, NULL));
    728:   if (Arhs) {
    729:     if (!ts->Arhs) {
    730:       if (ijacobian) {
    731:         PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &ts->Arhs));
    732:         PetscCall(TSSetMatStructure(ts, SAME_NONZERO_PATTERN));
    733:       } else {
    734:         ts->Arhs = A;
    735:         PetscCall(PetscObjectReference((PetscObject)A));
    736:       }
    737:     } else {
    738:       PetscBool flg;
    739:       PetscCall(SNESGetUseMatrixFree(ts->snes, NULL, &flg));
    740:       /* Handle case where user provided only RHSJacobian and used -snes_mf_operator */
    741:       if (flg && !ijacobian && ts->Arhs == ts->Brhs) {
    742:         PetscCall(PetscObjectDereference((PetscObject)ts->Arhs));
    743:         ts->Arhs = A;
    744:         PetscCall(PetscObjectReference((PetscObject)A));
    745:       }
    746:     }
    747:     *Arhs = ts->Arhs;
    748:   }
    749:   if (Brhs) {
    750:     if (!ts->Brhs) {
    751:       if (A != B) {
    752:         if (ijacobian) {
    753:           PetscCall(MatDuplicate(B, MAT_DO_NOT_COPY_VALUES, &ts->Brhs));
    754:         } else {
    755:           ts->Brhs = B;
    756:           PetscCall(PetscObjectReference((PetscObject)B));
    757:         }
    758:       } else {
    759:         PetscCall(PetscObjectReference((PetscObject)ts->Arhs));
    760:         ts->Brhs = ts->Arhs;
    761:       }
    762:     }
    763:     *Brhs = ts->Brhs;
    764:   }
    765:   PetscFunctionReturn(PETSC_SUCCESS);
    766: }

    768: /*@
    769:   TSComputeIFunction - Evaluates the DAE residual written in the implicit form F(t,U,Udot)=0

    771:   Collective

    773:   Input Parameters:
    774: + ts   - the `TS` context
    775: . t    - current time
    776: . U    - state vector
    777: . Udot - time derivative of state vector
    778: - imex - flag indicates if the method is `TSARKIMEX` so that the RHSFunction should be kept separate

    780:   Output Parameter:
    781: . Y - right-hand side

    783:   Level: developer

    785:   Note:
    786:   Most users should not need to explicitly call this routine, as it
    787:   is used internally within the nonlinear solvers.

    789:   If the user did not write their equations in implicit form, this
    790:   function recasts them in implicit form.

    792: .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `TSComputeRHSFunction()`
    793: @*/
    794: PetscErrorCode TSComputeIFunction(TS ts, PetscReal t, Vec U, Vec Udot, Vec Y, PetscBool imex)
    795: {
    796:   TSIFunctionFn   *ifunction;
    797:   TSRHSFunctionFn *rhsfunction;
    798:   void            *ctx;
    799:   DM               dm;

    801:   PetscFunctionBegin;

    807:   PetscCall(TSGetDM(ts, &dm));
    808:   PetscCall(DMTSGetIFunction(dm, &ifunction, &ctx));
    809:   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));

    811:   PetscCheck(rhsfunction || ifunction, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSFunction() and / or TSSetIFunction()");

    813:   PetscCall(PetscLogEventBegin(TS_FunctionEval, U, ts, Udot, Y));
    814:   if (ifunction) {
    815:     PetscCallBack("TS callback implicit function", (*ifunction)(ts, t, U, Udot, Y, ctx));
    816:     ts->ifuncs++;
    817:   }
    818:   if (imex) {
    819:     if (!ifunction) PetscCall(VecCopy(Udot, Y));
    820:   } else if (rhsfunction) {
    821:     if (ifunction) {
    822:       Vec Frhs;

    824:       PetscCall(DMGetGlobalVector(dm, &Frhs));
    825:       PetscCall(TSComputeRHSFunction(ts, t, U, Frhs));
    826:       PetscCall(VecAXPY(Y, -1, Frhs));
    827:       PetscCall(DMRestoreGlobalVector(dm, &Frhs));
    828:     } else {
    829:       PetscCall(TSComputeRHSFunction(ts, t, U, Y));
    830:       PetscCall(VecAYPX(Y, -1, Udot));
    831:     }
    832:   }
    833:   PetscCall(PetscLogEventEnd(TS_FunctionEval, U, ts, Udot, Y));
    834:   PetscFunctionReturn(PETSC_SUCCESS);
    835: }

    837: /*
    838:    TSRecoverRHSJacobian - Recover the Jacobian matrix so that one can call `TSComputeRHSJacobian()` on it.

    840:    Note:
    841:    This routine is needed when one switches from `TSComputeIJacobian()` to `TSComputeRHSJacobian()` because the Jacobian matrix may be shifted or scaled in `TSComputeIJacobian()`.

    843: */
    844: static PetscErrorCode TSRecoverRHSJacobian(TS ts, Mat A, Mat B)
    845: {
    846:   PetscFunctionBegin;
    848:   PetscCheck(A == ts->Arhs, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Invalid Amat");
    849:   PetscCheck(B == ts->Brhs, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Invalid Bmat");

    851:   if (ts->rhsjacobian.shift) PetscCall(MatShift(A, -ts->rhsjacobian.shift));
    852:   if (ts->rhsjacobian.scale == -1.) PetscCall(MatScale(A, -1));
    853:   if (B && B == ts->Brhs && A != B) {
    854:     if (ts->rhsjacobian.shift) PetscCall(MatShift(B, -ts->rhsjacobian.shift));
    855:     if (ts->rhsjacobian.scale == -1.) PetscCall(MatScale(B, -1));
    856:   }
    857:   ts->rhsjacobian.shift = 0;
    858:   ts->rhsjacobian.scale = 1.;
    859:   PetscFunctionReturn(PETSC_SUCCESS);
    860: }

    862: /*@
    863:   TSComputeIJacobian - Evaluates the Jacobian of the DAE

    865:   Collective

    867:   Input Parameters:
    868: + ts    - the `TS` context
    869: . t     - current timestep
    870: . U     - state vector
    871: . Udot  - time derivative of state vector
    872: . shift - shift to apply, see note below
    873: - imex  - flag indicates if the method is `TSARKIMEX` so that the RHSJacobian should be kept separate

    875:   Output Parameters:
    876: + A - Jacobian matrix
    877: - B - matrix from which the preconditioner is constructed; often the same as `A`

    879:   Level: developer

    881:   Notes:
    882:   If $ F(t,U,\dot{U})=0 $ is the DAE, the required Jacobian is
    883: .vb
    884:    dF/dU + shift*dF/dUdot
    885: .ve
    886:   Most users should not need to explicitly call this routine, as it
    887:   is used internally within the nonlinear solvers.

    889: .seealso: [](ch_ts), `TS`, `TSSetIJacobian()`
    890: @*/
    891: PetscErrorCode TSComputeIJacobian(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat A, Mat B, PetscBool imex)
    892: {
    893:   TSIJacobianFn   *ijacobian;
    894:   TSRHSJacobianFn *rhsjacobian;
    895:   DM               dm;
    896:   void            *ctx;

    898:   PetscFunctionBegin;

    905:   PetscCall(TSGetDM(ts, &dm));
    906:   PetscCall(DMTSGetIJacobian(dm, &ijacobian, &ctx));
    907:   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobian, NULL));

    909:   PetscCheck(rhsjacobian || ijacobian, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSJacobian() and / or TSSetIJacobian()");

    911:   PetscCall(PetscLogEventBegin(TS_JacobianEval, U, ts, A, B));
    912:   if (ijacobian) {
    913:     PetscCallBack("TS callback implicit Jacobian", (*ijacobian)(ts, t, U, Udot, shift, A, B, ctx));
    914:     ts->ijacs++;
    915:   }
    916:   if (imex) {
    917:     if (!ijacobian) { /* system was written as Udot = G(t,U) */
    918:       PetscBool assembled;
    919:       if (rhsjacobian) {
    920:         Mat Arhs = NULL;
    921:         PetscCall(TSGetRHSMats_Private(ts, &Arhs, NULL));
    922:         if (A == Arhs) {
    923:           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 */
    924:           ts->rhsjacobian.time = PETSC_MIN_REAL;
    925:         }
    926:       }
    927:       PetscCall(MatZeroEntries(A));
    928:       PetscCall(MatAssembled(A, &assembled));
    929:       if (!assembled) {
    930:         PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
    931:         PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
    932:       }
    933:       PetscCall(MatShift(A, shift));
    934:       if (A != B) {
    935:         PetscCall(MatZeroEntries(B));
    936:         PetscCall(MatAssembled(B, &assembled));
    937:         if (!assembled) {
    938:           PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
    939:           PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
    940:         }
    941:         PetscCall(MatShift(B, shift));
    942:       }
    943:     }
    944:   } else {
    945:     Mat Arhs = NULL, Brhs = NULL;

    947:     /* RHSJacobian needs to be converted to part of IJacobian if exists */
    948:     if (rhsjacobian) PetscCall(TSGetRHSMats_Private(ts, &Arhs, &Brhs));
    949:     if (Arhs == A) { /* No IJacobian matrix, so we only have the RHS matrix */
    950:       PetscObjectState Ustate;
    951:       PetscObjectId    Uid;
    952:       TSRHSFunctionFn *rhsfunction;

    954:       PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
    955:       PetscCall(PetscObjectStateGet((PetscObject)U, &Ustate));
    956:       PetscCall(PetscObjectGetId((PetscObject)U, &Uid));
    957:       if ((rhsjacobian == TSComputeRHSJacobianConstant || (ts->rhsjacobian.time == t && (ts->problem_type == TS_LINEAR || (ts->rhsjacobian.Xid == Uid && ts->rhsjacobian.Xstate == Ustate)) && rhsfunction != TSComputeRHSFunctionLinear)) &&
    958:           ts->rhsjacobian.scale == -1.) {                      /* No need to recompute RHSJacobian */
    959:         PetscCall(MatShift(A, shift - ts->rhsjacobian.shift)); /* revert the old shift and add the new shift with a single call to MatShift */
    960:         if (A != B) PetscCall(MatShift(B, shift - ts->rhsjacobian.shift));
    961:       } else {
    962:         PetscBool flg;

    964:         if (ts->rhsjacobian.reuse) { /* Undo the damage */
    965:           /* MatScale has a short path for this case.
    966:              However, this code path is taken the first time TSComputeRHSJacobian is called
    967:              and the matrices have not been assembled yet */
    968:           PetscCall(TSRecoverRHSJacobian(ts, A, B));
    969:         }
    970:         PetscCall(TSComputeRHSJacobian(ts, t, U, A, B));
    971:         PetscCall(SNESGetUseMatrixFree(ts->snes, NULL, &flg));
    972:         /* since -snes_mf_operator uses the full SNES function it does not need to be shifted or scaled here */
    973:         if (!flg) {
    974:           PetscCall(MatScale(A, -1));
    975:           PetscCall(MatShift(A, shift));
    976:         }
    977:         if (A != B) {
    978:           PetscCall(MatScale(B, -1));
    979:           PetscCall(MatShift(B, shift));
    980:         }
    981:       }
    982:       ts->rhsjacobian.scale = -1;
    983:       ts->rhsjacobian.shift = shift;
    984:     } else if (Arhs) {  /* Both IJacobian and RHSJacobian */
    985:       if (!ijacobian) { /* No IJacobian provided, but we have a separate RHS matrix */
    986:         PetscCall(MatZeroEntries(A));
    987:         PetscCall(MatShift(A, shift));
    988:         if (A != B) {
    989:           PetscCall(MatZeroEntries(B));
    990:           PetscCall(MatShift(B, shift));
    991:         }
    992:       }
    993:       PetscCall(TSComputeRHSJacobian(ts, t, U, Arhs, Brhs));
    994:       PetscCall(MatAXPY(A, -1, Arhs, ts->axpy_pattern));
    995:       if (A != B) PetscCall(MatAXPY(B, -1, Brhs, ts->axpy_pattern));
    996:     }
    997:   }
    998:   PetscCall(PetscLogEventEnd(TS_JacobianEval, U, ts, A, B));
    999:   PetscFunctionReturn(PETSC_SUCCESS);
    1000: }

    1002: /*@C
    1003:   TSSetRHSFunction - Sets the routine for evaluating the function,
    1004:   where U_t = G(t,u).

    1006:   Logically Collective

    1008:   Input Parameters:
    1009: + ts  - the `TS` context obtained from `TSCreate()`
    1010: . r   - vector to put the computed right-hand side (or `NULL` to have it created)
    1011: . f   - routine for evaluating the right-hand-side function
    1012: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)

    1014:   Level: beginner

    1016:   Note:
    1017:   You must call this function or `TSSetIFunction()` to define your ODE. You cannot use this function when solving a DAE.

    1019: .seealso: [](ch_ts), `TS`, `TSRHSFunctionFn`, `TSSetRHSJacobian()`, `TSSetIJacobian()`, `TSSetIFunction()`
    1020: @*/
    1021: PetscErrorCode TSSetRHSFunction(TS ts, Vec r, TSRHSFunctionFn *f, PetscCtx ctx)
    1022: {
    1023:   SNES snes;
    1024:   Vec  ralloc = NULL;
    1025:   DM   dm;

    1027:   PetscFunctionBegin;

    1031:   PetscCall(TSGetDM(ts, &dm));
    1032:   PetscCall(DMTSSetRHSFunction(dm, f, ctx));
    1033:   PetscCall(TSGetSNES(ts, &snes));
    1034:   if (!r && !ts->dm && ts->vec_sol) {
    1035:     PetscCall(VecDuplicate(ts->vec_sol, &ralloc));
    1036:     r = ralloc;
    1037:   }
    1038:   PetscCall(SNESSetFunction(snes, r, SNESTSFormFunction, ts));
    1039:   PetscCall(VecDestroy(&ralloc));
    1040:   PetscFunctionReturn(PETSC_SUCCESS);
    1041: }

    1043: /*@C
    1044:   TSSetSolutionFunction - Provide a function that computes the solution of the ODE or DAE

    1046:   Logically Collective

    1048:   Input Parameters:
    1049: + ts  - the `TS` context obtained from `TSCreate()`
    1050: . f   - routine for evaluating the solution
    1051: - ctx - [optional] user-defined context for private data for the
    1052:           function evaluation routine (may be `NULL`)

    1054:   Options Database Keys:
    1055: + -ts_monitor_lg_error   - create a graphical monitor of error history, requires user to have provided `TSSetSolutionFunction()`
    1056: - -ts_monitor_draw_error - Monitor error graphically, requires user to have provided `TSSetSolutionFunction()`

    1058:   Level: intermediate

    1060:   Notes:
    1061:   This routine is used for testing accuracy of time integration schemes when you already know the solution.
    1062:   If analytic solutions are not known for your system, consider using the Method of Manufactured Solutions to
    1063:   create closed-form solutions with non-physical forcing terms.

    1065:   For low-dimensional problems solved in serial, such as small discrete systems, `TSMonitorLGError()` can be used to monitor the error history.

    1067: .seealso: [](ch_ts), `TS`, `TSSolutionFn`, `TSSetRHSJacobian()`, `TSSetIJacobian()`, `TSComputeSolutionFunction()`, `TSSetForcingFunction()`, `TSSetSolution()`, `TSGetSolution()`, `TSMonitorLGError()`, `TSMonitorDrawError()`
    1068: @*/
    1069: PetscErrorCode TSSetSolutionFunction(TS ts, TSSolutionFn *f, PetscCtx ctx)
    1070: {
    1071:   DM dm;

    1073:   PetscFunctionBegin;
    1075:   PetscCall(TSGetDM(ts, &dm));
    1076:   PetscCall(DMTSSetSolutionFunction(dm, f, ctx));
    1077:   PetscFunctionReturn(PETSC_SUCCESS);
    1078: }

    1080: /*@C
    1081:   TSSetForcingFunction - Provide a function that computes a forcing term for a ODE or PDE

    1083:   Logically Collective

    1085:   Input Parameters:
    1086: + ts   - the `TS` context obtained from `TSCreate()`
    1087: . func - routine for evaluating the forcing function
    1088: - ctx  - [optional] user-defined context for private data for the function evaluation routine
    1089:          (may be `NULL`)

    1091:   Level: intermediate

    1093:   Notes:
    1094:   This routine is useful for testing accuracy of time integration schemes when using the Method of Manufactured Solutions to
    1095:   create closed-form solutions with a non-physical forcing term. It allows you to use the Method of Manufactored Solution without directly editing the
    1096:   definition of the problem you are solving and hence possibly introducing bugs.

    1098:   This replaces the ODE F(u,u_t,t) = 0 the `TS` is solving with F(u,u_t,t) - func(t) = 0

    1100:   This forcing function does not depend on the solution to the equations, it can only depend on spatial location, time, and possibly parameters, the
    1101:   parameters can be passed in the ctx variable.

    1103:   For low-dimensional problems solved in serial, such as small discrete systems, `TSMonitorLGError()` can be used to monitor the error history.

    1105: .seealso: [](ch_ts), `TS`, `TSForcingFn`, `TSSetRHSJacobian()`, `TSSetIJacobian()`,
    1106: `TSComputeSolutionFunction()`, `TSSetSolutionFunction()`
    1107: @*/
    1108: PetscErrorCode TSSetForcingFunction(TS ts, TSForcingFn *func, PetscCtx ctx)
    1109: {
    1110:   DM dm;

    1112:   PetscFunctionBegin;
    1114:   PetscCall(TSGetDM(ts, &dm));
    1115:   PetscCall(DMTSSetForcingFunction(dm, func, ctx));
    1116:   PetscFunctionReturn(PETSC_SUCCESS);
    1117: }

    1119: /*@C
    1120:   TSSetRHSJacobian - Sets the function to compute the Jacobian of G,
    1121:   where U_t = G(U,t), as well as the location to store the matrix.

    1123:   Logically Collective

    1125:   Input Parameters:
    1126: + ts   - the `TS` context obtained from `TSCreate()`
    1127: . Amat - (approximate) location to store Jacobian matrix entries computed by `f`
    1128: . Pmat - matrix from which preconditioner is to be constructed (usually the same as `Amat`)
    1129: . f    - the Jacobian evaluation routine
    1130: - ctx  - [optional] user-defined context for private data for the Jacobian evaluation routine (may be `NULL`)

    1132:   Level: beginner

    1134:   Notes:
    1135:   You must set all the diagonal entries of the matrices, if they are zero you must still set them with a zero value

    1137:   The `TS` solver may modify the nonzero structure and the entries of the matrices `Amat` and `Pmat` between the calls to `f()`
    1138:   You should not assume the values are the same in the next call to f() as you set them in the previous call.

    1140: .seealso: [](ch_ts), `TS`, `TSRHSJacobianFn`, `SNESComputeJacobianDefaultColor()`,
    1141: `TSSetRHSFunction()`, `TSRHSJacobianSetReuse()`, `TSSetIJacobian()`, `TSRHSFunctionFn`, `TSIFunctionFn`
    1142: @*/
    1143: PetscErrorCode TSSetRHSJacobian(TS ts, Mat Amat, Mat Pmat, TSRHSJacobianFn *f, PetscCtx ctx)
    1144: {
    1145:   SNES           snes;
    1146:   DM             dm;
    1147:   TSIJacobianFn *ijacobian;

    1149:   PetscFunctionBegin;
    1153:   if (Amat) PetscCheckSameComm(ts, 1, Amat, 2);
    1154:   if (Pmat) PetscCheckSameComm(ts, 1, Pmat, 3);

    1156:   PetscCall(TSGetDM(ts, &dm));
    1157:   PetscCall(DMTSSetRHSJacobian(dm, f, ctx));
    1158:   PetscCall(DMTSGetIJacobian(dm, &ijacobian, NULL));
    1159:   PetscCall(TSGetSNES(ts, &snes));
    1160:   if (!ijacobian) PetscCall(SNESSetJacobian(snes, Amat, Pmat, SNESTSFormJacobian, ts));
    1161:   if (Amat) {
    1162:     PetscCall(PetscObjectReference((PetscObject)Amat));
    1163:     PetscCall(MatDestroy(&ts->Arhs));
    1164:     ts->Arhs = Amat;
    1165:   }
    1166:   if (Pmat) {
    1167:     PetscCall(PetscObjectReference((PetscObject)Pmat));
    1168:     PetscCall(MatDestroy(&ts->Brhs));
    1169:     ts->Brhs = Pmat;
    1170:   }
    1171:   PetscFunctionReturn(PETSC_SUCCESS);
    1172: }

    1174: /*@C
    1175:   TSSetIFunction - Set the function to compute F(t,U,U_t) where F() = 0 is the DAE to be solved.

    1177:   Logically Collective

    1179:   Input Parameters:
    1180: + ts  - the `TS` context obtained from `TSCreate()`
    1181: . r   - vector to hold the residual (or `NULL` to have it created internally)
    1182: . f   - the function evaluation routine
    1183: - ctx - user-defined context for private data for the function evaluation routine (may be `NULL`)

    1185:   Level: beginner

    1187:   Note:
    1188:   The user MUST call either this routine or `TSSetRHSFunction()` to define the ODE.  When solving DAEs you must use this function.

    1190: .seealso: [](ch_ts), `TS`, `TSIFunctionFn`, `TSSetRHSJacobian()`, `TSSetRHSFunction()`,
    1191: `TSSetIJacobian()`
    1192: @*/
    1193: PetscErrorCode TSSetIFunction(TS ts, Vec r, TSIFunctionFn *f, PetscCtx ctx)
    1194: {
    1195:   SNES snes;
    1196:   Vec  ralloc = NULL;
    1197:   DM   dm;

    1199:   PetscFunctionBegin;

    1203:   PetscCall(TSGetDM(ts, &dm));
    1204:   PetscCall(DMTSSetIFunction(dm, f, ctx));

    1206:   PetscCall(TSGetSNES(ts, &snes));
    1207:   if (!r && !ts->dm && ts->vec_sol) {
    1208:     PetscCall(VecDuplicate(ts->vec_sol, &ralloc));
    1209:     r = ralloc;
    1210:   }
    1211:   PetscCall(SNESSetFunction(snes, r, SNESTSFormFunction, ts));
    1212:   PetscCall(VecDestroy(&ralloc));
    1213:   PetscFunctionReturn(PETSC_SUCCESS);
    1214: }

    1216: /*@C
    1217:   TSGetIFunction - Returns the vector where the implicit residual is stored and the function/context to compute it.

    1219:   Not Collective

    1221:   Input Parameter:
    1222: . ts - the `TS` context

    1224:   Output Parameters:
    1225: + r    - vector to hold residual (or `NULL`)
    1226: . func - the function to compute residual (or `NULL`)
    1227: - ctx  - the function context (or `NULL`)

    1229:   Level: advanced

    1231: .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `SNESGetFunction()`
    1232: @*/
    1233: PetscErrorCode TSGetIFunction(TS ts, Vec *r, TSIFunctionFn **func, PetscCtxRt ctx)
    1234: {
    1235:   SNES snes;
    1236:   DM   dm;

    1238:   PetscFunctionBegin;
    1240:   PetscCall(TSGetSNES(ts, &snes));
    1241:   PetscCall(SNESGetFunction(snes, r, NULL, NULL));
    1242:   PetscCall(TSGetDM(ts, &dm));
    1243:   PetscCall(DMTSGetIFunction(dm, func, ctx));
    1244:   PetscFunctionReturn(PETSC_SUCCESS);
    1245: }

    1247: /*@C
    1248:   TSGetRHSFunction - Returns the vector where the right-hand side is stored and the function/context to compute it.

    1250:   Not Collective

    1252:   Input Parameter:
    1253: . ts - the `TS` context

    1255:   Output Parameters:
    1256: + r    - vector to hold computed right-hand side (or `NULL`)
    1257: . func - the function to compute right-hand side (or `NULL`)
    1258: - ctx  - the function context (or `NULL`)

    1260:   Level: advanced

    1262: .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `SNESGetFunction()`
    1263: @*/
    1264: PetscErrorCode TSGetRHSFunction(TS ts, Vec *r, TSRHSFunctionFn **func, PetscCtxRt ctx)
    1265: {
    1266:   SNES snes;
    1267:   DM   dm;

    1269:   PetscFunctionBegin;
    1271:   PetscCall(TSGetSNES(ts, &snes));
    1272:   PetscCall(SNESGetFunction(snes, r, NULL, NULL));
    1273:   PetscCall(TSGetDM(ts, &dm));
    1274:   PetscCall(DMTSGetRHSFunction(dm, func, ctx));
    1275:   PetscFunctionReturn(PETSC_SUCCESS);
    1276: }

    1278: /*@C
    1279:   TSSetIJacobian - Set the function to compute the matrix dF/dU + a*dF/dU_t where F(t,U,U_t) is the function
    1280:   provided with `TSSetIFunction()`.

    1282:   Logically Collective

    1284:   Input Parameters:
    1285: + ts   - the `TS` context obtained from `TSCreate()`
    1286: . Amat - (approximate) matrix to store Jacobian entries computed by `f`
    1287: . Pmat - matrix used to compute preconditioner (usually the same as `Amat`)
    1288: . f    - the Jacobian evaluation routine
    1289: - ctx  - user-defined context for private data for the Jacobian evaluation routine (may be `NULL`)

    1291:   Level: beginner

    1293:   Notes:
    1294:   The matrices `Amat` and `Pmat` are exactly the matrices that are used by `SNES` for the nonlinear solve.

    1296:   If you know the operator Amat has a null space you can use `MatSetNullSpace()` and `MatSetTransposeNullSpace()` to supply the null
    1297:   space to `Amat` and the `KSP` solvers will automatically use that null space as needed during the solution process.

    1299:   The matrix dF/dU + a*dF/dU_t you provide turns out to be
    1300:   the Jacobian of F(t,U,W+a*U) where F(t,U,U_t) = 0 is the DAE to be solved.
    1301:   The time integrator internally approximates U_t by W+a*U where the positive "shift"
    1302:   a and vector W depend on the integration method, step size, and past states. For example with
    1303:   the backward Euler method a = 1/dt and W = -a*U(previous timestep) so
    1304:   W + a*U = a*(U - U(previous timestep)) = (U - U(previous timestep))/dt

    1306:   You must set all the diagonal entries of the matrices, if they are zero you must still set them with a zero value

    1308:   The TS solver may modify the nonzero structure and the entries of the matrices `Amat` and `Pmat` between the calls to `f`
    1309:   You should not assume the values are the same in the next call to `f` as you set them in the previous call.

    1311:   In case `TSSetRHSJacobian()` is also used in conjunction with a fully-implicit solver,
    1312:   multilevel linear solvers, e.g. `PCMG`, will likely not work due to the way `TS` handles rhs matrices.

    1314: .seealso: [](ch_ts), `TS`, `TSIJacobianFn`, `TSSetIFunction()`, `TSSetRHSJacobian()`,
    1315: `SNESComputeJacobianDefaultColor()`, `SNESComputeJacobianDefault()`, `TSSetRHSFunction()`
    1316: @*/
    1317: PetscErrorCode TSSetIJacobian(TS ts, Mat Amat, Mat Pmat, TSIJacobianFn *f, PetscCtx ctx)
    1318: {
    1319:   SNES snes;
    1320:   DM   dm;

    1322:   PetscFunctionBegin;
    1326:   if (Amat) PetscCheckSameComm(ts, 1, Amat, 2);
    1327:   if (Pmat) PetscCheckSameComm(ts, 1, Pmat, 3);

    1329:   PetscCall(TSGetDM(ts, &dm));
    1330:   PetscCall(DMTSSetIJacobian(dm, f, ctx));

    1332:   PetscCall(TSGetSNES(ts, &snes));
    1333:   PetscCall(SNESSetJacobian(snes, Amat, Pmat, SNESTSFormJacobian, ts));
    1334:   PetscFunctionReturn(PETSC_SUCCESS);
    1335: }

    1337: /*@
    1338:   TSRHSJacobianSetReuse - restore the RHS Jacobian before calling the user-provided `TSRHSJacobianFn` function again

    1340:   Logically Collective

    1342:   Input Parameters:
    1343: + ts    - `TS` context obtained from `TSCreate()`
    1344: - reuse - `PETSC_TRUE` if the RHS Jacobian

    1346:   Level: intermediate

    1348:   Notes:
    1349:   Without this flag, `TS` will change the sign and shift the RHS Jacobian for a
    1350:   finite-time-step implicit solve, in which case the user function will need to recompute the
    1351:   entire Jacobian.  The `reuse `flag must be set if the evaluation function assumes that the
    1352:   matrix entries have not been changed by the `TS`.

    1354: .seealso: [](ch_ts), `TS`, `TSSetRHSJacobian()`, `TSComputeRHSJacobianConstant()`
    1355: @*/
    1356: PetscErrorCode TSRHSJacobianSetReuse(TS ts, PetscBool reuse)
    1357: {
    1358:   PetscFunctionBegin;
    1359:   ts->rhsjacobian.reuse = reuse;
    1360:   PetscFunctionReturn(PETSC_SUCCESS);
    1361: }

    1363: /*@C
    1364:   TSSetI2Function - Set the function to compute F(t,U,U_t,U_tt) where F = 0 is the DAE to be solved.

    1366:   Logically Collective

    1368:   Input Parameters:
    1369: + ts  - the `TS` context obtained from `TSCreate()`
    1370: . F   - vector to hold the residual (or `NULL` to have it created internally)
    1371: . fun - the function evaluation routine
    1372: - ctx - user-defined context for private data for the function evaluation routine (may be `NULL`)

    1374:   Level: beginner

    1376: .seealso: [](ch_ts), `TS`, `TSI2FunctionFn`, `TSSetI2Jacobian()`, `TSSetIFunction()`,
    1377: `TSCreate()`, `TSSetRHSFunction()`
    1378: @*/
    1379: PetscErrorCode TSSetI2Function(TS ts, Vec F, TSI2FunctionFn *fun, PetscCtx ctx)
    1380: {
    1381:   DM dm;

    1383:   PetscFunctionBegin;
    1386:   PetscCall(TSSetIFunction(ts, F, NULL, NULL));
    1387:   PetscCall(TSGetDM(ts, &dm));
    1388:   PetscCall(DMTSSetI2Function(dm, fun, ctx));
    1389:   PetscFunctionReturn(PETSC_SUCCESS);
    1390: }

    1392: /*@C
    1393:   TSGetI2Function - Returns the vector where the implicit residual is stored and the function/context to compute it.

    1395:   Not Collective

    1397:   Input Parameter:
    1398: . ts - the `TS` context

    1400:   Output Parameters:
    1401: + r   - vector to hold residual (or `NULL`)
    1402: . fun - the function to compute residual (or `NULL`)
    1403: - ctx - the function context (or `NULL`)

    1405:   Level: advanced

    1407: .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `SNESGetFunction()`, `TSCreate()`
    1408: @*/
    1409: PetscErrorCode TSGetI2Function(TS ts, Vec *r, TSI2FunctionFn **fun, PetscCtxRt ctx)
    1410: {
    1411:   SNES snes;
    1412:   DM   dm;

    1414:   PetscFunctionBegin;
    1416:   PetscCall(TSGetSNES(ts, &snes));
    1417:   PetscCall(SNESGetFunction(snes, r, NULL, NULL));
    1418:   PetscCall(TSGetDM(ts, &dm));
    1419:   PetscCall(DMTSGetI2Function(dm, fun, ctx));
    1420:   PetscFunctionReturn(PETSC_SUCCESS);
    1421: }

    1423: /*@C
    1424:   TSSetI2Jacobian - Set the function to compute the matrix dF/dU + v*dF/dU_t  + a*dF/dU_tt
    1425:   where F(t,U,U_t,U_tt) is the function you provided with `TSSetI2Function()`.

    1427:   Logically Collective

    1429:   Input Parameters:
    1430: + ts  - the `TS` context obtained from `TSCreate()`
    1431: . J   - matrix to hold the Jacobian values
    1432: . P   - matrix for constructing the preconditioner (may be same as `J`)
    1433: . jac - the Jacobian evaluation routine, see `TSI2JacobianFn` for the calling sequence
    1434: - ctx - user-defined context for private data for the Jacobian evaluation routine (may be `NULL`)

    1436:   Level: beginner

    1438:   Notes:
    1439:   The matrices `J` and `P` are exactly the matrices that are used by `SNES` for the nonlinear solve.

    1441:   The matrix dF/dU + v*dF/dU_t + a*dF/dU_tt you provide turns out to be
    1442:   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.
    1443:   The time integrator internally approximates U_t by W+v*U and U_tt by W'+a*U  where the positive "shift"
    1444:   parameters 'v' and 'a' and vectors W, W' depend on the integration method, step size, and past states.

    1446: .seealso: [](ch_ts), `TS`, `TSI2JacobianFn`, `TSSetI2Function()`, `TSGetI2Jacobian()`
    1447: @*/
    1448: PetscErrorCode TSSetI2Jacobian(TS ts, Mat J, Mat P, TSI2JacobianFn *jac, PetscCtx ctx)
    1449: {
    1450:   DM dm;

    1452:   PetscFunctionBegin;
    1456:   PetscCall(TSSetIJacobian(ts, J, P, NULL, NULL));
    1457:   PetscCall(TSGetDM(ts, &dm));
    1458:   PetscCall(DMTSSetI2Jacobian(dm, jac, ctx));
    1459:   PetscFunctionReturn(PETSC_SUCCESS);
    1460: }

    1462: /*@C
    1463:   TSGetI2Jacobian - Returns the implicit Jacobian at the present timestep.

    1465:   Not Collective, but parallel objects are returned if `TS` is parallel

    1467:   Input Parameter:
    1468: . ts - The `TS` context obtained from `TSCreate()`

    1470:   Output Parameters:
    1471: + J   - The (approximate) Jacobian of F(t,U,U_t,U_tt)
    1472: . P   - The matrix from which the preconditioner is constructed, often the same as `J`
    1473: . jac - The function to compute the Jacobian matrices
    1474: - ctx - User-defined context for Jacobian evaluation routine

    1476:   Level: advanced

    1478:   Note:
    1479:   You can pass in `NULL` for any return argument you do not need.

    1481: .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetMatrices()`, `TSGetTime()`, `TSGetStepNumber()`, `TSSetI2Jacobian()`, `TSGetI2Function()`, `TSCreate()`
    1482: @*/
    1483: PetscErrorCode TSGetI2Jacobian(TS ts, Mat *J, Mat *P, TSI2JacobianFn **jac, PetscCtxRt ctx)
    1484: {
    1485:   SNES snes;
    1486:   DM   dm;

    1488:   PetscFunctionBegin;
    1489:   PetscCall(TSGetSNES(ts, &snes));
    1490:   PetscCall(SNESSetUpMatrices(snes));
    1491:   PetscCall(SNESGetJacobian(snes, J, P, NULL, NULL));
    1492:   PetscCall(TSGetDM(ts, &dm));
    1493:   PetscCall(DMTSGetI2Jacobian(dm, jac, ctx));
    1494:   PetscFunctionReturn(PETSC_SUCCESS);
    1495: }

    1497: /*@
    1498:   TSComputeI2Function - Evaluates the DAE residual written in implicit form F(t,U,U_t,U_tt) = 0

    1500:   Collective

    1502:   Input Parameters:
    1503: + ts - the `TS` context
    1504: . t  - current time
    1505: . U  - state vector
    1506: . V  - time derivative of state vector (U_t)
    1507: - A  - second time derivative of state vector (U_tt)

    1509:   Output Parameter:
    1510: . F - the residual vector

    1512:   Level: developer

    1514:   Note:
    1515:   Most users should not need to explicitly call this routine, as it
    1516:   is used internally within the nonlinear solvers.

    1518: .seealso: [](ch_ts), `TS`, `TSSetI2Function()`, `TSGetI2Function()`
    1519: @*/
    1520: PetscErrorCode TSComputeI2Function(TS ts, PetscReal t, Vec U, Vec V, Vec A, Vec F)
    1521: {
    1522:   DM               dm;
    1523:   TSI2FunctionFn  *I2Function;
    1524:   void            *ctx;
    1525:   TSRHSFunctionFn *rhsfunction;

    1527:   PetscFunctionBegin;

    1534:   PetscCall(TSGetDM(ts, &dm));
    1535:   PetscCall(DMTSGetI2Function(dm, &I2Function, &ctx));
    1536:   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));

    1538:   if (!I2Function) {
    1539:     PetscCall(TSComputeIFunction(ts, t, U, A, F, PETSC_FALSE));
    1540:     PetscFunctionReturn(PETSC_SUCCESS);
    1541:   }

    1543:   PetscCall(PetscLogEventBegin(TS_FunctionEval, U, ts, V, F));

    1545:   PetscCallBack("TS callback implicit function", I2Function(ts, t, U, V, A, F, ctx));

    1547:   if (rhsfunction) {
    1548:     Vec Frhs;

    1550:     PetscCall(DMGetGlobalVector(dm, &Frhs));
    1551:     PetscCall(TSComputeRHSFunction(ts, t, U, Frhs));
    1552:     PetscCall(VecAXPY(F, -1, Frhs));
    1553:     PetscCall(DMRestoreGlobalVector(dm, &Frhs));
    1554:   }

    1556:   PetscCall(PetscLogEventEnd(TS_FunctionEval, U, ts, V, F));
    1557:   PetscFunctionReturn(PETSC_SUCCESS);
    1558: }

    1560: /*@
    1561:   TSComputeI2Jacobian - Evaluates the Jacobian of the DAE

    1563:   Collective

    1565:   Input Parameters:
    1566: + ts     - the `TS` context
    1567: . t      - current timestep
    1568: . U      - state vector
    1569: . V      - time derivative of state vector
    1570: . A      - second time derivative of state vector
    1571: . shiftV - shift to apply, see note below
    1572: - shiftA - shift to apply, see note below

    1574:   Output Parameters:
    1575: + J - Jacobian matrix
    1576: - P - optional matrix used to construct the preconditioner

    1578:   Level: developer

    1580:   Notes:
    1581:   If $F(t,U,V,A) = 0$ is the DAE, the required Jacobian is

    1583: $$
    1584:   dF/dU + shiftV*dF/dV + shiftA*dF/dA
    1585: $$

    1587:   Most users should not need to explicitly call this routine, as it
    1588:   is used internally within the ODE integrators.

    1590: .seealso: [](ch_ts), `TS`, `TSSetI2Jacobian()`
    1591: @*/
    1592: PetscErrorCode TSComputeI2Jacobian(TS ts, PetscReal t, Vec U, Vec V, Vec A, PetscReal shiftV, PetscReal shiftA, Mat J, Mat P)
    1593: {
    1594:   DM               dm;
    1595:   TSI2JacobianFn  *I2Jacobian;
    1596:   void            *ctx;
    1597:   TSRHSJacobianFn *rhsjacobian;

    1599:   PetscFunctionBegin;

    1607:   PetscCall(TSGetDM(ts, &dm));
    1608:   PetscCall(DMTSGetI2Jacobian(dm, &I2Jacobian, &ctx));
    1609:   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobian, NULL));

    1611:   if (!I2Jacobian) {
    1612:     PetscCall(TSComputeIJacobian(ts, t, U, A, shiftA, J, P, PETSC_FALSE));
    1613:     PetscFunctionReturn(PETSC_SUCCESS);
    1614:   }

    1616:   PetscCall(PetscLogEventBegin(TS_JacobianEval, U, ts, J, P));
    1617:   PetscCallBack("TS callback implicit Jacobian", I2Jacobian(ts, t, U, V, A, shiftV, shiftA, J, P, ctx));
    1618:   if (rhsjacobian) {
    1619:     Mat Jrhs, Prhs;
    1620:     PetscCall(TSGetRHSMats_Private(ts, &Jrhs, &Prhs));
    1621:     PetscCall(TSComputeRHSJacobian(ts, t, U, Jrhs, Prhs));
    1622:     PetscCall(MatAXPY(J, -1, Jrhs, ts->axpy_pattern));
    1623:     if (P != J) PetscCall(MatAXPY(P, -1, Prhs, ts->axpy_pattern));
    1624:   }

    1626:   PetscCall(PetscLogEventEnd(TS_JacobianEval, U, ts, J, P));
    1627:   PetscFunctionReturn(PETSC_SUCCESS);
    1628: }

    1630: /*@C
    1631:   TSSetTransientVariable - sets function to transform from state to transient variables

    1633:   Logically Collective

    1635:   Input Parameters:
    1636: + ts   - time stepping context on which to change the transient variable
    1637: . tvar - a function that transforms to transient variables, see `TSTransientVariableFn` for the calling sequence
    1638: - ctx  - a context for tvar

    1640:   Level: advanced

    1642:   Notes:
    1643:   This is typically used to transform from primitive to conservative variables so that a time integrator (e.g., `TSBDF`)
    1644:   can be conservative.  In this context, primitive variables P are used to model the state (e.g., because they lead to
    1645:   well-conditioned formulations even in limiting cases such as low-Mach or zero porosity).  The transient variable is
    1646:   C(P), specified by calling this function.  An IFunction thus receives arguments (P, Cdot) and the IJacobian must be
    1647:   evaluated via the chain rule, as in
    1648: .vb
    1649:      dF/dP + shift * dF/dCdot dC/dP.
    1650: .ve

    1652: .seealso: [](ch_ts), `TS`, `TSBDF`, `TSTransientVariableFn`, `DMTSSetTransientVariable()`, `DMTSGetTransientVariable()`, `TSSetIFunction()`, `TSSetIJacobian()`
    1653: @*/
    1654: PetscErrorCode TSSetTransientVariable(TS ts, TSTransientVariableFn *tvar, PetscCtx ctx)
    1655: {
    1656:   DM dm;

    1658:   PetscFunctionBegin;
    1660:   PetscCall(TSGetDM(ts, &dm));
    1661:   PetscCall(DMTSSetTransientVariable(dm, tvar, ctx));
    1662:   PetscFunctionReturn(PETSC_SUCCESS);
    1663: }

    1665: /*@
    1666:   TSComputeTransientVariable - transforms state (primitive) variables to transient (conservative) variables

    1668:   Logically Collective

    1670:   Input Parameters:
    1671: + ts - TS on which to compute
    1672: - U  - state vector to be transformed to transient variables

    1674:   Output Parameter:
    1675: . C - transient (conservative) variable

    1677:   Level: developer

    1679:   Developer Notes:
    1680:   If `DMTSSetTransientVariable()` has not been called, then C is not modified in this routine and C = `NULL` is allowed.
    1681:   This makes it safe to call without a guard.  One can use `TSHasTransientVariable()` to check if transient variables are
    1682:   being used.

    1684: .seealso: [](ch_ts), `TS`, `TSBDF`, `DMTSSetTransientVariable()`, `TSComputeIFunction()`, `TSComputeIJacobian()`
    1685: @*/
    1686: PetscErrorCode TSComputeTransientVariable(TS ts, Vec U, Vec C)
    1687: {
    1688:   DM   dm;
    1689:   DMTS dmts;

    1691:   PetscFunctionBegin;
    1694:   PetscCall(TSGetDM(ts, &dm));
    1695:   PetscCall(DMGetDMTS(dm, &dmts));
    1696:   if (dmts->ops->transientvar) {
    1698:     PetscCall((*dmts->ops->transientvar)(ts, U, C, dmts->transientvarctx));
    1699:   }
    1700:   PetscFunctionReturn(PETSC_SUCCESS);
    1701: }

    1703: /*@
    1704:   TSHasTransientVariable - determine whether transient variables have been set

    1706:   Logically Collective

    1708:   Input Parameter:
    1709: . ts - `TS` on which to compute

    1711:   Output Parameter:
    1712: . has - `PETSC_TRUE` if transient variables have been set

    1714:   Level: developer

    1716: .seealso: [](ch_ts), `TS`, `TSBDF`, `DMTSSetTransientVariable()`, `TSComputeTransientVariable()`
    1717: @*/
    1718: PetscErrorCode TSHasTransientVariable(TS ts, PetscBool *has)
    1719: {
    1720:   DM   dm;
    1721:   DMTS dmts;

    1723:   PetscFunctionBegin;
    1725:   PetscCall(TSGetDM(ts, &dm));
    1726:   PetscCall(DMGetDMTS(dm, &dmts));
    1727:   *has = dmts->ops->transientvar ? PETSC_TRUE : PETSC_FALSE;
    1728:   PetscFunctionReturn(PETSC_SUCCESS);
    1729: }

    1731: /*@
    1732:   TS2SetSolution - Sets the initial solution and time derivative vectors
    1733:   for use by the `TS` routines handling second order equations.

    1735:   Logically Collective

    1737:   Input Parameters:
    1738: + ts - the `TS` context obtained from `TSCreate()`
    1739: . u  - the solution vector
    1740: - v  - the time derivative vector

    1742:   Level: beginner

    1744: .seealso: [](ch_ts), `TS`
    1745: @*/
    1746: PetscErrorCode TS2SetSolution(TS ts, Vec u, Vec v)
    1747: {
    1748:   PetscFunctionBegin;
    1752:   PetscCall(TSSetSolution(ts, u));
    1753:   PetscCall(PetscObjectReference((PetscObject)v));
    1754:   PetscCall(VecDestroy(&ts->vec_dot));
    1755:   ts->vec_dot = v;
    1756:   PetscFunctionReturn(PETSC_SUCCESS);
    1757: }

    1759: /*@
    1760:   TS2GetSolution - Returns the solution and time derivative at the present timestep
    1761:   for second order equations.

    1763:   Not Collective

    1765:   Input Parameter:
    1766: . ts - the `TS` context obtained from `TSCreate()`

    1768:   Output Parameters:
    1769: + u - the vector containing the solution
    1770: - v - the vector containing the time derivative

    1772:   Level: intermediate

    1774:   Notes:
    1775:   It is valid to call this routine inside the function
    1776:   that you are evaluating in order to move to the new timestep. This vector not
    1777:   changed until the solution at the next timestep has been calculated.

    1779: .seealso: [](ch_ts), `TS`, `TS2SetSolution()`, `TSGetTimeStep()`, `TSGetTime()`
    1780: @*/
    1781: PetscErrorCode TS2GetSolution(TS ts, Vec *u, Vec *v)
    1782: {
    1783:   PetscFunctionBegin;
    1785:   if (u) PetscAssertPointer(u, 2);
    1786:   if (v) PetscAssertPointer(v, 3);
    1787:   if (u) *u = ts->vec_sol;
    1788:   if (v) *v = ts->vec_dot;
    1789:   PetscFunctionReturn(PETSC_SUCCESS);
    1790: }

    1792: /*@
    1793:   TSLoad - Loads a `TS` that has been stored in binary  with `TSView()`.

    1795:   Collective

    1797:   Input Parameters:
    1798: + ts     - the newly loaded `TS`, this needs to have been created with `TSCreate()` or
    1799:            some related function before a call to `TSLoad()`.
    1800: - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()`

    1802:   Level: intermediate

    1804:   Note:
    1805:   The type is determined by the data in the file, any type set into the `TS` before this call is ignored.

    1807: .seealso: [](ch_ts), `TS`, `PetscViewer`, `PetscViewerBinaryOpen()`, `TSView()`, `MatLoad()`, `VecLoad()`
    1808: @*/
    1809: PetscErrorCode TSLoad(TS ts, PetscViewer viewer)
    1810: {
    1811:   PetscBool isbinary;
    1812:   PetscInt  classid;
    1813:   char      type[256];
    1814:   DMTS      sdm;
    1815:   DM        dm;

    1817:   PetscFunctionBegin;
    1820:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
    1821:   PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");

    1823:   PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
    1824:   PetscCheck(classid == TS_FILE_CLASSID, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "Not TS next in file");
    1825:   PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
    1826:   PetscCall(TSSetType(ts, type));
    1827:   PetscTryTypeMethod(ts, load, viewer);
    1828:   PetscCall(DMCreate(PetscObjectComm((PetscObject)ts), &dm));
    1829:   PetscCall(DMLoad(dm, viewer));
    1830:   PetscCall(TSSetDM(ts, dm));
    1831:   PetscCall(DMCreateGlobalVector(ts->dm, &ts->vec_sol));
    1832:   PetscCall(VecLoad(ts->vec_sol, viewer));
    1833:   PetscCall(DMGetDMTS(ts->dm, &sdm));
    1834:   PetscCall(DMTSLoad(sdm, viewer));
    1835:   PetscFunctionReturn(PETSC_SUCCESS);
    1836: }

    1838: #include <petscdraw.h>
    1839: #if defined(PETSC_HAVE_SAWS)
    1840: #include <petscviewersaws.h>
    1841: #endif

    1843: /*@
    1844:   TSViewFromOptions - View a `TS` based on values in the options database

    1846:   Collective

    1848:   Input Parameters:
    1849: + ts   - the `TS` context
    1850: . obj  - Optional object that provides the prefix for the options database keys
    1851: - name - command line option string to be passed by user

    1853:   Options Database Key:
    1854: . -name [viewertype][:...] - option name and values. See `PetscObjectViewFromOptions()` for the possible arguments

    1856:   Level: intermediate

    1858: .seealso: [](ch_ts), `TS`, `TSView`, `PetscObjectViewFromOptions()`, `TSCreate()`
    1859: @*/
    1860: PetscErrorCode TSViewFromOptions(TS ts, PetscObject obj, const char name[])
    1861: {
    1862:   PetscFunctionBegin;
    1864:   PetscCall(PetscObjectViewFromOptions((PetscObject)ts, obj, name));
    1865:   PetscFunctionReturn(PETSC_SUCCESS);
    1866: }

    1868: /*@
    1869:   TSView - Prints the `TS` data structure.

    1871:   Collective

    1873:   Input Parameters:
    1874: + ts     - the `TS` context obtained from `TSCreate()`
    1875: - viewer - visualization context

    1877:   Options Database Key:
    1878: . -ts_view - calls `TSView()` at end of `TSStep()`

    1880:   Level: beginner

    1882:   Notes:
    1883:   The available visualization contexts include
    1884: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
    1885: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
    1886:   output where only the first processor opens
    1887:   the file.  All other processors send their
    1888:   data to the first processor to print.

    1890:   The user can open an alternative visualization context with
    1891:   `PetscViewerASCIIOpen()` - output to a specified file.

    1893:   In the debugger you can do call `TSView`(ts,0) to display the `TS` solver. (The same holds for any PETSc object viewer).

    1895:   The "initial time step" displayed is the default time step from `TSCreate()` or that set with `TSSetTimeStep()` or `-ts_time_step`

    1897: .seealso: [](ch_ts), `TS`, `PetscViewer`, `PetscViewerASCIIOpen()`
    1898: @*/
    1899: PetscErrorCode TSView(TS ts, PetscViewer viewer)
    1900: {
    1901:   TSType    type;
    1902:   PetscBool isascii, isstring, issundials, isbinary, isdraw;
    1903:   DMTS      sdm;
    1904: #if defined(PETSC_HAVE_SAWS)
    1905:   PetscBool issaws;
    1906: #endif

    1908:   PetscFunctionBegin;
    1910:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)ts), &viewer));
    1912:   PetscCheckSameComm(ts, 1, viewer, 2);

    1914:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    1915:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
    1916:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
    1917:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    1918: #if defined(PETSC_HAVE_SAWS)
    1919:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
    1920: #endif
    1921:   if (isascii) {
    1922:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)ts, viewer));
    1923:     if (ts->ops->view) {
    1924:       PetscCall(PetscViewerASCIIPushTab(viewer));
    1925:       PetscUseTypeMethod(ts, view, viewer);
    1926:       PetscCall(PetscViewerASCIIPopTab(viewer));
    1927:     }
    1928:     PetscCall(PetscViewerASCIIPrintf(viewer, "  initial time step=%g\n", (double)ts->initial_time_step));
    1929:     if (ts->max_steps < PETSC_INT_MAX) PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum steps=%" PetscInt_FMT "\n", ts->max_steps));
    1930:     if (ts->run_steps < PETSC_INT_MAX) PetscCall(PetscViewerASCIIPrintf(viewer, "  run steps=%" PetscInt_FMT "\n", ts->run_steps));
    1931:     if (ts->max_time < PETSC_MAX_REAL) PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum time=%g\n", (double)ts->max_time));
    1932:     if (ts->max_reject != PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum number of step rejections=%" PetscInt_FMT "\n", ts->max_reject));
    1933:     if (ts->max_snes_failures != PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum number of SNES failures allowed=%" PetscInt_FMT "\n", ts->max_snes_failures));
    1934:     if (ts->ifuncs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of I function evaluations=%" PetscInt_FMT "\n", ts->ifuncs));
    1935:     if (ts->ijacs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of I Jacobian evaluations=%" PetscInt_FMT "\n", ts->ijacs));
    1936:     if (ts->rhsfuncs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of RHS function evaluations=%" PetscInt_FMT "\n", ts->rhsfuncs));
    1937:     if (ts->rhsjacs) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of RHS Jacobian evaluations=%" PetscInt_FMT "\n", ts->rhsjacs));
    1938:     if (ts->usessnes) {
    1939:       PetscBool lin;
    1940:       if (ts->problem_type == TS_NONLINEAR) PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of nonlinear solver iterations=%" PetscInt_FMT "\n", ts->snes_its));
    1941:       PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of linear solver iterations=%" PetscInt_FMT "\n", ts->ksp_its));
    1942:       PetscCall(PetscObjectTypeCompareAny((PetscObject)ts->snes, &lin, SNESKSPONLY, SNESKSPTRANSPOSEONLY, ""));
    1943:       PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of %slinear solve failures=%" PetscInt_FMT "\n", lin ? "" : "non", ts->num_snes_failures));
    1944:     }
    1945:     PetscCall(PetscViewerASCIIPrintf(viewer, "  total number of rejected steps=%" PetscInt_FMT "\n", ts->reject));
    1946:     if (ts->vrtol) PetscCall(PetscViewerASCIIPrintf(viewer, "  using vector of relative error tolerances, "));
    1947:     else PetscCall(PetscViewerASCIIPrintf(viewer, "  using relative error tolerance of %g, ", (double)ts->rtol));
    1948:     if (ts->vatol) PetscCall(PetscViewerASCIIPrintf(viewer, "using vector of absolute error tolerances\n"));
    1949:     else PetscCall(PetscViewerASCIIPrintf(viewer, "using absolute error tolerance of %g\n", (double)ts->atol));
    1950:     PetscCall(PetscViewerASCIIPushTab(viewer));
    1951:     PetscCall(TSAdaptView(ts->adapt, viewer));
    1952:     PetscCall(PetscViewerASCIIPopTab(viewer));
    1953:   } else if (isstring) {
    1954:     PetscCall(TSGetType(ts, &type));
    1955:     PetscCall(PetscViewerStringSPrintf(viewer, " TSType: %-7.7s", type));
    1956:     PetscTryTypeMethod(ts, view, viewer);
    1957:   } else if (isbinary) {
    1958:     PetscInt    classid = TS_FILE_CLASSID;
    1959:     MPI_Comm    comm;
    1960:     PetscMPIInt rank;
    1961:     char        type[256];

    1963:     PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
    1964:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
    1965:     if (rank == 0) {
    1966:       PetscCall(PetscViewerBinaryWrite(viewer, &classid, 1, PETSC_INT));
    1967:       PetscCall(PetscStrncpy(type, ((PetscObject)ts)->type_name, 256));
    1968:       PetscCall(PetscViewerBinaryWrite(viewer, type, 256, PETSC_CHAR));
    1969:     }
    1970:     PetscTryTypeMethod(ts, view, viewer);
    1971:     if (ts->adapt) PetscCall(TSAdaptView(ts->adapt, viewer));
    1972:     PetscCall(DMView(ts->dm, viewer));
    1973:     PetscCall(VecView(ts->vec_sol, viewer));
    1974:     PetscCall(DMGetDMTS(ts->dm, &sdm));
    1975:     PetscCall(DMTSView(sdm, viewer));
    1976:   } else if (isdraw) {
    1977:     PetscDraw draw;
    1978:     char      str[36];
    1979:     PetscReal x, y, bottom, h;

    1981:     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
    1982:     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
    1983:     PetscCall(PetscStrncpy(str, "TS: ", sizeof(str)));
    1984:     PetscCall(PetscStrlcat(str, ((PetscObject)ts)->type_name, sizeof(str)));
    1985:     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_BLACK, PETSC_DRAW_BLACK, str, NULL, &h));
    1986:     bottom = y - h;
    1987:     PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
    1988:     PetscTryTypeMethod(ts, view, viewer);
    1989:     if (ts->adapt) PetscCall(TSAdaptView(ts->adapt, viewer));
    1990:     if (ts->snes) PetscCall(SNESView(ts->snes, viewer));
    1991:     PetscCall(PetscDrawPopCurrentPoint(draw));
    1992: #if defined(PETSC_HAVE_SAWS)
    1993:   } else if (issaws) {
    1994:     PetscMPIInt rank;
    1995:     const char *name;

    1997:     PetscCall(PetscObjectGetName((PetscObject)ts, &name));
    1998:     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
    1999:     if (!((PetscObject)ts)->amsmem && rank == 0) {
    2000:       char dir[1024];

    2002:       PetscCall(PetscObjectViewSAWs((PetscObject)ts, viewer));
    2003:       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/time_step", name));
    2004:       PetscCallSAWs(SAWs_Register, (dir, &ts->steps, 1, SAWs_READ, SAWs_INT));
    2005:       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/time", name));
    2006:       PetscCallSAWs(SAWs_Register, (dir, &ts->ptime, 1, SAWs_READ, SAWs_DOUBLE));
    2007:     }
    2008:     PetscTryTypeMethod(ts, view, viewer);
    2009: #endif
    2010:   }
    2011:   if (ts->snes && ts->usessnes) {
    2012:     PetscCall(PetscViewerASCIIPushTab(viewer));
    2013:     PetscCall(SNESView(ts->snes, viewer));
    2014:     PetscCall(PetscViewerASCIIPopTab(viewer));
    2015:   }
    2016:   PetscCall(DMGetDMTS(ts->dm, &sdm));
    2017:   PetscCall(DMTSView(sdm, viewer));

    2019:   PetscCall(PetscViewerASCIIPushTab(viewer));
    2020:   PetscCall(PetscObjectTypeCompare((PetscObject)ts, TSSUNDIALS, &issundials));
    2021:   PetscCall(PetscViewerASCIIPopTab(viewer));
    2022:   PetscFunctionReturn(PETSC_SUCCESS);
    2023: }

    2025: /*@
    2026:   TSSetApplicationContext - Sets an optional user-defined context for the timesteppers that may be accessed, for example inside the user provided
    2027:   `TS` callbacks with `TSGetApplicationContext()`

    2029:   Logically Collective

    2031:   Input Parameters:
    2032: + ts  - the `TS` context obtained from `TSCreate()`
    2033: - ctx - user context

    2035:   Level: intermediate

    2037:   Fortran Note:
    2038:   This only works when `ctx` is a Fortran derived type (it cannot be a `PetscObject`), we recommend writing a Fortran interface definition for this
    2039:   function that tells the Fortran compiler the derived data type that is passed in as the `ctx` argument. See `TSGetApplicationContext()` for
    2040:   an example.

    2042: .seealso: [](ch_ts), `TS`, `TSGetApplicationContext()`
    2043: @*/
    2044: PetscErrorCode TSSetApplicationContext(TS ts, PetscCtx ctx)
    2045: {
    2046:   PetscFunctionBegin;
    2048:   ts->ctx = ctx;
    2049:   PetscFunctionReturn(PETSC_SUCCESS);
    2050: }

    2052: /*@
    2053:   TSGetApplicationContext - Gets the user-defined context for the
    2054:   timestepper that was set with `TSSetApplicationContext()`

    2056:   Not Collective

    2058:   Input Parameter:
    2059: . ts - the `TS` context obtained from `TSCreate()`

    2061:   Output Parameter:
    2062: . ctx - a pointer to the user context

    2064:   Level: intermediate

    2066:   Fortran Notes:
    2067:   This only works when the context is a Fortran derived type or a `PetscObject`. Declare `ctx` with
    2068: .vb
    2069:   type(tUsertype), pointer :: ctx
    2070: .ve

    2072: .seealso: [](ch_ts), `TS`, `TSSetApplicationContext()`
    2073: @*/
    2074: PetscErrorCode TSGetApplicationContext(TS ts, PetscCtxRt ctx)
    2075: {
    2076:   PetscFunctionBegin;
    2078:   *(void **)ctx = ts->ctx;
    2079:   PetscFunctionReturn(PETSC_SUCCESS);
    2080: }

    2082: /*@
    2083:   TSGetStepNumber - Gets the number of time steps completed.

    2085:   Not Collective

    2087:   Input Parameter:
    2088: . ts - the `TS` context obtained from `TSCreate()`

    2090:   Output Parameter:
    2091: . steps - number of steps completed so far

    2093:   Level: intermediate

    2095: .seealso: [](ch_ts), `TS`, `TSGetTime()`, `TSGetTimeStep()`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostStage()`, `TSSetPostStep()`
    2096: @*/
    2097: PetscErrorCode TSGetStepNumber(TS ts, PetscInt *steps)
    2098: {
    2099:   PetscFunctionBegin;
    2101:   PetscAssertPointer(steps, 2);
    2102:   *steps = ts->steps;
    2103:   PetscFunctionReturn(PETSC_SUCCESS);
    2104: }

    2106: /*@
    2107:   TSSetStepNumber - Sets the number of steps completed.

    2109:   Logically Collective

    2111:   Input Parameters:
    2112: + ts    - the `TS` context
    2113: - steps - number of steps completed so far

    2115:   Level: developer

    2117:   Note:
    2118:   For most uses of the `TS` solvers the user need not explicitly call
    2119:   `TSSetStepNumber()`, as the step counter is appropriately updated in
    2120:   `TSSolve()`/`TSStep()`/`TSRollBack()`. Power users may call this routine to
    2121:   reinitialize timestepping by setting the step counter to zero (and time
    2122:   to the initial time) to solve a similar problem with different initial
    2123:   conditions or parameters. Other possible use case is to continue
    2124:   timestepping from a previously interrupted run in such a way that `TS`
    2125:   monitors will be called with a initial nonzero step counter.

    2127: .seealso: [](ch_ts), `TS`, `TSGetStepNumber()`, `TSSetTime()`, `TSSetTimeStep()`, `TSSetSolution()`
    2128: @*/
    2129: PetscErrorCode TSSetStepNumber(TS ts, PetscInt steps)
    2130: {
    2131:   PetscFunctionBegin;
    2134:   PetscCheck(steps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Step number must be non-negative");
    2135:   ts->steps = steps;
    2136:   PetscFunctionReturn(PETSC_SUCCESS);
    2137: }

    2139: /*@
    2140:   TSSetTimeStep - Allows one to reset the timestep at any time.

    2142:   Logically Collective

    2144:   Input Parameters:
    2145: + ts        - the `TS` context obtained from `TSCreate()`
    2146: - time_step - the size of the timestep

    2148:   Options Database Key:
    2149: . -ts_time_step dt - provide the initial time step

    2151:   Level: intermediate

    2153:   Notes:
    2154:   This is only a suggestion, the actual initial time step used may differ

    2156:   If this is called after `TSSetUp()`, it will not change the initial time step value printed by `TSView()`

    2158: .seealso: [](ch_ts), `TS`, `TSPSEUDO`, `TSGetTimeStep()`, `TSSetTime()`
    2159: @*/
    2160: PetscErrorCode TSSetTimeStep(TS ts, PetscReal time_step)
    2161: {
    2162:   PetscFunctionBegin;
    2165:   ts->time_step = time_step;
    2166:   if (ts->setupcalled == PETSC_FALSE) ts->initial_time_step = time_step;
    2167:   PetscFunctionReturn(PETSC_SUCCESS);
    2168: }

    2170: /*@
    2171:   TSSetExactFinalTime - Determines whether to adapt the final time step to
    2172:   match the exact final time, to interpolate the solution to the exact final time,
    2173:   or to just return at the final time `TS` computed (which may be slightly larger
    2174:   than the requested final time).

    2176:   Logically Collective

    2178:   Input Parameters:
    2179: + ts     - the time-step context
    2180: - eftopt - exact final time option
    2181: .vb
    2182:   TS_EXACTFINALTIME_STEPOVER    - Don't do anything if final time is exceeded, just use it
    2183:   TS_EXACTFINALTIME_INTERPOLATE - Interpolate back to final time if the final time is exceeded
    2184:   TS_EXACTFINALTIME_MATCHSTEP   - Adapt final time step to ensure the computed final time exactly equals the requested final time
    2185: .ve

    2187:   Options Database Key:
    2188: . -ts_exact_final_time stepover,interpolate,matchstep - select the final step approach at runtime

    2190:   Level: beginner

    2192:   Note:
    2193:   If you use the option `TS_EXACTFINALTIME_STEPOVER` the solution may be at a very different time
    2194:   then the final time you selected.

    2196: .seealso: [](ch_ts), `TS`, `TSExactFinalTimeOption`, `TSGetExactFinalTime()`
    2197: @*/
    2198: PetscErrorCode TSSetExactFinalTime(TS ts, TSExactFinalTimeOption eftopt)
    2199: {
    2200:   PetscFunctionBegin;
    2203:   ts->exact_final_time = eftopt;
    2204:   PetscFunctionReturn(PETSC_SUCCESS);
    2205: }

    2207: /*@
    2208:   TSGetExactFinalTime - Gets the exact final time option set with `TSSetExactFinalTime()`

    2210:   Not Collective

    2212:   Input Parameter:
    2213: . ts - the `TS` context

    2215:   Output Parameter:
    2216: . eftopt - exact final time option

    2218:   Level: beginner

    2220: .seealso: [](ch_ts), `TS`, `TSExactFinalTimeOption`, `TSSetExactFinalTime()`
    2221: @*/
    2222: PetscErrorCode TSGetExactFinalTime(TS ts, TSExactFinalTimeOption *eftopt)
    2223: {
    2224:   PetscFunctionBegin;
    2226:   PetscAssertPointer(eftopt, 2);
    2227:   *eftopt = ts->exact_final_time;
    2228:   PetscFunctionReturn(PETSC_SUCCESS);
    2229: }

    2231: /*@
    2232:   TSGetTimeStep - Gets the current timestep size.

    2234:   Not Collective

    2236:   Input Parameter:
    2237: . ts - the `TS` context obtained from `TSCreate()`

    2239:   Output Parameter:
    2240: . dt - the current timestep size

    2242:   Level: intermediate

    2244: .seealso: [](ch_ts), `TS`, `TSSetTimeStep()`, `TSGetTime()`
    2245: @*/
    2246: PetscErrorCode TSGetTimeStep(TS ts, PetscReal *dt)
    2247: {
    2248:   PetscFunctionBegin;
    2250:   PetscAssertPointer(dt, 2);
    2251:   *dt = ts->time_step;
    2252:   PetscFunctionReturn(PETSC_SUCCESS);
    2253: }

    2255: /*@
    2256:   TSGetSolution - Returns the solution at the present timestep. It
    2257:   is valid to call this routine inside the function that you are evaluating
    2258:   in order to move to the new timestep. This vector not changed until
    2259:   the solution at the next timestep has been calculated.

    2261:   Not Collective, but v returned is parallel if ts is parallel

    2263:   Input Parameter:
    2264: . ts - the `TS` context obtained from `TSCreate()`

    2266:   Output Parameter:
    2267: . v - the vector containing the solution

    2269:   Level: intermediate

    2271:   Note:
    2272:   If you used `TSSetExactFinalTime`(ts,`TS_EXACTFINALTIME_MATCHSTEP`); this does not return the solution at the requested
    2273:   final time. It returns the solution at the next timestep.

    2275: .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetTime()`, `TSGetSolveTime()`, `TSGetSolutionComponents()`, `TSSetSolutionFunction()`
    2276: @*/
    2277: PetscErrorCode TSGetSolution(TS ts, Vec *v)
    2278: {
    2279:   PetscFunctionBegin;
    2281:   PetscAssertPointer(v, 2);
    2282:   *v = ts->vec_sol;
    2283:   PetscFunctionReturn(PETSC_SUCCESS);
    2284: }

    2286: /*@
    2287:   TSGetSolutionComponents - Returns any solution components at the present
    2288:   timestep, if available for the time integration method being used.
    2289:   Solution components are quantities that share the same size and
    2290:   structure as the solution vector.

    2292:   Not Collective, but v returned is parallel if ts is parallel

    2294:   Input Parameters:
    2295: + ts - the `TS` context obtained from `TSCreate()` (input parameter).
    2296: . n  - If v is `NULL`, then the number of solution components is
    2297:        returned through n, else the n-th solution component is
    2298:        returned in v.
    2299: - v  - the vector containing the n-th solution component
    2300:        (may be `NULL` to use this function to find out
    2301:         the number of solutions components).

    2303:   Level: advanced

    2305: .seealso: [](ch_ts), `TS`, `TSGetSolution()`
    2306: @*/
    2307: PetscErrorCode TSGetSolutionComponents(TS ts, PetscInt *n, Vec *v)
    2308: {
    2309:   PetscFunctionBegin;
    2311:   if (!ts->ops->getsolutioncomponents) *n = 0;
    2312:   else PetscUseTypeMethod(ts, getsolutioncomponents, n, v);
    2313:   PetscFunctionReturn(PETSC_SUCCESS);
    2314: }

    2316: /*@
    2317:   TSGetAuxSolution - Returns an auxiliary solution at the present
    2318:   timestep, if available for the time integration method being used.

    2320:   Not Collective, but v returned is parallel if ts is parallel

    2322:   Input Parameters:
    2323: + ts - the `TS` context obtained from `TSCreate()` (input parameter).
    2324: - v  - the vector containing the auxiliary solution

    2326:   Level: intermediate

    2328: .seealso: [](ch_ts), `TS`, `TSGetSolution()`
    2329: @*/
    2330: PetscErrorCode TSGetAuxSolution(TS ts, Vec *v)
    2331: {
    2332:   PetscFunctionBegin;
    2334:   if (ts->ops->getauxsolution) PetscUseTypeMethod(ts, getauxsolution, v);
    2335:   else PetscCall(VecZeroEntries(*v));
    2336:   PetscFunctionReturn(PETSC_SUCCESS);
    2337: }

    2339: /*@
    2340:   TSGetTimeError - Returns the estimated error vector, if the chosen
    2341:   `TSType` has an error estimation functionality and `TSSetTimeError()` was called

    2343:   Not Collective, but v returned is parallel if ts is parallel

    2345:   Input Parameters:
    2346: + ts - the `TS` context obtained from `TSCreate()` (input parameter).
    2347: . n  - current estimate (n=0) or previous one (n=-1)
    2348: - v  - the vector containing the error (same size as the solution).

    2350:   Level: intermediate

    2352:   Note:
    2353:   MUST call after `TSSetUp()`

    2355: .seealso: [](ch_ts), `TSGetSolution()`, `TSSetTimeError()`
    2356: @*/
    2357: PetscErrorCode TSGetTimeError(TS ts, PetscInt n, Vec *v)
    2358: {
    2359:   PetscFunctionBegin;
    2361:   if (ts->ops->gettimeerror) PetscUseTypeMethod(ts, gettimeerror, n, v);
    2362:   else PetscCall(VecZeroEntries(*v));
    2363:   PetscFunctionReturn(PETSC_SUCCESS);
    2364: }

    2366: /*@
    2367:   TSSetTimeError - Sets the estimated error vector, if the chosen
    2368:   `TSType` has an error estimation functionality. This can be used
    2369:   to restart such a time integrator with a given error vector.

    2371:   Not Collective, but v returned is parallel if ts is parallel

    2373:   Input Parameters:
    2374: + ts - the `TS` context obtained from `TSCreate()` (input parameter).
    2375: - v  - the vector containing the error (same size as the solution).

    2377:   Level: intermediate

    2379: .seealso: [](ch_ts), `TS`, `TSSetSolution()`, `TSGetTimeError()`
    2380: @*/
    2381: PetscErrorCode TSSetTimeError(TS ts, Vec v)
    2382: {
    2383:   PetscFunctionBegin;
    2385:   PetscCheck(ts->setupcalled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetUp() first");
    2386:   PetscTryTypeMethod(ts, settimeerror, v);
    2387:   PetscFunctionReturn(PETSC_SUCCESS);
    2388: }

    2390: /* ----- Routines to initialize and destroy a timestepper ---- */
    2391: /*@
    2392:   TSSetProblemType - Sets the type of problem to be solved.

    2394:   Not collective

    2396:   Input Parameters:
    2397: + ts   - The `TS`
    2398: - type - One of `TS_LINEAR`, `TS_NONLINEAR` where these types refer to problems of the forms
    2399: .vb
    2400:          U_t - A U = 0      (linear)
    2401:          U_t - A(t) U = 0   (linear)
    2402:          F(t,U,U_t) = 0     (nonlinear)
    2403: .ve

    2405:   Level: beginner

    2407: .seealso: [](ch_ts), `TSSetUp()`, `TSProblemType`, `TS`
    2408: @*/
    2409: PetscErrorCode TSSetProblemType(TS ts, TSProblemType type)
    2410: {
    2411:   PetscFunctionBegin;
    2413:   ts->problem_type = type;
    2414:   if (type == TS_LINEAR) {
    2415:     SNES snes;
    2416:     PetscCall(TSGetSNES(ts, &snes));
    2417:     PetscCall(SNESSetType(snes, SNESKSPONLY));
    2418:   }
    2419:   PetscFunctionReturn(PETSC_SUCCESS);
    2420: }

    2422: /*@
    2423:   TSGetProblemType - Gets the type of problem to be solved.

    2425:   Not collective

    2427:   Input Parameter:
    2428: . ts - The `TS`

    2430:   Output Parameter:
    2431: . type - One of `TS_LINEAR`, `TS_NONLINEAR` where these types refer to problems of the forms
    2432: .vb
    2433:          M U_t = A U
    2434:          M(t) U_t = A(t) U
    2435:          F(t,U,U_t)
    2436: .ve

    2438:   Level: beginner

    2440: .seealso: [](ch_ts), `TSSetUp()`, `TSProblemType`, `TS`
    2441: @*/
    2442: PetscErrorCode TSGetProblemType(TS ts, TSProblemType *type)
    2443: {
    2444:   PetscFunctionBegin;
    2446:   PetscAssertPointer(type, 2);
    2447:   *type = ts->problem_type;
    2448:   PetscFunctionReturn(PETSC_SUCCESS);
    2449: }

    2451: /*
    2452:     Attempt to check/preset a default value for the exact final time option. This is needed at the beginning of TSSolve() and in TSSetUp()
    2453: */
    2454: static PetscErrorCode TSSetExactFinalTimeDefault(TS ts)
    2455: {
    2456:   PetscBool isnone;

    2458:   PetscFunctionBegin;
    2459:   PetscCall(TSGetAdapt(ts, &ts->adapt));
    2460:   PetscCall(TSAdaptSetDefaultType(ts->adapt, ts->default_adapt_type));

    2462:   PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &isnone));
    2463:   if (!isnone && ts->exact_final_time == TS_EXACTFINALTIME_UNSPECIFIED) ts->exact_final_time = TS_EXACTFINALTIME_MATCHSTEP;
    2464:   else if (ts->exact_final_time == TS_EXACTFINALTIME_UNSPECIFIED) ts->exact_final_time = TS_EXACTFINALTIME_INTERPOLATE;
    2465:   PetscFunctionReturn(PETSC_SUCCESS);
    2466: }

    2468: /*@
    2469:   TSSetUp - Sets up the internal data structures for the later use of a timestepper.

    2471:   Collective

    2473:   Input Parameter:
    2474: . ts - the `TS` context obtained from `TSCreate()`

    2476:   Level: advanced

    2478:   Note:
    2479:   For basic use of the `TS` solvers the user need not explicitly call
    2480:   `TSSetUp()`, since these actions will automatically occur during
    2481:   the call to `TSStep()` or `TSSolve()`.  However, if one wishes to control this
    2482:   phase separately, `TSSetUp()` should be called after `TSCreate()`
    2483:   and optional routines of the form TSSetXXX(), but before `TSStep()` and `TSSolve()`.

    2485: .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSStep()`, `TSDestroy()`, `TSSolve()`
    2486: @*/
    2487: PetscErrorCode TSSetUp(TS ts)
    2488: {
    2489:   DM dm;
    2490:   PetscErrorCode (*func)(SNES, Vec, Vec, void *);
    2491:   PetscErrorCode (*jac)(SNES, Vec, Mat, Mat, void *);
    2492:   TSIFunctionFn   *ifun;
    2493:   TSIJacobianFn   *ijac;
    2494:   TSI2JacobianFn  *i2jac;
    2495:   TSRHSJacobianFn *rhsjac;

    2497:   PetscFunctionBegin;
    2499:   if (ts->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);

    2501:   if (!((PetscObject)ts)->type_name) {
    2502:     PetscCall(TSGetIFunction(ts, NULL, &ifun, NULL));
    2503:     PetscCall(TSSetType(ts, ifun ? TSBEULER : TSEULER));
    2504:   }

    2506:   if (!ts->vec_sol) {
    2507:     PetscCheck(ts->dm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call TSSetSolution() first");
    2508:     PetscCall(DMCreateGlobalVector(ts->dm, &ts->vec_sol));
    2509:   }

    2511:   if (!ts->Jacp && ts->Jacprhs) { /* IJacobianP shares the same matrix with RHSJacobianP if only RHSJacobianP is provided */
    2512:     PetscCall(PetscObjectReference((PetscObject)ts->Jacprhs));
    2513:     ts->Jacp = ts->Jacprhs;
    2514:   }

    2516:   if (ts->quadraturets) {
    2517:     PetscCall(TSSetUp(ts->quadraturets));
    2518:     PetscCall(VecDestroy(&ts->vec_costintegrand));
    2519:     PetscCall(VecDuplicate(ts->quadraturets->vec_sol, &ts->vec_costintegrand));
    2520:   }

    2522:   PetscCall(TSGetRHSJacobian(ts, NULL, NULL, &rhsjac, NULL));
    2523:   if (rhsjac == TSComputeRHSJacobianConstant) {
    2524:     Mat  Amat, Pmat;
    2525:     SNES snes;
    2526:     PetscCall(TSGetSNES(ts, &snes));
    2527:     PetscCall(SNESGetJacobian(snes, &Amat, &Pmat, NULL, NULL));
    2528:     /* Matching matrices implies that an IJacobian is NOT set, because if it had been set, the IJacobian's matrix would
    2529:      * have displaced the RHS matrix */
    2530:     if (Amat && Amat == ts->Arhs) {
    2531:       /* 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 */
    2532:       PetscCall(MatDuplicate(ts->Arhs, MAT_COPY_VALUES, &Amat));
    2533:       PetscCall(SNESSetJacobian(snes, Amat, NULL, NULL, NULL));
    2534:       PetscCall(MatDestroy(&Amat));
    2535:     }
    2536:     if (Pmat && Pmat == ts->Brhs) {
    2537:       PetscCall(MatDuplicate(ts->Brhs, MAT_COPY_VALUES, &Pmat));
    2538:       PetscCall(SNESSetJacobian(snes, NULL, Pmat, NULL, NULL));
    2539:       PetscCall(MatDestroy(&Pmat));
    2540:     }
    2541:   }

    2543:   PetscCall(TSGetAdapt(ts, &ts->adapt));
    2544:   PetscCall(TSAdaptSetDefaultType(ts->adapt, ts->default_adapt_type));

    2546:   PetscTryTypeMethod(ts, setup);

    2548:   PetscCall(TSSetExactFinalTimeDefault(ts));

    2550:   /* In the case where we've set a DMTSFunction or what have you, we need the default SNESFunction
    2551:      to be set right but can't do it elsewhere due to the overreliance on ctx=ts.
    2552:    */
    2553:   PetscCall(TSGetDM(ts, &dm));
    2554:   PetscCall(DMSNESGetFunction(dm, &func, NULL));
    2555:   if (!func) PetscCall(DMSNESSetFunction(dm, SNESTSFormFunction, ts));

    2557:   /* If the SNES doesn't have a jacobian set and the TS has an ijacobian or rhsjacobian set, set the SNES to use it.
    2558:      Otherwise, the SNES will use coloring internally to form the Jacobian.
    2559:    */
    2560:   PetscCall(DMSNESGetJacobian(dm, &jac, NULL));
    2561:   PetscCall(DMTSGetIJacobian(dm, &ijac, NULL));
    2562:   PetscCall(DMTSGetI2Jacobian(dm, &i2jac, NULL));
    2563:   PetscCall(DMTSGetRHSJacobian(dm, &rhsjac, NULL));
    2564:   if (!jac && (ijac || i2jac || rhsjac)) PetscCall(DMSNESSetJacobian(dm, SNESTSFormJacobian, ts));

    2566:   /* if time integration scheme has a starting method, call it */
    2567:   PetscTryTypeMethod(ts, startingmethod);

    2569:   ts->setupcalled = PETSC_TRUE;
    2570:   PetscFunctionReturn(PETSC_SUCCESS);
    2571: }

    2573: /*@
    2574:   TSReset - Resets a `TS` context to the state it was in before `TSSetUp()` was called and removes any allocated `Vec` and `Mat` from its data structures

    2576:   Collective

    2578:   Input Parameter:
    2579: . ts - the `TS` context obtained from `TSCreate()`

    2581:   Level: developer

    2583:   Notes:
    2584:   Any options set on the `TS` object, including those set with `TSSetFromOptions()` remain.

    2586:   See also `TSSetResize()` to change the size of the system being integrated (for example by adaptive mesh refinement) during the time integration.

    2588: .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetUp()`, `TSDestroy()`, `TSSetResize()`
    2589: @*/
    2590: PetscErrorCode TSReset(TS ts)
    2591: {
    2592:   TS_RHSSplitLink ilink = ts->tsrhssplit, next;

    2594:   PetscFunctionBegin;

    2597:   PetscTryTypeMethod(ts, reset);
    2598:   if (ts->snes) PetscCall(SNESReset(ts->snes));
    2599:   if (ts->adapt) PetscCall(TSAdaptReset(ts->adapt));

    2601:   PetscCall(MatDestroy(&ts->Arhs));
    2602:   PetscCall(MatDestroy(&ts->Brhs));
    2603:   PetscCall(VecDestroy(&ts->Frhs));
    2604:   PetscCall(VecDestroy(&ts->vec_sol));
    2605:   PetscCall(VecDestroy(&ts->vec_sol0));
    2606:   PetscCall(VecDestroy(&ts->vec_dot));
    2607:   PetscCall(VecDestroy(&ts->vatol));
    2608:   PetscCall(VecDestroy(&ts->vrtol));
    2609:   PetscCall(VecDestroyVecs(ts->nwork, &ts->work));

    2611:   PetscCall(MatDestroy(&ts->Jacprhs));
    2612:   PetscCall(MatDestroy(&ts->Jacp));
    2613:   if (ts->forward_solve) PetscCall(TSForwardReset(ts));
    2614:   if (ts->quadraturets) {
    2615:     PetscCall(TSReset(ts->quadraturets));
    2616:     PetscCall(VecDestroy(&ts->vec_costintegrand));
    2617:   }
    2618:   while (ilink) {
    2619:     next = ilink->next;
    2620:     PetscCall(TSDestroy(&ilink->ts));
    2621:     PetscCall(PetscFree(ilink->splitname));
    2622:     PetscCall(ISDestroy(&ilink->is));
    2623:     PetscCall(PetscFree(ilink));
    2624:     ilink = next;
    2625:   }
    2626:   ts->tsrhssplit     = NULL;
    2627:   ts->num_rhs_splits = 0;
    2628:   if (ts->eval_times) {
    2629:     PetscCall(PetscFree(ts->eval_times->time_points));
    2630:     PetscCall(PetscFree(ts->eval_times->sol_times));
    2631:     PetscCall(VecDestroyVecs(ts->eval_times->num_time_points, &ts->eval_times->sol_vecs));
    2632:     PetscCall(PetscFree(ts->eval_times));
    2633:   }
    2634:   ts->rhsjacobian.time  = PETSC_MIN_REAL;
    2635:   ts->rhsjacobian.scale = 1.0;
    2636:   ts->ijacobian.shift   = 1.0;
    2637:   ts->setupcalled       = PETSC_FALSE;
    2638:   PetscFunctionReturn(PETSC_SUCCESS);
    2639: }

    2641: static PetscErrorCode TSResizeReset(TS);

    2643: /*@
    2644:   TSDestroy - Destroys the timestepper context that was created
    2645:   with `TSCreate()`.

    2647:   Collective

    2649:   Input Parameter:
    2650: . ts - the `TS` context obtained from `TSCreate()`

    2652:   Level: beginner

    2654: .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetUp()`, `TSSolve()`
    2655: @*/
    2656: PetscErrorCode TSDestroy(TS *ts)
    2657: {
    2658:   PetscFunctionBegin;
    2659:   if (!*ts) PetscFunctionReturn(PETSC_SUCCESS);
    2661:   if (--((PetscObject)*ts)->refct > 0) {
    2662:     *ts = NULL;
    2663:     PetscFunctionReturn(PETSC_SUCCESS);
    2664:   }

    2666:   PetscCall(TSReset(*ts));
    2667:   PetscCall(TSAdjointReset(*ts));
    2668:   if ((*ts)->forward_solve) PetscCall(TSForwardReset(*ts));
    2669:   PetscCall(TSResizeReset(*ts));

    2671:   /* if memory was published with SAWs then destroy it */
    2672:   PetscCall(PetscObjectSAWsViewOff((PetscObject)*ts));
    2673:   PetscTryTypeMethod(*ts, destroy);

    2675:   PetscCall(TSTrajectoryDestroy(&(*ts)->trajectory));

    2677:   PetscCall(TSAdaptDestroy(&(*ts)->adapt));
    2678:   PetscCall(TSEventDestroy(&(*ts)->event));

    2680:   PetscCall(SNESDestroy(&(*ts)->snes));
    2681:   PetscCall(SNESDestroy(&(*ts)->snesrhssplit));
    2682:   PetscCall(DMDestroy(&(*ts)->dm));
    2683:   PetscCall(TSMonitorCancel(*ts));
    2684:   PetscCall(TSAdjointMonitorCancel(*ts));

    2686:   PetscCall(TSDestroy(&(*ts)->quadraturets));
    2687:   PetscCall(PetscHeaderDestroy(ts));
    2688:   PetscFunctionReturn(PETSC_SUCCESS);
    2689: }

    2691: /*@
    2692:   TSGetSNES - Returns the `SNES` (nonlinear solver) associated with
    2693:   a `TS` (timestepper) context. Valid only for nonlinear problems.

    2695:   Not Collective, but `snes` is parallel if `ts` is parallel

    2697:   Input Parameter:
    2698: . ts - the `TS` context obtained from `TSCreate()`

    2700:   Output Parameter:
    2701: . snes - the nonlinear solver context

    2703:   Level: beginner

    2705:   Notes:
    2706:   The user can then directly manipulate the `SNES` context to set various
    2707:   options, etc.  Likewise, the user can then extract and manipulate the
    2708:   `KSP`, and `PC` contexts as well.

    2710:   `TSGetSNES()` does not work for integrators that do not use `SNES`; in
    2711:   this case `TSGetSNES()` returns `NULL` in `snes`.

    2713: .seealso: [](ch_ts), `TS`, `SNES`, `TSCreate()`, `TSSetUp()`, `TSSolve()`
    2714: @*/
    2715: PetscErrorCode TSGetSNES(TS ts, SNES *snes)
    2716: {
    2717:   PetscFunctionBegin;
    2719:   PetscAssertPointer(snes, 2);
    2720:   if (!ts->snes) {
    2721:     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ts), &ts->snes));
    2722:     PetscCall(PetscObjectSetOptions((PetscObject)ts->snes, ((PetscObject)ts)->options));
    2723:     PetscCall(SNESSetFunction(ts->snes, NULL, SNESTSFormFunction, ts));
    2724:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->snes, (PetscObject)ts, 1));
    2725:     if (ts->dm) PetscCall(SNESSetDM(ts->snes, ts->dm));
    2726:     if (ts->problem_type == TS_LINEAR) PetscCall(SNESSetType(ts->snes, SNESKSPONLY));
    2727:   }
    2728:   *snes = ts->snes;
    2729:   PetscFunctionReturn(PETSC_SUCCESS);
    2730: }

    2732: /*@
    2733:   TSSetSNES - Set the `SNES` (nonlinear solver) to be used by the `TS` timestepping context

    2735:   Collective

    2737:   Input Parameters:
    2738: + ts   - the `TS` context obtained from `TSCreate()`
    2739: - snes - the nonlinear solver context

    2741:   Level: developer

    2743:   Note:
    2744:   Most users should have the `TS` created by calling `TSGetSNES()`

    2746: .seealso: [](ch_ts), `TS`, `SNES`, `TSCreate()`, `TSSetUp()`, `TSSolve()`, `TSGetSNES()`
    2747: @*/
    2748: PetscErrorCode TSSetSNES(TS ts, SNES snes)
    2749: {
    2750:   PetscErrorCode (*func)(SNES, Vec, Mat, Mat, void *);

    2752:   PetscFunctionBegin;
    2755:   PetscCall(PetscObjectReference((PetscObject)snes));
    2756:   PetscCall(SNESDestroy(&ts->snes));

    2758:   ts->snes = snes;

    2760:   PetscCall(SNESSetFunction(ts->snes, NULL, SNESTSFormFunction, ts));
    2761:   PetscCall(SNESGetJacobian(ts->snes, NULL, NULL, &func, NULL));
    2762:   if (func == SNESTSFormJacobian) PetscCall(SNESSetJacobian(ts->snes, NULL, NULL, SNESTSFormJacobian, ts));
    2763:   PetscFunctionReturn(PETSC_SUCCESS);
    2764: }

    2766: /*@
    2767:   TSGetKSP - Returns the `KSP` (linear solver) associated with
    2768:   a `TS` (timestepper) context.

    2770:   Not Collective, but `ksp` is parallel if `ts` is parallel

    2772:   Input Parameter:
    2773: . ts - the `TS` context obtained from `TSCreate()`

    2775:   Output Parameter:
    2776: . ksp - the nonlinear solver context

    2778:   Level: beginner

    2780:   Notes:
    2781:   The user can then directly manipulate the `KSP` context to set various
    2782:   options, etc.  Likewise, the user can then extract and manipulate the
    2783:   `PC` context as well.

    2785:   `TSGetKSP()` does not work for integrators that do not use `KSP`;
    2786:   in this case `TSGetKSP()` returns `NULL` in `ksp`.

    2788: .seealso: [](ch_ts), `TS`, `SNES`, `KSP`, `TSCreate()`, `TSSetUp()`, `TSSolve()`, `TSGetSNES()`
    2789: @*/
    2790: PetscErrorCode TSGetKSP(TS ts, KSP *ksp)
    2791: {
    2792:   SNES snes;

    2794:   PetscFunctionBegin;
    2796:   PetscAssertPointer(ksp, 2);
    2797:   PetscCheck(((PetscObject)ts)->type_name, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "KSP is not created yet. Call TSSetType() first");
    2798:   PetscCheck(ts->problem_type == TS_LINEAR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Linear only; use TSGetSNES()");
    2799:   PetscCall(TSGetSNES(ts, &snes));
    2800:   PetscCall(SNESGetKSP(snes, ksp));
    2801:   PetscFunctionReturn(PETSC_SUCCESS);
    2802: }

    2804: /* ----------- Routines to set solver parameters ---------- */

    2806: /*@
    2807:   TSSetMaxSteps - Sets the maximum number of steps to use.

    2809:   Logically Collective

    2811:   Input Parameters:
    2812: + ts       - the `TS` context obtained from `TSCreate()`
    2813: - maxsteps - maximum number of steps to use

    2815:   Options Database Key:
    2816: . -ts_max_steps maxsteps - Sets maxsteps

    2818:   Level: intermediate

    2820:   Note:
    2821:   Use `PETSC_DETERMINE` to reset the maximum number of steps to the default from when the object's type was set

    2823:   The default maximum number of steps is 5,000

    2825:   Fortran Note:
    2826:   Use `PETSC_DETERMINE_INTEGER`

    2828: .seealso: [](ch_ts), `TS`, `TSGetMaxSteps()`, `TSSetMaxTime()`, `TSSetExactFinalTime()`
    2829: @*/
    2830: PetscErrorCode TSSetMaxSteps(TS ts, PetscInt maxsteps)
    2831: {
    2832:   PetscFunctionBegin;
    2835:   if (maxsteps == PETSC_DETERMINE) {
    2836:     ts->max_steps = ts->default_max_steps;
    2837:   } else {
    2838:     PetscCheck(maxsteps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of steps must be non-negative");
    2839:     ts->max_steps = maxsteps;
    2840:   }
    2841:   PetscFunctionReturn(PETSC_SUCCESS);
    2842: }

    2844: /*@
    2845:   TSGetMaxSteps - Gets the maximum number of steps to use.

    2847:   Not Collective

    2849:   Input Parameter:
    2850: . ts - the `TS` context obtained from `TSCreate()`

    2852:   Output Parameter:
    2853: . maxsteps - maximum number of steps to use

    2855:   Level: advanced

    2857: .seealso: [](ch_ts), `TS`, `TSSetMaxSteps()`, `TSGetMaxTime()`, `TSSetMaxTime()`
    2858: @*/
    2859: PetscErrorCode TSGetMaxSteps(TS ts, PetscInt *maxsteps)
    2860: {
    2861:   PetscFunctionBegin;
    2863:   PetscAssertPointer(maxsteps, 2);
    2864:   *maxsteps = ts->max_steps;
    2865:   PetscFunctionReturn(PETSC_SUCCESS);
    2866: }

    2868: /*@
    2869:   TSSetRunSteps - Sets the maximum number of steps to take in each call to `TSSolve()`.

    2871:   If the step count when `TSSolve()` is `start_step`, this will stop the simulation once `current_step - start_step >= run_steps`.
    2872:   Comparatively, `TSSetMaxSteps()` will stop if `current_step >= max_steps`.
    2873:   The simulation will stop when either condition is reached.

    2875:   Logically Collective

    2877:   Input Parameters:
    2878: + ts       - the `TS` context obtained from `TSCreate()`
    2879: - runsteps - maximum number of steps to take in each call to `TSSolve()`;

    2881:   Options Database Key:
    2882: . -ts_run_steps runsteps - Sets runsteps

    2884:   Level: intermediate

    2886:   Note:
    2887:   The default is `PETSC_UNLIMITED`

    2889: .seealso: [](ch_ts), `TS`, `TSGetRunSteps()`, `TSSetMaxTime()`, `TSSetExactFinalTime()`, `TSSetMaxSteps()`
    2890: @*/
    2891: PetscErrorCode TSSetRunSteps(TS ts, PetscInt runsteps)
    2892: {
    2893:   PetscFunctionBegin;
    2896:   if (runsteps == PETSC_DETERMINE) {
    2897:     ts->run_steps = PETSC_UNLIMITED;
    2898:   } else {
    2899:     PetscCheck(runsteps >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Max number of steps to take in each call to TSSolve must be non-negative");
    2900:     ts->run_steps = runsteps;
    2901:   }
    2902:   PetscFunctionReturn(PETSC_SUCCESS);
    2903: }

    2905: /*@
    2906:   TSGetRunSteps - Gets the maximum number of steps to take in each call to `TSSolve()`.

    2908:   Not Collective

    2910:   Input Parameter:
    2911: . ts - the `TS` context obtained from `TSCreate()`

    2913:   Output Parameter:
    2914: . runsteps - maximum number of steps to take in each call to `TSSolve`.

    2916:   Level: advanced

    2918: .seealso: [](ch_ts), `TS`, `TSSetRunSteps()`, `TSGetMaxTime()`, `TSSetMaxTime()`, `TSGetMaxSteps()`
    2919: @*/
    2920: PetscErrorCode TSGetRunSteps(TS ts, PetscInt *runsteps)
    2921: {
    2922:   PetscFunctionBegin;
    2924:   PetscAssertPointer(runsteps, 2);
    2925:   *runsteps = ts->run_steps;
    2926:   PetscFunctionReturn(PETSC_SUCCESS);
    2927: }

    2929: /*@
    2930:   TSSetMaxTime - Sets the maximum (or final) time for timestepping.

    2932:   Logically Collective

    2934:   Input Parameters:
    2935: + ts      - the `TS` context obtained from `TSCreate()`
    2936: - maxtime - final time to step to

    2938:   Options Database Key:
    2939: . -ts_max_time maxtime - Sets maxtime

    2941:   Level: intermediate

    2943:   Notes:
    2944:   Use `PETSC_DETERMINE` to reset the maximum time to the default from when the object's type was set

    2946:   The default maximum time is 5.0

    2948:   Fortran Note:
    2949:   Use `PETSC_DETERMINE_REAL`

    2951: .seealso: [](ch_ts), `TS`, `TSGetMaxTime()`, `TSSetMaxSteps()`, `TSSetExactFinalTime()`
    2952: @*/
    2953: PetscErrorCode TSSetMaxTime(TS ts, PetscReal maxtime)
    2954: {
    2955:   PetscFunctionBegin;
    2958:   if (maxtime == PETSC_DETERMINE) {
    2959:     ts->max_time = ts->default_max_time;
    2960:   } else {
    2961:     ts->max_time = maxtime;
    2962:   }
    2963:   PetscFunctionReturn(PETSC_SUCCESS);
    2964: }

    2966: /*@
    2967:   TSGetMaxTime - Gets the maximum (or final) time for timestepping.

    2969:   Not Collective

    2971:   Input Parameter:
    2972: . ts - the `TS` context obtained from `TSCreate()`

    2974:   Output Parameter:
    2975: . maxtime - final time to step to

    2977:   Level: advanced

    2979: .seealso: [](ch_ts), `TS`, `TSSetMaxTime()`, `TSGetMaxSteps()`, `TSSetMaxSteps()`
    2980: @*/
    2981: PetscErrorCode TSGetMaxTime(TS ts, PetscReal *maxtime)
    2982: {
    2983:   PetscFunctionBegin;
    2985:   PetscAssertPointer(maxtime, 2);
    2986:   *maxtime = ts->max_time;
    2987:   PetscFunctionReturn(PETSC_SUCCESS);
    2988: }

    2990: // PetscClangLinter pragma disable: -fdoc-*
    2991: /*@
    2992:   TSSetInitialTimeStep - Deprecated, use `TSSetTime()` and `TSSetTimeStep()`.

    2994:   Level: deprecated

    2996: @*/
    2997: PetscErrorCode TSSetInitialTimeStep(TS ts, PetscReal initial_time, PetscReal time_step)
    2998: {
    2999:   PetscFunctionBegin;
    3001:   PetscCall(TSSetTime(ts, initial_time));
    3002:   PetscCall(TSSetTimeStep(ts, time_step));
    3003:   PetscFunctionReturn(PETSC_SUCCESS);
    3004: }

    3006: // PetscClangLinter pragma disable: -fdoc-*
    3007: /*@
    3008:   TSGetDuration - Deprecated, use `TSGetMaxSteps()` and `TSGetMaxTime()`.

    3010:   Level: deprecated

    3012: @*/
    3013: PetscErrorCode TSGetDuration(TS ts, PetscInt *maxsteps, PetscReal *maxtime)
    3014: {
    3015:   PetscFunctionBegin;
    3017:   if (maxsteps) {
    3018:     PetscAssertPointer(maxsteps, 2);
    3019:     *maxsteps = ts->max_steps;
    3020:   }
    3021:   if (maxtime) {
    3022:     PetscAssertPointer(maxtime, 3);
    3023:     *maxtime = ts->max_time;
    3024:   }
    3025:   PetscFunctionReturn(PETSC_SUCCESS);
    3026: }

    3028: // PetscClangLinter pragma disable: -fdoc-*
    3029: /*@
    3030:   TSSetDuration - Deprecated, use `TSSetMaxSteps()` and `TSSetMaxTime()`.

    3032:   Level: deprecated

    3034: @*/
    3035: PetscErrorCode TSSetDuration(TS ts, PetscInt maxsteps, PetscReal maxtime)
    3036: {
    3037:   PetscFunctionBegin;
    3038:   if (maxsteps != PETSC_CURRENT) PetscCall(TSSetMaxSteps(ts, maxsteps));
    3039:   if (maxtime != (PetscReal)PETSC_CURRENT) PetscCall(TSSetMaxTime(ts, maxtime));
    3040:   PetscFunctionReturn(PETSC_SUCCESS);
    3041: }

    3043: // PetscClangLinter pragma disable: -fdoc-*
    3044: /*@
    3045:   TSGetTimeStepNumber - Deprecated, use `TSGetStepNumber()`.

    3047:   Level: deprecated

    3049: @*/
    3050: PetscErrorCode TSGetTimeStepNumber(TS ts, PetscInt *steps)
    3051: {
    3052:   return TSGetStepNumber(ts, steps);
    3053: }

    3055: // PetscClangLinter pragma disable: -fdoc-*
    3056: /*@
    3057:   TSGetTotalSteps - Deprecated, use `TSGetStepNumber()`.

    3059:   Level: deprecated

    3061: @*/
    3062: PetscErrorCode TSGetTotalSteps(TS ts, PetscInt *steps)
    3063: {
    3064:   return TSGetStepNumber(ts, steps);
    3065: }

    3067: /*@
    3068:   TSSetSolution - Sets the initial solution vector
    3069:   for use by the `TS` routines.

    3071:   Logically Collective

    3073:   Input Parameters:
    3074: + ts - the `TS` context obtained from `TSCreate()`
    3075: - u  - the solution vector

    3077:   Level: beginner

    3079: .seealso: [](ch_ts), `TS`, `TSSetSolutionFunction()`, `TSGetSolution()`, `TSCreate()`
    3080: @*/
    3081: PetscErrorCode TSSetSolution(TS ts, Vec u)
    3082: {
    3083:   DM dm;

    3085:   PetscFunctionBegin;
    3088:   PetscCall(PetscObjectReference((PetscObject)u));
    3089:   PetscCall(VecDestroy(&ts->vec_sol));
    3090:   ts->vec_sol = u;

    3092:   PetscCall(TSGetDM(ts, &dm));
    3093:   PetscCall(DMShellSetGlobalVector(dm, u));
    3094:   PetscFunctionReturn(PETSC_SUCCESS);
    3095: }

    3097: /*@C
    3098:   TSSetPreStep - Sets the general-purpose function
    3099:   called once at the beginning of each time step.

    3101:   Logically Collective

    3103:   Input Parameters:
    3104: + ts   - The `TS` context obtained from `TSCreate()`
    3105: - func - The function

    3107:   Calling sequence of `func`:
    3108: . ts - the `TS` context

    3110:   Level: intermediate

    3112: .seealso: [](ch_ts), `TS`, `TSSetPreStage()`, `TSSetPostStage()`, `TSSetPostStep()`, `TSStep()`, `TSRestartStep()`
    3113: @*/
    3114: PetscErrorCode TSSetPreStep(TS ts, PetscErrorCode (*func)(TS ts))
    3115: {
    3116:   PetscFunctionBegin;
    3118:   ts->prestep = func;
    3119:   PetscFunctionReturn(PETSC_SUCCESS);
    3120: }

    3122: /*@
    3123:   TSPreStep - Runs the user-defined pre-step function provided with `TSSetPreStep()`

    3125:   Collective

    3127:   Input Parameter:
    3128: . ts - The `TS` context obtained from `TSCreate()`

    3130:   Level: developer

    3132:   Note:
    3133:   `TSPreStep()` is typically used within time stepping implementations,
    3134:   so most users would not generally call this routine themselves.

    3136: .seealso: [](ch_ts), `TS`, `TSSetPreStep()`, `TSPreStage()`, `TSPostStage()`, `TSPostStep()`
    3137: @*/
    3138: PetscErrorCode TSPreStep(TS ts)
    3139: {
    3140:   PetscFunctionBegin;
    3142:   if (ts->prestep) {
    3143:     Vec              U;
    3144:     PetscObjectId    idprev;
    3145:     PetscBool        sameObject;
    3146:     PetscObjectState sprev, spost;

    3148:     PetscCall(TSGetSolution(ts, &U));
    3149:     PetscCall(PetscObjectGetId((PetscObject)U, &idprev));
    3150:     PetscCall(PetscObjectStateGet((PetscObject)U, &sprev));
    3151:     PetscCallBack("TS callback preset", (*ts->prestep)(ts));
    3152:     PetscCall(TSGetSolution(ts, &U));
    3153:     PetscCall(PetscObjectCompareId((PetscObject)U, idprev, &sameObject));
    3154:     PetscCall(PetscObjectStateGet((PetscObject)U, &spost));
    3155:     if (!sameObject || sprev != spost) PetscCall(TSRestartStep(ts));
    3156:   }
    3157:   PetscFunctionReturn(PETSC_SUCCESS);
    3158: }

    3160: /*@C
    3161:   TSSetPreStage - Sets the general-purpose function
    3162:   called once at the beginning of each stage.

    3164:   Logically Collective

    3166:   Input Parameters:
    3167: + ts   - The `TS` context obtained from `TSCreate()`
    3168: - func - The function

    3170:   Calling sequence of `func`:
    3171: + ts        - the `TS` context
    3172: - stagetime - the stage time

    3174:   Level: intermediate

    3176:   Note:
    3177:   There may be several stages per time step. If the solve for a given stage fails, the step may be rejected and retried.
    3178:   The time step number being computed can be queried using `TSGetStepNumber()` and the total size of the step being
    3179:   attempted can be obtained using `TSGetTimeStep()`. The time at the start of the step is available via `TSGetTime()`.

    3181: .seealso: [](ch_ts), `TS`, `TSSetPostStage()`, `TSSetPreStep()`, `TSSetPostStep()`, `TSGetApplicationContext()`
    3182: @*/
    3183: PetscErrorCode TSSetPreStage(TS ts, PetscErrorCode (*func)(TS ts, PetscReal stagetime))
    3184: {
    3185:   PetscFunctionBegin;
    3187:   ts->prestage = func;
    3188:   PetscFunctionReturn(PETSC_SUCCESS);
    3189: }

    3191: /*@C
    3192:   TSSetPostStage - Sets the general-purpose function
    3193:   called once at the end of each stage.

    3195:   Logically Collective

    3197:   Input Parameters:
    3198: + ts   - The `TS` context obtained from `TSCreate()`
    3199: - func - The function

    3201:   Calling sequence of `func`:
    3202: + ts         - the `TS` context
    3203: . stagetime  - the stage time
    3204: . stageindex - the stage index
    3205: - Y          - Array of vectors (of size = total number of stages) with the stage solutions

    3207:   Level: intermediate

    3209:   Note:
    3210:   There may be several stages per time step. If the solve for a given stage fails, the step may be rejected and retried.
    3211:   The time step number being computed can be queried using `TSGetStepNumber()` and the total size of the step being
    3212:   attempted can be obtained using `TSGetTimeStep()`. The time at the start of the step is available via `TSGetTime()`.

    3214: .seealso: [](ch_ts), `TS`, `TSSetPreStage()`, `TSSetPreStep()`, `TSSetPostStep()`, `TSGetApplicationContext()`
    3215: @*/
    3216: PetscErrorCode TSSetPostStage(TS ts, PetscErrorCode (*func)(TS ts, PetscReal stagetime, PetscInt stageindex, Vec *Y))
    3217: {
    3218:   PetscFunctionBegin;
    3220:   ts->poststage = func;
    3221:   PetscFunctionReturn(PETSC_SUCCESS);
    3222: }

    3224: /*@C
    3225:   TSSetPostEvaluate - Sets the general-purpose function
    3226:   called at the end of each step evaluation.

    3228:   Logically Collective

    3230:   Input Parameters:
    3231: + ts   - The `TS` context obtained from `TSCreate()`
    3232: - func - The function

    3234:   Calling sequence of `func`:
    3235: . ts - the `TS` context

    3237:   Level: intermediate

    3239:   Note:
    3240:   The function set by `TSSetPostEvaluate()` is called after the solution is evaluated, or after the step rollback.
    3241:   Inside the `func` callback, the solution vector can be obtained with `TSGetSolution()`, and modified, if need be.
    3242:   The time step can be obtained with `TSGetTimeStep()`, and the time at the start of the step - via `TSGetTime()`.
    3243:   The potential changes to the solution vector introduced by event handling (`postevent()`) are not relevant for `TSSetPostEvaluate()`,
    3244:   but are relevant for `TSSetPostStep()`, according to the function call scheme in `TSSolve()`, as shown below
    3245: .vb
    3246:   ...
    3247:   Step()
    3248:   PostEvaluate()
    3249:   EventHandling()
    3250:   step_rollback ? PostEvaluate() : PostStep()
    3251:   ...
    3252: .ve
    3253:   where EventHandling() may result in one of the following three outcomes
    3254: .vb
    3255:   (1) | successful step | solution intact
    3256:   (2) | successful step | solution modified by `postevent()`
    3257:   (3) | step_rollback   | solution rolled back
    3258: .ve

    3260: .seealso: [](ch_ts), `TS`, `TSSetPreStage()`, `TSSetPreStep()`, `TSSetPostStep()`, `TSGetApplicationContext()`
    3261: @*/
    3262: PetscErrorCode TSSetPostEvaluate(TS ts, PetscErrorCode (*func)(TS ts))
    3263: {
    3264:   PetscFunctionBegin;
    3266:   ts->postevaluate = func;
    3267:   PetscFunctionReturn(PETSC_SUCCESS);
    3268: }

    3270: /*@
    3271:   TSPreStage - Runs the user-defined pre-stage function set using `TSSetPreStage()`

    3273:   Collective

    3275:   Input Parameters:
    3276: + ts        - The `TS` context obtained from `TSCreate()`
    3277: - stagetime - The absolute time of the current stage

    3279:   Level: developer

    3281:   Note:
    3282:   `TSPreStage()` is typically used within time stepping implementations,
    3283:   most users would not generally call this routine themselves.

    3285: .seealso: [](ch_ts), `TS`, `TSPostStage()`, `TSSetPreStep()`, `TSPreStep()`, `TSPostStep()`
    3286: @*/
    3287: PetscErrorCode TSPreStage(TS ts, PetscReal stagetime)
    3288: {
    3289:   PetscFunctionBegin;
    3291:   if (ts->prestage) PetscCallBack("TS callback prestage", (*ts->prestage)(ts, stagetime));
    3292:   PetscFunctionReturn(PETSC_SUCCESS);
    3293: }

    3295: /*@
    3296:   TSPostStage - Runs the user-defined post-stage function set using `TSSetPostStage()`

    3298:   Collective

    3300:   Input Parameters:
    3301: + ts         - The `TS` context obtained from `TSCreate()`
    3302: . stagetime  - The absolute time of the current stage
    3303: . stageindex - Stage number
    3304: - Y          - Array of vectors (of size = total number of stages) with the stage solutions

    3306:   Level: developer

    3308:   Note:
    3309:   `TSPostStage()` is typically used within time stepping implementations,
    3310:   most users would not generally call this routine themselves.

    3312: .seealso: [](ch_ts), `TS`, `TSPreStage()`, `TSSetPreStep()`, `TSPreStep()`, `TSPostStep()`
    3313: @*/
    3314: PetscErrorCode TSPostStage(TS ts, PetscReal stagetime, PetscInt stageindex, Vec Y[])
    3315: {
    3316:   PetscFunctionBegin;
    3318:   if (ts->poststage) PetscCallBack("TS callback poststage", (*ts->poststage)(ts, stagetime, stageindex, Y));
    3319:   PetscFunctionReturn(PETSC_SUCCESS);
    3320: }

    3322: /*@
    3323:   TSPostEvaluate - Runs the user-defined post-evaluate function set using `TSSetPostEvaluate()`

    3325:   Collective

    3327:   Input Parameter:
    3328: . ts - The `TS` context obtained from `TSCreate()`

    3330:   Level: developer

    3332:   Note:
    3333:   `TSPostEvaluate()` is typically used within time stepping implementations,
    3334:   most users would not generally call this routine themselves.

    3336: .seealso: [](ch_ts), `TS`, `TSSetPostEvaluate()`, `TSSetPreStep()`, `TSPreStep()`, `TSPostStep()`
    3337: @*/
    3338: PetscErrorCode TSPostEvaluate(TS ts)
    3339: {
    3340:   PetscFunctionBegin;
    3342:   if (ts->postevaluate) {
    3343:     Vec              U;
    3344:     PetscObjectState sprev, spost;

    3346:     PetscCall(TSGetSolution(ts, &U));
    3347:     PetscCall(PetscObjectStateGet((PetscObject)U, &sprev));
    3348:     PetscCallBack("TS callback postevaluate", (*ts->postevaluate)(ts));
    3349:     PetscCall(PetscObjectStateGet((PetscObject)U, &spost));
    3350:     if (sprev != spost) PetscCall(TSRestartStep(ts));
    3351:   }
    3352:   PetscFunctionReturn(PETSC_SUCCESS);
    3353: }

    3355: /*@C
    3356:   TSSetPostStep - Sets the general-purpose function
    3357:   called once at the end of each successful time step.

    3359:   Logically Collective

    3361:   Input Parameters:
    3362: + ts   - The `TS` context obtained from `TSCreate()`
    3363: - func - The function

    3365:   Calling sequence of `func`:
    3366: . ts - the `TS` context

    3368:   Level: intermediate

    3370:   Note:
    3371:   The function set by `TSSetPostStep()` is called after each successful step. If the event handler locates an event at the
    3372:   given step, and `postevent()` modifies the solution vector, the solution vector obtained by `TSGetSolution()` inside `func` will
    3373:   contain the changes. To get the solution without these changes, use `TSSetPostEvaluate()` to set the appropriate callback.
    3374:   The scheme of the relevant function calls in `TSSolve()` is shown below
    3375: .vb
    3376:   ...
    3377:   Step()
    3378:   PostEvaluate()
    3379:   EventHandling()
    3380:   step_rollback ? PostEvaluate() : PostStep()
    3381:   ...
    3382: .ve
    3383:   where EventHandling() may result in one of the following three outcomes
    3384: .vb
    3385:   (1) | successful step | solution intact
    3386:   (2) | successful step | solution modified by `postevent()`
    3387:   (3) | step_rollback   | solution rolled back
    3388: .ve

    3390: .seealso: [](ch_ts), `TS`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostEvaluate()`, `TSGetTimeStep()`, `TSGetStepNumber()`, `TSGetTime()`, `TSRestartStep()`
    3391: @*/
    3392: PetscErrorCode TSSetPostStep(TS ts, PetscErrorCode (*func)(TS ts))
    3393: {
    3394:   PetscFunctionBegin;
    3396:   ts->poststep = func;
    3397:   PetscFunctionReturn(PETSC_SUCCESS);
    3398: }

    3400: /*@
    3401:   TSPostStep - Runs the user-defined post-step function that was set with `TSSetPostStep()`

    3403:   Collective

    3405:   Input Parameter:
    3406: . ts - The `TS` context obtained from `TSCreate()`

    3408:   Note:
    3409:   `TSPostStep()` is typically used within time stepping implementations,
    3410:   so most users would not generally call this routine themselves.

    3412:   Level: developer

    3414: .seealso: [](ch_ts), `TS`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostEvaluate()`, `TSGetTimeStep()`, `TSGetStepNumber()`, `TSGetTime()`, `TSSetPostStep()`
    3415: @*/
    3416: PetscErrorCode TSPostStep(TS ts)
    3417: {
    3418:   PetscFunctionBegin;
    3420:   if (ts->poststep) {
    3421:     Vec              U;
    3422:     PetscObjectId    idprev;
    3423:     PetscBool        sameObject;
    3424:     PetscObjectState sprev, spost;

    3426:     PetscCall(TSGetSolution(ts, &U));
    3427:     PetscCall(PetscObjectGetId((PetscObject)U, &idprev));
    3428:     PetscCall(PetscObjectStateGet((PetscObject)U, &sprev));
    3429:     PetscCallBack("TS callback poststep", (*ts->poststep)(ts));
    3430:     PetscCall(TSGetSolution(ts, &U));
    3431:     PetscCall(PetscObjectCompareId((PetscObject)U, idprev, &sameObject));
    3432:     PetscCall(PetscObjectStateGet((PetscObject)U, &spost));
    3433:     if (!sameObject || sprev != spost) PetscCall(TSRestartStep(ts));
    3434:   }
    3435:   PetscFunctionReturn(PETSC_SUCCESS);
    3436: }

    3438: /*@
    3439:   TSInterpolate - Interpolate the solution computed during the previous step to an arbitrary location in the interval

    3441:   Collective

    3443:   Input Parameters:
    3444: + ts - time stepping context
    3445: - t  - time to interpolate to

    3447:   Output Parameter:
    3448: . U - state at given time

    3450:   Level: intermediate

    3452:   Developer Notes:
    3453:   `TSInterpolate()` and the storing of previous steps/stages should be generalized to support delay differential equations and continuous adjoints.

    3455: .seealso: [](ch_ts), `TS`, `TSSetExactFinalTime()`, `TSSolve()`
    3456: @*/
    3457: PetscErrorCode TSInterpolate(TS ts, PetscReal t, Vec U)
    3458: {
    3459:   PetscFunctionBegin;
    3462:   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);
    3463:   PetscUseTypeMethod(ts, interpolate, t, U);
    3464:   PetscFunctionReturn(PETSC_SUCCESS);
    3465: }

    3467: /*@
    3468:   TSStep - Steps one time step

    3470:   Collective

    3472:   Input Parameter:
    3473: . ts - the `TS` context obtained from `TSCreate()`

    3475:   Level: developer

    3477:   Notes:
    3478:   The public interface for the ODE/DAE solvers is `TSSolve()`, you should almost for sure be using that routine and not this routine.

    3480:   The hook set using `TSSetPreStep()` is called before each attempt to take the step. In general, the time step size may
    3481:   be changed due to adaptive error controller or solve failures. Note that steps may contain multiple stages.

    3483:   This may over-step the final time provided in `TSSetMaxTime()` depending on the time-step used. `TSSolve()` interpolates to exactly the
    3484:   time provided in `TSSetMaxTime()`. One can use `TSInterpolate()` to determine an interpolated solution within the final timestep.

    3486: .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetUp()`, `TSDestroy()`, `TSSolve()`, `TSSetPreStep()`, `TSSetPreStage()`, `TSSetPostStage()`, `TSInterpolate()`
    3487: @*/
    3488: PetscErrorCode TSStep(TS ts)
    3489: {
    3490:   static PetscBool cite = PETSC_FALSE;
    3491:   PetscReal        ptime;

    3493:   PetscFunctionBegin;
    3495:   PetscCall(PetscCitationsRegister("@article{tspaper,\n"
    3496:                                    "  title         = {{PETSc/TS}: A Modern Scalable {DAE/ODE} Solver Library},\n"
    3497:                                    "  author        = {Abhyankar, Shrirang and Brown, Jed and Constantinescu, Emil and Ghosh, Debojyoti and Smith, Barry F. and Zhang, Hong},\n"
    3498:                                    "  journal       = {arXiv e-preprints},\n"
    3499:                                    "  eprint        = {1806.01437},\n"
    3500:                                    "  archivePrefix = {arXiv},\n"
    3501:                                    "  year          = {2018}\n}\n",
    3502:                                    &cite));
    3503:   PetscCall(TSSetUp(ts));
    3504:   PetscCall(TSTrajectorySetUp(ts->trajectory, ts));
    3505:   if (ts->eval_times)
    3506:     ts->eval_times->worktol = 0; /* In each step of TSSolve() 'eval_times->worktol' will be meaningfully defined (later) only once:
    3507:                                                    in TSAdaptChoose() or TSEvent_dt_cap(), and then reused till the end of the step */

    3509:   PetscCheck(ts->max_time < PETSC_MAX_REAL || ts->run_steps != PETSC_INT_MAX || ts->max_steps != PETSC_INT_MAX, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "You must call TSSetMaxTime(), TSSetMaxSteps(), or TSSetRunSteps() or use -ts_max_time <time>, -ts_max_steps <steps>, -ts_run_steps <steps>");
    3510:   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()");
    3511:   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");

    3513:   if (!ts->vec_sol0) PetscCall(VecDuplicate(ts->vec_sol, &ts->vec_sol0));
    3514:   PetscCall(VecCopy(ts->vec_sol, ts->vec_sol0));
    3515:   ts->time_step0 = ts->time_step;

    3517:   if (!ts->steps) ts->ptime_prev = ts->ptime;
    3518:   ptime = ts->ptime;

    3520:   ts->ptime_prev_rollback = ts->ptime_prev;
    3521:   ts->reason              = TS_CONVERGED_ITERATING;

    3523:   PetscCall(PetscLogEventBegin(TS_Step, ts, 0, 0, 0));
    3524:   PetscUseTypeMethod(ts, step);
    3525:   PetscCall(PetscLogEventEnd(TS_Step, ts, 0, 0, 0));

    3527:   if (ts->reason >= 0) {
    3528:     ts->ptime_prev = ptime;
    3529:     ts->steps++;
    3530:     ts->steprollback = PETSC_FALSE;
    3531:     ts->steprestart  = PETSC_FALSE;
    3532:     ts->stepresize   = PETSC_FALSE;
    3533:   }

    3535:   if (ts->reason < 0 && ts->errorifstepfailed) {
    3536:     PetscCall(TSMonitorCancel(ts));
    3537:     if (ts->usessnes && ts->snes) PetscCall(SNESMonitorCancel(ts->snes));
    3538:     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 use unlimited to attempt recovery", TSConvergedReasons[ts->reason]);
    3539:     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_NOT_CONVERGED, "TSStep has failed due to %s", TSConvergedReasons[ts->reason]);
    3540:   }
    3541:   PetscFunctionReturn(PETSC_SUCCESS);
    3542: }

    3544: /*@
    3545:   TSEvaluateWLTE - Evaluate the weighted local truncation error norm
    3546:   at the end of a time step with a given order of accuracy.

    3548:   Collective

    3550:   Input Parameters:
    3551: + ts        - time stepping context
    3552: - wnormtype - norm type, either `NORM_2` or `NORM_INFINITY`

    3554:   Input/Output Parameter:
    3555: . order - optional, desired order for the error evaluation or `PETSC_DECIDE`;
    3556:            on output, the actual order of the error evaluation

    3558:   Output Parameter:
    3559: . wlte - the weighted local truncation error norm

    3561:   Level: advanced

    3563:   Note:
    3564:   If the timestepper cannot evaluate the error in a particular step
    3565:   (eg. in the first step or restart steps after event handling),
    3566:   this routine returns wlte=-1.0 .

    3568: .seealso: [](ch_ts), `TS`, `TSStep()`, `TSAdapt`, `TSErrorWeightedNorm()`
    3569: @*/
    3570: PetscErrorCode TSEvaluateWLTE(TS ts, NormType wnormtype, PetscInt *order, PetscReal *wlte)
    3571: {
    3572:   PetscFunctionBegin;
    3576:   if (order) PetscAssertPointer(order, 3);
    3578:   PetscAssertPointer(wlte, 4);
    3579:   PetscCheck(wnormtype == NORM_2 || wnormtype == NORM_INFINITY, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "No support for norm type %s", NormTypes[wnormtype]);
    3580:   PetscUseTypeMethod(ts, evaluatewlte, wnormtype, order, wlte);
    3581:   PetscFunctionReturn(PETSC_SUCCESS);
    3582: }

    3584: /*@
    3585:   TSEvaluateStep - Evaluate the solution at the end of a time step with a given order of accuracy.

    3587:   Collective

    3589:   Input Parameters:
    3590: + ts    - time stepping context
    3591: . order - desired order of accuracy
    3592: - done  - whether the step was evaluated at this order (pass `NULL` to generate an error if not available)

    3594:   Output Parameter:
    3595: . U - state at the end of the current step

    3597:   Level: advanced

    3599:   Notes:
    3600:   This function cannot be called until all stages have been evaluated.

    3602:   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.

    3604: .seealso: [](ch_ts), `TS`, `TSStep()`, `TSAdapt`
    3605: @*/
    3606: PetscErrorCode TSEvaluateStep(TS ts, PetscInt order, Vec U, PetscBool *done)
    3607: {
    3608:   PetscFunctionBegin;
    3612:   PetscUseTypeMethod(ts, evaluatestep, order, U, done);
    3613:   PetscFunctionReturn(PETSC_SUCCESS);
    3614: }

    3616: /*@C
    3617:   TSGetComputeInitialCondition - Get the function used to automatically compute an initial condition for the timestepping.

    3619:   Not collective

    3621:   Input Parameter:
    3622: . ts - time stepping context

    3624:   Output Parameter:
    3625: . initCondition - The function which computes an initial condition

    3627:   Calling sequence of `initCondition`:
    3628: + ts - The timestepping context
    3629: - u  - The input vector in which the initial condition is stored

    3631:   Level: advanced

    3633: .seealso: [](ch_ts), `TS`, `TSSetComputeInitialCondition()`, `TSComputeInitialCondition()`
    3634: @*/
    3635: PetscErrorCode TSGetComputeInitialCondition(TS ts, PetscErrorCode (**initCondition)(TS ts, Vec u))
    3636: {
    3637:   PetscFunctionBegin;
    3639:   PetscAssertPointer(initCondition, 2);
    3640:   *initCondition = ts->ops->initcondition;
    3641:   PetscFunctionReturn(PETSC_SUCCESS);
    3642: }

    3644: /*@C
    3645:   TSSetComputeInitialCondition - Set the function used to automatically compute an initial condition for the timestepping.

    3647:   Logically collective

    3649:   Input Parameters:
    3650: + ts            - time stepping context
    3651: - initCondition - The function which computes an initial condition

    3653:   Calling sequence of `initCondition`:
    3654: + ts - The timestepping context
    3655: - e  - The input vector in which the initial condition is to be stored

    3657:   Level: advanced

    3659: .seealso: [](ch_ts), `TS`, `TSGetComputeInitialCondition()`, `TSComputeInitialCondition()`
    3660: @*/
    3661: PetscErrorCode TSSetComputeInitialCondition(TS ts, PetscErrorCode (*initCondition)(TS ts, Vec e))
    3662: {
    3663:   PetscFunctionBegin;
    3666:   ts->ops->initcondition = initCondition;
    3667:   PetscFunctionReturn(PETSC_SUCCESS);
    3668: }

    3670: /*@
    3671:   TSComputeInitialCondition - Compute an initial condition for the timestepping using the function previously set with `TSSetComputeInitialCondition()`

    3673:   Collective

    3675:   Input Parameters:
    3676: + ts - time stepping context
    3677: - u  - The `Vec` to store the condition in which will be used in `TSSolve()`

    3679:   Level: advanced

    3681: .seealso: [](ch_ts), `TS`, `TSGetComputeInitialCondition()`, `TSSetComputeInitialCondition()`, `TSSolve()`
    3682: @*/
    3683: PetscErrorCode TSComputeInitialCondition(TS ts, Vec u)
    3684: {
    3685:   PetscFunctionBegin;
    3688:   PetscTryTypeMethod(ts, initcondition, u);
    3689:   PetscFunctionReturn(PETSC_SUCCESS);
    3690: }

    3692: /*@C
    3693:   TSGetComputeExactError - Get the function used to automatically compute the exact error for the timestepping.

    3695:   Not collective

    3697:   Input Parameter:
    3698: . ts - time stepping context

    3700:   Output Parameter:
    3701: . exactError - The function which computes the solution error

    3703:   Calling sequence of `exactError`:
    3704: + ts - The timestepping context
    3705: . u  - The approximate solution vector
    3706: - e  - The vector in which the error is stored

    3708:   Level: advanced

    3710: .seealso: [](ch_ts), `TS`, `TSComputeExactError()`
    3711: @*/
    3712: PetscErrorCode TSGetComputeExactError(TS ts, PetscErrorCode (**exactError)(TS ts, Vec u, Vec e))
    3713: {
    3714:   PetscFunctionBegin;
    3716:   PetscAssertPointer(exactError, 2);
    3717:   *exactError = ts->ops->exacterror;
    3718:   PetscFunctionReturn(PETSC_SUCCESS);
    3719: }

    3721: /*@C
    3722:   TSSetComputeExactError - Set the function used to automatically compute the exact error for the timestepping.

    3724:   Logically collective

    3726:   Input Parameters:
    3727: + ts         - time stepping context
    3728: - exactError - The function which computes the solution error

    3730:   Calling sequence of `exactError`:
    3731: + ts - The timestepping context
    3732: . u  - The approximate solution vector
    3733: - e  - The  vector in which the error is stored

    3735:   Level: advanced

    3737: .seealso: [](ch_ts), `TS`, `TSGetComputeExactError()`, `TSComputeExactError()`
    3738: @*/
    3739: PetscErrorCode TSSetComputeExactError(TS ts, PetscErrorCode (*exactError)(TS ts, Vec u, Vec e))
    3740: {
    3741:   PetscFunctionBegin;
    3744:   ts->ops->exacterror = exactError;
    3745:   PetscFunctionReturn(PETSC_SUCCESS);
    3746: }

    3748: /*@
    3749:   TSComputeExactError - Compute the solution error for the timestepping using the function previously set with `TSSetComputeExactError()`

    3751:   Collective

    3753:   Input Parameters:
    3754: + ts - time stepping context
    3755: . u  - The approximate solution
    3756: - e  - The `Vec` used to store the error

    3758:   Level: advanced

    3760: .seealso: [](ch_ts), `TS`, `TSGetComputeInitialCondition()`, `TSSetComputeInitialCondition()`, `TSSolve()`
    3761: @*/
    3762: PetscErrorCode TSComputeExactError(TS ts, Vec u, Vec e)
    3763: {
    3764:   PetscFunctionBegin;
    3768:   PetscTryTypeMethod(ts, exacterror, u, e);
    3769:   PetscFunctionReturn(PETSC_SUCCESS);
    3770: }

    3772: /*@C
    3773:   TSSetResize - Sets the resize callbacks.

    3775:   Logically Collective

    3777:   Input Parameters:
    3778: + ts       - The `TS` context obtained from `TSCreate()`
    3779: . rollback - Whether a resize will restart the step
    3780: . setup    - The setup function
    3781: . transfer - The transfer function
    3782: - ctx      - [optional] The user-defined context

    3784:   Calling sequence of `setup`:
    3785: + ts     - the `TS` context
    3786: . step   - the current step
    3787: . time   - the current time
    3788: . state  - the current vector of state
    3789: . resize - (output parameter) `PETSC_TRUE` if need resizing, `PETSC_FALSE` otherwise
    3790: - ctx    - user defined context

    3792:   Calling sequence of `transfer`:
    3793: + ts      - the `TS` context
    3794: . nv      - the number of vectors to be transferred
    3795: . vecsin  - array of vectors to be transferred
    3796: . vecsout - array of transferred vectors
    3797: - ctx     - user defined context

    3799:   Notes:
    3800:   The `setup` function is called inside `TSSolve()` after `TSEventHandler()` or after `TSPostStep()`
    3801:   depending on the `rollback` value: if `rollback` is true, then these callbacks behave as error indicators
    3802:   and will flag the need to remesh and restart the current step. Otherwise, they will simply flag the solver
    3803:   that the size of the discrete problem has changed.
    3804:   In both cases, the solver will collect the needed vectors that will be
    3805:   transferred from the old to the new sizes using the `transfer` callback. These vectors will include the
    3806:   current solution vector, and other vectors needed by the specific solver used.
    3807:   For example, `TSBDF` uses previous solutions vectors to solve for the next time step.
    3808:   Other application specific objects associated with the solver, i.e. Jacobian matrices and `DM`,
    3809:   will be automatically reset if the sizes are changed and they must be specified again by the user
    3810:   inside the `transfer` function.
    3811:   The input and output arrays passed to `transfer` are allocated by PETSc.
    3812:   Vectors in `vecsout` must be created by the user.
    3813:   Ownership of vectors in `vecsout` is transferred to PETSc.

    3815:   Level: advanced

    3817: .seealso: [](ch_ts), `TS`, `TSSetDM()`, `TSSetIJacobian()`, `TSSetRHSJacobian()`
    3818: @*/
    3819: PetscErrorCode TSSetResize(TS ts, PetscBool rollback, PetscErrorCode (*setup)(TS ts, PetscInt step, PetscReal time, Vec state, PetscBool *resize, PetscCtx ctx), PetscErrorCode (*transfer)(TS ts, PetscInt nv, Vec vecsin[], Vec vecsout[], PetscCtx ctx), PetscCtx ctx)
    3820: {
    3821:   PetscFunctionBegin;
    3823:   ts->resizerollback = rollback;
    3824:   ts->resizesetup    = setup;
    3825:   ts->resizetransfer = transfer;
    3826:   ts->resizectx      = ctx;
    3827:   PetscFunctionReturn(PETSC_SUCCESS);
    3828: }

    3830: /*
    3831:   TSResizeRegisterOrRetrieve - Register or import vectors transferred with `TSResize()`.

    3833:   Collective

    3835:   Input Parameters:
    3836: + ts   - The `TS` context obtained from `TSCreate()`
    3837: - flg - If `PETSC_TRUE` each TS implementation (e.g. `TSBDF`) will register vectors to be transferred, if `PETSC_FALSE` vectors will be imported from transferred vectors.

    3839:   Level: developer

    3841:   Note:
    3842:   `TSResizeRegisterOrRetrieve()` is declared PETSC_INTERN since it is
    3843:    used within time stepping implementations,
    3844:    so most users would not generally call this routine themselves.

    3846: .seealso: [](ch_ts), `TS`, `TSSetResize()`
    3847: @*/
    3848: static PetscErrorCode TSResizeRegisterOrRetrieve(TS ts, PetscBool flg)
    3849: {
    3850:   PetscFunctionBegin;
    3852:   PetscTryTypeMethod(ts, resizeregister, flg);
    3853:   /* PetscTryTypeMethod(adapt, resizeregister, flg); */
    3854:   PetscFunctionReturn(PETSC_SUCCESS);
    3855: }

    3857: static PetscErrorCode TSResizeReset(TS ts)
    3858: {
    3859:   PetscFunctionBegin;
    3861:   PetscCall(PetscObjectListDestroy(&ts->resizetransferobjs));
    3862:   PetscFunctionReturn(PETSC_SUCCESS);
    3863: }

    3865: static PetscErrorCode TSResizeTransferVecs(TS ts, PetscInt cnt, Vec vecsin[], Vec vecsout[])
    3866: {
    3867:   PetscFunctionBegin;
    3870:   for (PetscInt i = 0; i < cnt; i++) PetscCall(VecLockReadPush(vecsin[i]));
    3871:   if (ts->resizetransfer) {
    3872:     PetscCall(PetscInfo(ts, "Transferring %" PetscInt_FMT " vectors\n", cnt));
    3873:     PetscCallBack("TS callback resize transfer", (*ts->resizetransfer)(ts, cnt, vecsin, vecsout, ts->resizectx));
    3874:   }
    3875:   for (PetscInt i = 0; i < cnt; i++) PetscCall(VecLockReadPop(vecsin[i]));
    3876:   PetscFunctionReturn(PETSC_SUCCESS);
    3877: }

    3879: /*@C
    3880:   TSResizeRegisterVec - Register a vector to be transferred with `TSResize()`.

    3882:   Collective

    3884:   Input Parameters:
    3885: + ts   - The `TS` context obtained from `TSCreate()`
    3886: . name - A string identifying the vector
    3887: - vec  - The vector

    3889:   Level: developer

    3891:   Note:
    3892:   `TSResizeRegisterVec()` is typically used within time stepping implementations,
    3893:   so most users would not generally call this routine themselves.

    3895: .seealso: [](ch_ts), `TS`, `TSSetResize()`, `TSResize()`, `TSResizeRetrieveVec()`
    3896: @*/
    3897: PetscErrorCode TSResizeRegisterVec(TS ts, const char name[], Vec vec)
    3898: {
    3899:   PetscFunctionBegin;
    3901:   PetscAssertPointer(name, 2);
    3903:   PetscCall(PetscObjectListAdd(&ts->resizetransferobjs, name, (PetscObject)vec));
    3904:   PetscFunctionReturn(PETSC_SUCCESS);
    3905: }

    3907: /*@C
    3908:   TSResizeRetrieveVec - Retrieve a vector registered with `TSResizeRegisterVec()`.

    3910:   Collective

    3912:   Input Parameters:
    3913: + ts   - The `TS` context obtained from `TSCreate()`
    3914: . name - A string identifying the vector
    3915: - vec  - The vector

    3917:   Level: developer

    3919:   Note:
    3920:   `TSResizeRetrieveVec()` is typically used within time stepping implementations,
    3921:   so most users would not generally call this routine themselves.

    3923: .seealso: [](ch_ts), `TS`, `TSSetResize()`, `TSResize()`, `TSResizeRegisterVec()`
    3924: @*/
    3925: PetscErrorCode TSResizeRetrieveVec(TS ts, const char name[], Vec *vec)
    3926: {
    3927:   PetscFunctionBegin;
    3929:   PetscAssertPointer(name, 2);
    3930:   PetscAssertPointer(vec, 3);
    3931:   PetscCall(PetscObjectListFind(ts->resizetransferobjs, name, (PetscObject *)vec));
    3932:   PetscFunctionReturn(PETSC_SUCCESS);
    3933: }

    3935: static PetscErrorCode TSResizeGetVecArray(TS ts, PetscInt *nv, const char **names[], Vec *vecs[])
    3936: {
    3937:   PetscInt        cnt;
    3938:   PetscObjectList tmp;
    3939:   Vec            *vecsin  = NULL;
    3940:   const char    **namesin = NULL;

    3942:   PetscFunctionBegin;
    3943:   for (tmp = ts->resizetransferobjs, cnt = 0; tmp; tmp = tmp->next)
    3944:     if (tmp->obj && tmp->obj->classid == VEC_CLASSID) cnt++;
    3945:   if (names) PetscCall(PetscMalloc1(cnt, &namesin));
    3946:   if (vecs) PetscCall(PetscMalloc1(cnt, &vecsin));
    3947:   for (tmp = ts->resizetransferobjs, cnt = 0; tmp; tmp = tmp->next) {
    3948:     if (tmp->obj && tmp->obj->classid == VEC_CLASSID) {
    3949:       if (vecs) vecsin[cnt] = (Vec)tmp->obj;
    3950:       if (names) namesin[cnt] = tmp->name;
    3951:       cnt++;
    3952:     }
    3953:   }
    3954:   if (nv) *nv = cnt;
    3955:   if (names) *names = namesin;
    3956:   if (vecs) *vecs = vecsin;
    3957:   PetscFunctionReturn(PETSC_SUCCESS);
    3958: }

    3960: /*@
    3961:   TSResize - Runs the user-defined transfer functions provided with `TSSetResize()`

    3963:   Collective

    3965:   Input Parameter:
    3966: . ts - The `TS` context obtained from `TSCreate()`

    3968:   Level: developer

    3970:   Note:
    3971:   `TSResize()` is typically used within time stepping implementations,
    3972:   so most users would not generally call this routine themselves.

    3974: .seealso: [](ch_ts), `TS`, `TSSetResize()`
    3975: @*/
    3976: PetscErrorCode TSResize(TS ts)
    3977: {
    3978:   PetscInt     nv      = 0;
    3979:   const char **names   = NULL;
    3980:   Vec         *vecsin  = NULL;
    3981:   const char  *solname = "ts:vec_sol";

    3983:   PetscFunctionBegin;
    3985:   if (!ts->resizesetup) PetscFunctionReturn(PETSC_SUCCESS);
    3986:   if (ts->resizesetup) {
    3987:     PetscCall(VecLockReadPush(ts->vec_sol));
    3988:     PetscCallBack("TS callback resize setup", (*ts->resizesetup)(ts, ts->steps, ts->ptime, ts->vec_sol, &ts->stepresize, ts->resizectx));
    3989:     PetscCall(VecLockReadPop(ts->vec_sol));
    3990:     if (ts->stepresize) {
    3991:       if (ts->resizerollback) {
    3992:         PetscCall(TSRollBack(ts));
    3993:         ts->time_step = ts->time_step0;
    3994:       }
    3995:       PetscCall(TSResizeRegisterVec(ts, solname, ts->vec_sol));
    3996:       PetscCall(TSResizeRegisterOrRetrieve(ts, PETSC_TRUE)); /* specific impls register their own objects */
    3997:     }
    3998:   }

    4000:   PetscCall(TSResizeGetVecArray(ts, &nv, &names, &vecsin));
    4001:   if (nv) {
    4002:     Vec *vecsout, vecsol;

    4004:     /* Reset internal objects */
    4005:     PetscCall(TSReset(ts));

    4007:     /* Transfer needed vectors (users can call SetJacobian, SetDM, etc. here) */
    4008:     PetscCall(PetscCalloc1(nv, &vecsout));
    4009:     PetscCall(TSResizeTransferVecs(ts, nv, vecsin, vecsout));
    4010:     for (PetscInt i = 0; i < nv; i++) {
    4011:       const char *name;
    4012:       char       *oname;

    4014:       PetscCall(PetscObjectGetName((PetscObject)vecsin[i], &name));
    4015:       PetscCall(PetscStrallocpy(name, &oname));
    4016:       PetscCall(TSResizeRegisterVec(ts, names[i], vecsout[i]));
    4017:       if (vecsout[i]) PetscCall(PetscObjectSetName((PetscObject)vecsout[i], oname));
    4018:       PetscCall(PetscFree(oname));
    4019:       PetscCall(VecDestroy(&vecsout[i]));
    4020:     }
    4021:     PetscCall(PetscFree(vecsout));
    4022:     PetscCall(TSResizeRegisterOrRetrieve(ts, PETSC_FALSE)); /* specific impls import the transferred objects */

    4024:     PetscCall(TSResizeRetrieveVec(ts, solname, &vecsol));
    4025:     if (vecsol) PetscCall(TSSetSolution(ts, vecsol));
    4026:     PetscAssert(ts->vec_sol, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_NULL, "Missing TS solution");
    4027:   }

    4029:   PetscCall(PetscFree(names));
    4030:   PetscCall(PetscFree(vecsin));
    4031:   PetscCall(TSResizeReset(ts));
    4032:   PetscFunctionReturn(PETSC_SUCCESS);
    4033: }

    4035: /*@
    4036:   TSSolve - Steps the requested number of timesteps.

    4038:   Collective

    4040:   Input Parameters:
    4041: + ts - the `TS` context obtained from `TSCreate()`
    4042: - u  - the solution vector  (can be `NULL` if `TSSetSolution()` was used and `TSSetExactFinalTime`(ts,`TS_EXACTFINALTIME_MATCHSTEP`) was not used,
    4043:        otherwise it must contain the initial conditions and will contain the solution at the final requested time

    4045:   Level: beginner

    4047:   Note:
    4048:   The final time returned by this function may be different from the time of the internally
    4049:   held state accessible by `TSGetSolution()` and `TSGetTime()` because the method may have
    4050:   stepped over the final time.

    4052: .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetSolution()`, `TSStep()`, `TSGetTime()`, `TSGetSolveTime()`
    4053: @*/
    4054: PetscErrorCode TSSolve(TS ts, Vec u)
    4055: {
    4056:   Vec solution;

    4058:   PetscFunctionBegin;

    4062:   PetscCall(TSSetExactFinalTimeDefault(ts));
    4063:   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 */
    4064:     if (!ts->vec_sol || u == ts->vec_sol) {
    4065:       PetscCall(VecDuplicate(u, &solution));
    4066:       PetscCall(TSSetSolution(ts, solution));
    4067:       PetscCall(VecDestroy(&solution)); /* grant ownership */
    4068:     }
    4069:     PetscCall(VecCopy(u, ts->vec_sol));
    4070:     PetscCheck(!ts->forward_solve, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Sensitivity analysis does not support the mode TS_EXACTFINALTIME_INTERPOLATE");
    4071:   } else if (u) PetscCall(TSSetSolution(ts, u));
    4072:   PetscCall(TSSetUp(ts));
    4073:   PetscCall(TSTrajectorySetUp(ts->trajectory, ts));

    4075:   PetscCheck(ts->max_time < PETSC_MAX_REAL || ts->run_steps != PETSC_INT_MAX || ts->max_steps != PETSC_INT_MAX, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "You must call TSSetMaxTime(), TSSetMaxSteps(), or TSSetRunSteps() or use -ts_max_time <time>, -ts_max_steps <steps>, -ts_run_steps <steps>");
    4076:   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()");
    4077:   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");
    4078:   PetscCheck(!(ts->eval_times && ts->exact_final_time != TS_EXACTFINALTIME_MATCHSTEP), PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "You must use TS_EXACTFINALTIME_MATCHSTEP when using time span or evaluation times");

    4080:   if (ts->eval_times) {
    4081:     if (!ts->eval_times->sol_vecs) PetscCall(VecDuplicateVecs(ts->vec_sol, ts->eval_times->num_time_points, &ts->eval_times->sol_vecs));
    4082:     for (PetscInt i = 0; i < ts->eval_times->num_time_points; i++) {
    4083:       PetscBool is_close = PetscIsCloseAtTol(ts->ptime, ts->eval_times->time_points[i], ts->eval_times->reltol * ts->time_step + ts->eval_times->abstol, 0);
    4084:       if (ts->ptime <= ts->eval_times->time_points[i] || is_close) {
    4085:         ts->eval_times->time_point_idx = i;

    4087:         PetscBool is_ptime_in_sol_times = PETSC_FALSE; // If current solution has already been saved, we should not save it again
    4088:         if (ts->eval_times->sol_idx > 0) is_ptime_in_sol_times = PetscIsCloseAtTol(ts->ptime, ts->eval_times->sol_times[ts->eval_times->sol_idx - 1], ts->eval_times->reltol * ts->time_step + ts->eval_times->abstol, 0);
    4089:         if (is_close && !is_ptime_in_sol_times) {
    4090:           PetscCall(VecCopy(ts->vec_sol, ts->eval_times->sol_vecs[ts->eval_times->sol_idx]));
    4091:           ts->eval_times->sol_times[ts->eval_times->sol_idx] = ts->ptime;
    4092:           ts->eval_times->sol_idx++;
    4093:           ts->eval_times->time_point_idx++;
    4094:         }
    4095:         break;
    4096:       }
    4097:     }
    4098:   }

    4100:   if (ts->forward_solve) PetscCall(TSForwardSetUp(ts));

    4102:   /* reset number of steps only when the step is not restarted. ARKIMEX
    4103:      restarts the step after an event. Resetting these counters in such case causes
    4104:      TSTrajectory to incorrectly save the output files
    4105:   */
    4106:   /* reset time step and iteration counters */
    4107:   if (!ts->steps) {
    4108:     ts->ksp_its           = 0;
    4109:     ts->snes_its          = 0;
    4110:     ts->num_snes_failures = 0;
    4111:     ts->reject            = 0;
    4112:     ts->steprestart       = PETSC_TRUE;
    4113:     ts->steprollback      = PETSC_FALSE;
    4114:     ts->stepresize        = PETSC_FALSE;
    4115:     ts->rhsjacobian.time  = PETSC_MIN_REAL;
    4116:   }

    4118:   /* make sure initial time step does not overshoot final time or the next point in evaluation times */
    4119:   if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
    4120:     PetscReal maxdt;
    4121:     PetscReal dt = ts->time_step;

    4123:     if (ts->eval_times) maxdt = ts->eval_times->time_points[ts->eval_times->time_point_idx] - ts->ptime;
    4124:     else maxdt = ts->max_time - ts->ptime;
    4125:     ts->time_step = dt >= maxdt ? maxdt : (PetscIsCloseAtTol(dt, maxdt, 10 * PETSC_MACHINE_EPSILON, 0) ? maxdt : dt);
    4126:   }
    4127:   ts->reason = TS_CONVERGED_ITERATING;

    4129:   {
    4130:     PetscViewer       viewer;
    4131:     PetscViewerFormat format;
    4132:     PetscBool         flg;
    4133:     static PetscBool  incall = PETSC_FALSE;

    4135:     if (!incall) {
    4136:       /* Estimate the convergence rate of the time discretization */
    4137:       PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)ts), ((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_convergence_estimate", &viewer, &format, &flg));
    4138:       if (flg) {
    4139:         PetscConvEst conv;
    4140:         DM           dm;
    4141:         PetscReal   *alpha; /* Convergence rate of the solution error for each field in the L_2 norm */
    4142:         PetscInt     Nf;
    4143:         PetscBool    checkTemporal = PETSC_TRUE;

    4145:         incall = PETSC_TRUE;
    4146:         PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_convergence_temporal", &checkTemporal, &flg));
    4147:         PetscCall(TSGetDM(ts, &dm));
    4148:         PetscCall(DMGetNumFields(dm, &Nf));
    4149:         PetscCall(PetscCalloc1(PetscMax(Nf, 1), &alpha));
    4150:         PetscCall(PetscConvEstCreate(PetscObjectComm((PetscObject)ts), &conv));
    4151:         PetscCall(PetscConvEstUseTS(conv, checkTemporal));
    4152:         PetscCall(PetscConvEstSetSolver(conv, (PetscObject)ts));
    4153:         PetscCall(PetscConvEstSetFromOptions(conv));
    4154:         PetscCall(PetscConvEstSetUp(conv));
    4155:         PetscCall(PetscConvEstGetConvRate(conv, alpha));
    4156:         PetscCall(PetscViewerPushFormat(viewer, format));
    4157:         PetscCall(PetscConvEstRateView(conv, alpha, viewer));
    4158:         PetscCall(PetscViewerPopFormat(viewer));
    4159:         PetscCall(PetscViewerDestroy(&viewer));
    4160:         PetscCall(PetscConvEstDestroy(&conv));
    4161:         PetscCall(PetscFree(alpha));
    4162:         incall = PETSC_FALSE;
    4163:       }
    4164:     }
    4165:   }

    4167:   PetscCall(TSViewFromOptions(ts, NULL, "-ts_view_pre"));

    4169:   if (ts->ops->solve) { /* This private interface is transitional and should be removed when all implementations are updated. */
    4170:     PetscUseTypeMethod(ts, solve);
    4171:     if (u) PetscCall(VecCopy(ts->vec_sol, u));
    4172:     ts->solvetime = ts->ptime;
    4173:     solution      = ts->vec_sol;
    4174:   } else { /* Step the requested number of timesteps. */
    4175:     if (ts->steps >= ts->max_steps) ts->reason = TS_CONVERGED_ITS;
    4176:     else if (ts->ptime >= ts->max_time) ts->reason = TS_CONVERGED_TIME;

    4178:     if (!ts->steps) {
    4179:       PetscCall(TSTrajectorySet(ts->trajectory, ts, ts->steps, ts->ptime, ts->vec_sol));
    4180:       PetscCall(TSEventInitialize(ts->event, ts, ts->ptime, ts->vec_sol));
    4181:     }

    4183:     ts->start_step = ts->steps; // records starting step
    4184:     while (!ts->reason) {
    4185:       PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
    4186:       if (!ts->steprollback || (ts->stepresize && ts->resizerollback)) PetscCall(TSPreStep(ts));
    4187:       PetscCall(TSStep(ts));
    4188:       if (ts->testjacobian) PetscCall(TSRHSJacobianTest(ts, NULL));
    4189:       if (ts->testjacobiantranspose) PetscCall(TSRHSJacobianTestTranspose(ts, NULL));
    4190:       if (ts->quadraturets && ts->costintegralfwd) { /* Must evaluate the cost integral before event is handled. The cost integral value can also be rolled back. */
    4191:         if (ts->reason >= 0) ts->steps--;            /* Revert the step number changed by TSStep() */
    4192:         PetscCall(TSForwardCostIntegral(ts));
    4193:         if (ts->reason >= 0) ts->steps++;
    4194:       }
    4195:       if (ts->forward_solve) {            /* compute forward sensitivities before event handling because postevent() may change RHS and jump conditions may have to be applied */
    4196:         if (ts->reason >= 0) ts->steps--; /* Revert the step number changed by TSStep() */
    4197:         PetscCall(TSForwardStep(ts));
    4198:         if (ts->reason >= 0) ts->steps++;
    4199:       }
    4200:       PetscCall(TSPostEvaluate(ts));
    4201:       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. */
    4202:       if (ts->steprollback) PetscCall(TSPostEvaluate(ts));
    4203:       if (!ts->steprollback && ts->resizerollback) PetscCall(TSResize(ts));
    4204:       /* check convergence */
    4205:       if (!ts->reason) {
    4206:         if ((ts->steps - ts->start_step) >= ts->run_steps) ts->reason = TS_CONVERGED_ITS;
    4207:         else if (ts->steps >= ts->max_steps) ts->reason = TS_CONVERGED_ITS;
    4208:         else if (ts->ptime >= ts->max_time) ts->reason = TS_CONVERGED_TIME;
    4209:       }
    4210:       if (!ts->steprollback) {
    4211:         PetscCall(TSTrajectorySet(ts->trajectory, ts, ts->steps, ts->ptime, ts->vec_sol));
    4212:         PetscCall(TSPostStep(ts));
    4213:         if (!ts->resizerollback) PetscCall(TSResize(ts));

    4215:         if (ts->eval_times && ts->eval_times->time_point_idx < ts->eval_times->num_time_points && ts->reason >= 0) {
    4216:           PetscCheck(ts->eval_times->worktol > 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Unexpected state !(eval_times->worktol > 0) in TSSolve()");
    4217:           if (PetscIsCloseAtTol(ts->ptime, ts->eval_times->time_points[ts->eval_times->time_point_idx], ts->eval_times->worktol, 0)) {
    4218:             ts->eval_times->sol_times[ts->eval_times->sol_idx] = ts->ptime;
    4219:             PetscCall(VecCopy(ts->vec_sol, ts->eval_times->sol_vecs[ts->eval_times->sol_idx]));
    4220:             ts->eval_times->sol_idx++;
    4221:             ts->eval_times->time_point_idx++;
    4222:           }
    4223:         }
    4224:       }
    4225:     }
    4226:     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));

    4228:     if (ts->exact_final_time == TS_EXACTFINALTIME_INTERPOLATE && ts->ptime > ts->max_time) {
    4229:       if (!u) u = ts->vec_sol;
    4230:       PetscCall(TSInterpolate(ts, ts->max_time, u));
    4231:       ts->solvetime = ts->max_time;
    4232:       solution      = u;
    4233:       PetscCall(TSMonitor(ts, -1, ts->solvetime, solution));
    4234:     } else {
    4235:       if (u) PetscCall(VecCopy(ts->vec_sol, u));
    4236:       ts->solvetime = ts->ptime;
    4237:       solution      = ts->vec_sol;
    4238:     }
    4239:   }

    4241:   PetscCall(TSViewFromOptions(ts, NULL, "-ts_view"));
    4242:   PetscCall(VecViewFromOptions(solution, (PetscObject)ts, "-ts_view_solution"));
    4243:   PetscCall(PetscObjectSAWsBlock((PetscObject)ts));
    4244:   if (ts->adjoint_solve) PetscCall(TSAdjointSolve(ts));
    4245:   PetscFunctionReturn(PETSC_SUCCESS);
    4246: }

    4248: /*@
    4249:   TSGetTime - Gets the time of the most recently completed step.

    4251:   Not Collective

    4253:   Input Parameter:
    4254: . ts - the `TS` context obtained from `TSCreate()`

    4256:   Output Parameter:
    4257: . t - the current time. This time may not corresponds to the final time set with `TSSetMaxTime()`, use `TSGetSolveTime()`.

    4259:   Level: beginner

    4261:   Note:
    4262:   When called during time step evaluation (e.g. during residual evaluation or via hooks set using `TSSetPreStep()`,
    4263:   `TSSetPreStage()`, `TSSetPostStage()`, or `TSSetPostStep()`), the time is the time at the start of the step being evaluated.

    4265: .seealso: [](ch_ts), `TS`, `TSGetSolveTime()`, `TSSetTime()`, `TSGetTimeStep()`, `TSGetStepNumber()`
    4266: @*/
    4267: PetscErrorCode TSGetTime(TS ts, PetscReal *t)
    4268: {
    4269:   PetscFunctionBegin;
    4271:   PetscAssertPointer(t, 2);
    4272:   *t = ts->ptime;
    4273:   PetscFunctionReturn(PETSC_SUCCESS);
    4274: }

    4276: /*@
    4277:   TSGetPrevTime - Gets the starting time of the previously completed step.

    4279:   Not Collective

    4281:   Input Parameter:
    4282: . ts - the `TS` context obtained from `TSCreate()`

    4284:   Output Parameter:
    4285: . t - the previous time

    4287:   Level: beginner

    4289: .seealso: [](ch_ts), `TS`, `TSGetTime()`, `TSGetSolveTime()`, `TSGetTimeStep()`
    4290: @*/
    4291: PetscErrorCode TSGetPrevTime(TS ts, PetscReal *t)
    4292: {
    4293:   PetscFunctionBegin;
    4295:   PetscAssertPointer(t, 2);
    4296:   *t = ts->ptime_prev;
    4297:   PetscFunctionReturn(PETSC_SUCCESS);
    4298: }

    4300: /*@
    4301:   TSSetTime - Allows one to reset the time.

    4303:   Logically Collective

    4305:   Input Parameters:
    4306: + ts - the `TS` context obtained from `TSCreate()`
    4307: - t  - the time

    4309:   Level: intermediate

    4311: .seealso: [](ch_ts), `TS`, `TSGetTime()`, `TSSetMaxSteps()`
    4312: @*/
    4313: PetscErrorCode TSSetTime(TS ts, PetscReal t)
    4314: {
    4315:   PetscFunctionBegin;
    4318:   ts->ptime = t;
    4319:   PetscFunctionReturn(PETSC_SUCCESS);
    4320: }

    4322: /*@
    4323:   TSSetOptionsPrefix - Sets the prefix used for searching for all
    4324:   TS options in the database.

    4326:   Logically Collective

    4328:   Input Parameters:
    4329: + ts     - The `TS` context
    4330: - prefix - The prefix to prepend to all option names

    4332:   Level: advanced

    4334:   Note:
    4335:   A hyphen (-) must NOT be given at the beginning of the prefix name.
    4336:   The first character of all runtime options is AUTOMATICALLY the
    4337:   hyphen.

    4339: .seealso: [](ch_ts), `TS`, `TSSetFromOptions()`, `TSAppendOptionsPrefix()`
    4340: @*/
    4341: PetscErrorCode TSSetOptionsPrefix(TS ts, const char prefix[])
    4342: {
    4343:   SNES snes;

    4345:   PetscFunctionBegin;
    4347:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ts, prefix));
    4348:   PetscCall(TSGetSNES(ts, &snes));
    4349:   PetscCall(SNESSetOptionsPrefix(snes, prefix));
    4350:   PetscFunctionReturn(PETSC_SUCCESS);
    4351: }

    4353: /*@
    4354:   TSAppendOptionsPrefix - Appends to the prefix used for searching for all
    4355:   TS options in the database.

    4357:   Logically Collective

    4359:   Input Parameters:
    4360: + ts     - The `TS` context
    4361: - prefix - The prefix to prepend to all option names

    4363:   Level: advanced

    4365:   Note:
    4366:   A hyphen (-) must NOT be given at the beginning of the prefix name.
    4367:   The first character of all runtime options is AUTOMATICALLY the
    4368:   hyphen.

    4370: .seealso: [](ch_ts), `TS`, `TSGetOptionsPrefix()`, `TSSetOptionsPrefix()`, `TSSetFromOptions()`
    4371: @*/
    4372: PetscErrorCode TSAppendOptionsPrefix(TS ts, const char prefix[])
    4373: {
    4374:   SNES snes;

    4376:   PetscFunctionBegin;
    4378:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)ts, prefix));
    4379:   PetscCall(TSGetSNES(ts, &snes));
    4380:   PetscCall(SNESAppendOptionsPrefix(snes, prefix));
    4381:   PetscFunctionReturn(PETSC_SUCCESS);
    4382: }

    4384: /*@
    4385:   TSGetOptionsPrefix - Sets the prefix used for searching for all
    4386:   `TS` options in the database.

    4388:   Not Collective

    4390:   Input Parameter:
    4391: . ts - The `TS` context

    4393:   Output Parameter:
    4394: . prefix - A pointer to the prefix string used

    4396:   Level: intermediate

    4398: .seealso: [](ch_ts), `TS`, `TSAppendOptionsPrefix()`, `TSSetFromOptions()`
    4399: @*/
    4400: PetscErrorCode TSGetOptionsPrefix(TS ts, const char *prefix[])
    4401: {
    4402:   PetscFunctionBegin;
    4404:   PetscAssertPointer(prefix, 2);
    4405:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)ts, prefix));
    4406:   PetscFunctionReturn(PETSC_SUCCESS);
    4407: }

    4409: /*@C
    4410:   TSGetRHSJacobian - Returns the Jacobian J at the present timestep.

    4412:   Not Collective, but parallel objects are returned if ts is parallel

    4414:   Input Parameter:
    4415: . ts - The `TS` context obtained from `TSCreate()`

    4417:   Output Parameters:
    4418: + Amat - The (approximate) Jacobian J of G, where U_t = G(U,t)  (or `NULL`)
    4419: . Pmat - The matrix from which the preconditioner is constructed, usually the same as `Amat`  (or `NULL`)
    4420: . func - Function to compute the Jacobian of the RHS  (or `NULL`)
    4421: - ctx  - User-defined context for Jacobian evaluation routine  (or `NULL`)

    4423:   Level: intermediate

    4425:   Note:
    4426:   You can pass in `NULL` for any return argument you do not need.

    4428: .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetMatrices()`, `TSGetTime()`, `TSGetStepNumber()`
    4429: @*/
    4430: PetscErrorCode TSGetRHSJacobian(TS ts, Mat *Amat, Mat *Pmat, TSRHSJacobianFn **func, PetscCtxRt ctx)
    4431: {
    4432:   DM dm;

    4434:   PetscFunctionBegin;
    4435:   if (Amat || Pmat) {
    4436:     SNES snes;
    4437:     PetscCall(TSGetSNES(ts, &snes));
    4438:     PetscCall(SNESSetUpMatrices(snes));
    4439:     PetscCall(SNESGetJacobian(snes, Amat, Pmat, NULL, NULL));
    4440:   }
    4441:   PetscCall(TSGetDM(ts, &dm));
    4442:   PetscCall(DMTSGetRHSJacobian(dm, func, ctx));
    4443:   PetscFunctionReturn(PETSC_SUCCESS);
    4444: }

    4446: /*@C
    4447:   TSGetIJacobian - Returns the implicit Jacobian at the present timestep.

    4449:   Not Collective, but parallel objects are returned if ts is parallel

    4451:   Input Parameter:
    4452: . ts - The `TS` context obtained from `TSCreate()`

    4454:   Output Parameters:
    4455: + Amat - The (approximate) Jacobian of F(t,U,U_t)
    4456: . Pmat - The matrix from which the preconditioner is constructed, often the same as `Amat`
    4457: . f    - The function to compute the matrices
    4458: - ctx  - User-defined context for Jacobian evaluation routine

    4460:   Level: advanced

    4462:   Note:
    4463:   You can pass in `NULL` for any return argument you do not need.

    4465: .seealso: [](ch_ts), `TS`, `TSGetTimeStep()`, `TSGetRHSJacobian()`, `TSGetMatrices()`, `TSGetTime()`, `TSGetStepNumber()`
    4466: @*/
    4467: PetscErrorCode TSGetIJacobian(TS ts, Mat *Amat, Mat *Pmat, TSIJacobianFn **f, PetscCtxRt ctx)
    4468: {
    4469:   DM dm;

    4471:   PetscFunctionBegin;
    4472:   if (Amat || Pmat) {
    4473:     SNES snes;
    4474:     PetscCall(TSGetSNES(ts, &snes));
    4475:     PetscCall(SNESSetUpMatrices(snes));
    4476:     PetscCall(SNESGetJacobian(snes, Amat, Pmat, NULL, NULL));
    4477:   }
    4478:   PetscCall(TSGetDM(ts, &dm));
    4479:   PetscCall(DMTSGetIJacobian(dm, f, ctx));
    4480:   PetscFunctionReturn(PETSC_SUCCESS);
    4481: }

    4483: #include <petsc/private/dmimpl.h>
    4484: /*@
    4485:   TSSetDM - Sets the `DM` that may be used by some nonlinear solvers or preconditioners under the `TS`

    4487:   Logically Collective

    4489:   Input Parameters:
    4490: + ts - the `TS` integrator object
    4491: - dm - the dm, cannot be `NULL`

    4493:   Level: intermediate

    4495:   Notes:
    4496:   A `DM` can only be used for solving one problem at a time because information about the problem is stored on the `DM`,
    4497:   even when not using interfaces like `DMTSSetIFunction()`.  Use `DMClone()` to get a distinct `DM` when solving
    4498:   different problems using the same function space.

    4500: .seealso: [](ch_ts), `TS`, `DM`, `TSGetDM()`, `SNESSetDM()`, `SNESGetDM()`
    4501: @*/
    4502: PetscErrorCode TSSetDM(TS ts, DM dm)
    4503: {
    4504:   SNES snes;
    4505:   DMTS tsdm;

    4507:   PetscFunctionBegin;
    4510:   PetscCall(PetscObjectReference((PetscObject)dm));
    4511:   if (ts->dm) { /* Move the DMTS context over to the new DM unless the new DM already has one */
    4512:     if (ts->dm->dmts && !dm->dmts) {
    4513:       PetscCall(DMCopyDMTS(ts->dm, dm));
    4514:       PetscCall(DMGetDMTS(ts->dm, &tsdm));
    4515:       /* Grant write privileges to the replacement DM */
    4516:       if (tsdm->originaldm == ts->dm) tsdm->originaldm = dm;
    4517:     }
    4518:     PetscCall(DMDestroy(&ts->dm));
    4519:   }
    4520:   ts->dm = dm;

    4522:   PetscCall(TSGetSNES(ts, &snes));
    4523:   PetscCall(SNESSetDM(snes, dm));
    4524:   PetscFunctionReturn(PETSC_SUCCESS);
    4525: }

    4527: /*@
    4528:   TSGetDM - Gets the `DM` that may be used by some preconditioners

    4530:   Not Collective

    4532:   Input Parameter:
    4533: . ts - the `TS`

    4535:   Output Parameter:
    4536: . dm - the `DM`

    4538:   Level: intermediate

    4540: .seealso: [](ch_ts), `TS`, `DM`, `TSSetDM()`, `SNESSetDM()`, `SNESGetDM()`
    4541: @*/
    4542: PetscErrorCode TSGetDM(TS ts, DM *dm)
    4543: {
    4544:   PetscFunctionBegin;
    4546:   if (!ts->dm) {
    4547:     PetscCall(DMShellCreate(PetscObjectComm((PetscObject)ts), &ts->dm));
    4548:     if (ts->snes) PetscCall(SNESSetDM(ts->snes, ts->dm));
    4549:   }
    4550:   *dm = ts->dm;
    4551:   PetscFunctionReturn(PETSC_SUCCESS);
    4552: }

    4554: /*@
    4555:   SNESTSFormFunction - Function to evaluate nonlinear residual defined by an ODE solver algorithm implemented within `TS`

    4557:   Logically Collective

    4559:   Input Parameters:
    4560: + snes - nonlinear solver
    4561: . U    - the current state at which to evaluate the residual
    4562: - ctx  - user context, must be a `TS`

    4564:   Output Parameter:
    4565: . F - the nonlinear residual

    4567:   Level: developer

    4569:   Note:
    4570:   This function is not normally called by users and is automatically registered with the `SNES` used by `TS`.
    4571:   It is most frequently passed to `MatFDColoringSetFunction()`.

    4573: .seealso: [](ch_ts), `SNESSetFunction()`, `MatFDColoringSetFunction()`
    4574: @*/
    4575: PetscErrorCode SNESTSFormFunction(SNES snes, Vec U, Vec F, PetscCtx ctx)
    4576: {
    4577:   TS ts = (TS)ctx;

    4579:   PetscFunctionBegin;
    4584:   PetscCheck(ts->ops->snesfunction, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "No method snesfunction for TS of type %s", ((PetscObject)ts)->type_name);
    4585:   PetscCall((*ts->ops->snesfunction)(snes, U, F, ts));
    4586:   PetscFunctionReturn(PETSC_SUCCESS);
    4587: }

    4589: /*@
    4590:   SNESTSFormJacobian - Function to evaluate the Jacobian defined by an ODE solver algorithm implemented within `TS`

    4592:   Collective

    4594:   Input Parameters:
    4595: + snes - nonlinear solver
    4596: . U    - the current state at which to evaluate the residual
    4597: - ctx  - user context, must be a `TS`

    4599:   Output Parameters:
    4600: + A - the Jacobian
    4601: - B - the matrix used to construct the preconditioner (often the same as `A`)

    4603:   Level: developer

    4605:   Note:
    4606:   This function is not normally called by users and is automatically registered with the `SNES` used by `TS`.

    4608: .seealso: [](ch_ts), `SNESSetJacobian()`
    4609: @*/
    4610: PetscErrorCode SNESTSFormJacobian(SNES snes, Vec U, Mat A, Mat B, PetscCtx ctx)
    4611: {
    4612:   TS ts = (TS)ctx;

    4614:   PetscFunctionBegin;
    4620:   PetscCheck(ts->ops->snesjacobian, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "No method snesjacobian for TS of type %s", ((PetscObject)ts)->type_name);
    4621:   PetscCall((*ts->ops->snesjacobian)(snes, U, A, B, ts));
    4622:   PetscFunctionReturn(PETSC_SUCCESS);
    4623: }

    4625: /*@C
    4626:   TSComputeRHSFunctionLinear - Evaluate the right-hand side via the user-provided Jacobian, for linear problems Udot = A U only

    4628:   Collective

    4630:   Input Parameters:
    4631: + ts  - time stepping context
    4632: . t   - time at which to evaluate
    4633: . U   - state at which to evaluate
    4634: - ctx - context

    4636:   Output Parameter:
    4637: . F - right-hand side

    4639:   Level: intermediate

    4641:   Note:
    4642:   This function is intended to be passed to `TSSetRHSFunction()` to evaluate the right-hand side for linear problems.
    4643:   The matrix (and optionally the evaluation context) should be passed to `TSSetRHSJacobian()`.

    4645: .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSSetRHSJacobian()`, `TSComputeRHSJacobianConstant()`
    4646: @*/
    4647: PetscErrorCode TSComputeRHSFunctionLinear(TS ts, PetscReal t, Vec U, Vec F, PetscCtx ctx)
    4648: {
    4649:   Mat Arhs, Brhs;

    4651:   PetscFunctionBegin;
    4652:   PetscCall(TSGetRHSMats_Private(ts, &Arhs, &Brhs));
    4653:   /* undo the damage caused by shifting */
    4654:   PetscCall(TSRecoverRHSJacobian(ts, Arhs, Brhs));
    4655:   PetscCall(TSComputeRHSJacobian(ts, t, U, Arhs, Brhs));
    4656:   PetscCall(MatMult(Arhs, U, F));
    4657:   PetscFunctionReturn(PETSC_SUCCESS);
    4658: }

    4660: /*@C
    4661:   TSComputeRHSJacobianConstant - Reuses a Jacobian that is time-independent.

    4663:   Collective

    4665:   Input Parameters:
    4666: + ts  - time stepping context
    4667: . t   - time at which to evaluate
    4668: . U   - state at which to evaluate
    4669: - ctx - context

    4671:   Output Parameters:
    4672: + A - Jacobian
    4673: - B - matrix used to construct the preconditioner, often the same as `A`

    4675:   Level: intermediate

    4677:   Note:
    4678:   This function is intended to be passed to `TSSetRHSJacobian()` to evaluate the Jacobian for linear time-independent problems.

    4680: .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSSetRHSJacobian()`, `TSComputeRHSFunctionLinear()`
    4681: @*/
    4682: PetscErrorCode TSComputeRHSJacobianConstant(TS ts, PetscReal t, Vec U, Mat A, Mat B, PetscCtx ctx)
    4683: {
    4684:   PetscFunctionBegin;
    4685:   PetscFunctionReturn(PETSC_SUCCESS);
    4686: }

    4688: /*@C
    4689:   TSComputeIFunctionLinear - Evaluate the left hand side via the user-provided Jacobian, for linear problems only

    4691:   Collective

    4693:   Input Parameters:
    4694: + ts   - time stepping context
    4695: . t    - time at which to evaluate
    4696: . U    - state at which to evaluate
    4697: . Udot - time derivative of state vector
    4698: - ctx  - context

    4700:   Output Parameter:
    4701: . F - left hand side

    4703:   Level: intermediate

    4705:   Notes:
    4706:   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
    4707:   user is required to write their own `TSComputeIFunction()`.
    4708:   This function is intended to be passed to `TSSetIFunction()` to evaluate the left hand side for linear problems.
    4709:   The matrix (and optionally the evaluation context) should be passed to `TSSetIJacobian()`.

    4711:   Note that using this function is NOT equivalent to using `TSComputeRHSFunctionLinear()` since that solves Udot = A U

    4713: .seealso: [](ch_ts), `TS`, `TSSetIFunction()`, `TSSetIJacobian()`, `TSComputeIJacobianConstant()`, `TSComputeRHSFunctionLinear()`
    4714: @*/
    4715: PetscErrorCode TSComputeIFunctionLinear(TS ts, PetscReal t, Vec U, Vec Udot, Vec F, PetscCtx ctx)
    4716: {
    4717:   Mat A, B;

    4719:   PetscFunctionBegin;
    4720:   PetscCall(TSGetIJacobian(ts, &A, &B, NULL, NULL));
    4721:   PetscCall(TSComputeIJacobian(ts, t, U, Udot, 1.0, A, B, PETSC_TRUE));
    4722:   PetscCall(MatMult(A, Udot, F));
    4723:   PetscFunctionReturn(PETSC_SUCCESS);
    4724: }

    4726: /*@C
    4727:   TSComputeIJacobianConstant - Reuses the matrix previously computed with the provided `TSIJacobianFn` for a semi-implicit DAE or ODE

    4729:   Collective

    4731:   Input Parameters:
    4732: + ts    - time stepping context
    4733: . t     - time at which to evaluate
    4734: . U     - state at which to evaluate
    4735: . Udot  - time derivative of state vector
    4736: . shift - shift to apply
    4737: - ctx   - context

    4739:   Output Parameters:
    4740: + A - pointer to operator
    4741: - B - pointer to matrix from which the preconditioner is built (often `A`)

    4743:   Level: advanced

    4745:   Notes:
    4746:   This function is intended to be passed to `TSSetIJacobian()` to evaluate the Jacobian for linear time-independent problems.

    4748:   It is only appropriate for problems of the form

    4750:   $$
    4751:   M \dot{U} = F(U,t)
    4752:   $$

    4754:   where M is constant and F is non-stiff.  The user must pass M to `TSSetIJacobian()`.  The current implementation only
    4755:   works with IMEX time integration methods such as `TSROSW` and `TSARKIMEX`, since there is no support for de-constructing
    4756:   an implicit operator of the form

    4758:   $$
    4759:   shift*M + J
    4760:   $$

    4762:   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
    4763:   a copy of M or reassemble it when requested.

    4765: .seealso: [](ch_ts), `TS`, `TSROSW`, `TSARKIMEX`, `TSSetIFunction()`, `TSSetIJacobian()`, `TSComputeIFunctionLinear()`
    4766: @*/
    4767: PetscErrorCode TSComputeIJacobianConstant(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat A, Mat B, PetscCtx ctx)
    4768: {
    4769:   PetscFunctionBegin;
    4770:   PetscCall(MatScale(A, shift / ts->ijacobian.shift));
    4771:   ts->ijacobian.shift = shift;
    4772:   PetscFunctionReturn(PETSC_SUCCESS);
    4773: }

    4775: /*@
    4776:   TSGetEquationType - Gets the type of the equation that `TS` is solving.

    4778:   Not Collective

    4780:   Input Parameter:
    4781: . ts - the `TS` context

    4783:   Output Parameter:
    4784: . equation_type - see `TSEquationType`

    4786:   Level: beginner

    4788: .seealso: [](ch_ts), `TS`, `TSSetEquationType()`, `TSEquationType`
    4789: @*/
    4790: PetscErrorCode TSGetEquationType(TS ts, TSEquationType *equation_type)
    4791: {
    4792:   PetscFunctionBegin;
    4794:   PetscAssertPointer(equation_type, 2);
    4795:   *equation_type = ts->equation_type;
    4796:   PetscFunctionReturn(PETSC_SUCCESS);
    4797: }

    4799: /*@
    4800:   TSSetEquationType - Sets the type of the equation that `TS` is solving.

    4802:   Not Collective

    4804:   Input Parameters:
    4805: + ts            - the `TS` context
    4806: - equation_type - see `TSEquationType`

    4808:   Level: advanced

    4810: .seealso: [](ch_ts), `TS`, `TSGetEquationType()`, `TSEquationType`
    4811: @*/
    4812: PetscErrorCode TSSetEquationType(TS ts, TSEquationType equation_type)
    4813: {
    4814:   PetscFunctionBegin;
    4816:   ts->equation_type = equation_type;
    4817:   PetscFunctionReturn(PETSC_SUCCESS);
    4818: }

    4820: /*@
    4821:   TSGetConvergedReason - Gets the reason the `TS` iteration was stopped.

    4823:   Not Collective

    4825:   Input Parameter:
    4826: . ts - the `TS` context

    4828:   Output Parameter:
    4829: . reason - negative value indicates diverged, positive value converged, see `TSConvergedReason` or the
    4830:             manual pages for the individual convergence tests for complete lists

    4832:   Level: beginner

    4834:   Note:
    4835:   Can only be called after the call to `TSSolve()` is complete.

    4837: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSConvergedReason`
    4838: @*/
    4839: PetscErrorCode TSGetConvergedReason(TS ts, TSConvergedReason *reason)
    4840: {
    4841:   PetscFunctionBegin;
    4843:   PetscAssertPointer(reason, 2);
    4844:   *reason = ts->reason;
    4845:   PetscFunctionReturn(PETSC_SUCCESS);
    4846: }

    4848: /*@
    4849:   TSSetConvergedReason - Sets the reason for handling the convergence of `TSSolve()`.

    4851:   Logically Collective; reason must contain common value

    4853:   Input Parameters:
    4854: + ts     - the `TS` context
    4855: - reason - negative value indicates diverged, positive value converged, see `TSConvergedReason` or the
    4856:             manual pages for the individual convergence tests for complete lists

    4858:   Level: advanced

    4860:   Note:
    4861:   Can only be called while `TSSolve()` is active.

    4863: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSConvergedReason`
    4864: @*/
    4865: PetscErrorCode TSSetConvergedReason(TS ts, TSConvergedReason reason)
    4866: {
    4867:   PetscFunctionBegin;
    4869:   ts->reason = reason;
    4870:   PetscFunctionReturn(PETSC_SUCCESS);
    4871: }

    4873: /*@
    4874:   TSGetSolveTime - Gets the time after a call to `TSSolve()`

    4876:   Not Collective

    4878:   Input Parameter:
    4879: . ts - the `TS` context

    4881:   Output Parameter:
    4882: . ftime - the final time. This time corresponds to the final time set with `TSSetMaxTime()`

    4884:   Level: beginner

    4886:   Note:
    4887:   Can only be called after the call to `TSSolve()` is complete.

    4889: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSConvergedReason`
    4890: @*/
    4891: PetscErrorCode TSGetSolveTime(TS ts, PetscReal *ftime)
    4892: {
    4893:   PetscFunctionBegin;
    4895:   PetscAssertPointer(ftime, 2);
    4896:   *ftime = ts->solvetime;
    4897:   PetscFunctionReturn(PETSC_SUCCESS);
    4898: }

    4900: /*@
    4901:   TSGetSNESIterations - Gets the total number of nonlinear iterations
    4902:   used by the time integrator.

    4904:   Not Collective

    4906:   Input Parameter:
    4907: . ts - `TS` context

    4909:   Output Parameter:
    4910: . nits - number of nonlinear iterations

    4912:   Level: intermediate

    4914:   Note:
    4915:   This counter is reset to zero for each successive call to `TSSolve()`.

    4917: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetKSPIterations()`
    4918: @*/
    4919: PetscErrorCode TSGetSNESIterations(TS ts, PetscInt *nits)
    4920: {
    4921:   PetscFunctionBegin;
    4923:   PetscAssertPointer(nits, 2);
    4924:   *nits = ts->snes_its;
    4925:   PetscFunctionReturn(PETSC_SUCCESS);
    4926: }

    4928: /*@
    4929:   TSGetKSPIterations - Gets the total number of linear iterations
    4930:   used by the time integrator.

    4932:   Not Collective

    4934:   Input Parameter:
    4935: . ts - `TS` context

    4937:   Output Parameter:
    4938: . lits - number of linear iterations

    4940:   Level: intermediate

    4942:   Note:
    4943:   This counter is reset to zero for each successive call to `TSSolve()`.

    4945: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetSNESIterations()`
    4946: @*/
    4947: PetscErrorCode TSGetKSPIterations(TS ts, PetscInt *lits)
    4948: {
    4949:   PetscFunctionBegin;
    4951:   PetscAssertPointer(lits, 2);
    4952:   *lits = ts->ksp_its;
    4953:   PetscFunctionReturn(PETSC_SUCCESS);
    4954: }

    4956: /*@
    4957:   TSGetStepRejections - Gets the total number of rejected steps.

    4959:   Not Collective

    4961:   Input Parameter:
    4962: . ts - `TS` context

    4964:   Output Parameter:
    4965: . rejects - number of steps rejected

    4967:   Level: intermediate

    4969:   Note:
    4970:   This counter is reset to zero for each successive call to `TSSolve()`.

    4972: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetSNESFailures()`, `TSSetMaxSNESFailures()`, `TSSetErrorIfStepFails()`
    4973: @*/
    4974: PetscErrorCode TSGetStepRejections(TS ts, PetscInt *rejects)
    4975: {
    4976:   PetscFunctionBegin;
    4978:   PetscAssertPointer(rejects, 2);
    4979:   *rejects = ts->reject;
    4980:   PetscFunctionReturn(PETSC_SUCCESS);
    4981: }

    4983: /*@
    4984:   TSGetSNESFailures - Gets the total number of failed `SNES` solves in a `TS`

    4986:   Not Collective

    4988:   Input Parameter:
    4989: . ts - `TS` context

    4991:   Output Parameter:
    4992: . fails - number of failed nonlinear solves

    4994:   Level: intermediate

    4996:   Note:
    4997:   This counter is reset to zero for each successive call to `TSSolve()`.

    4999: .seealso: [](ch_ts), `TS`, `TSSolve()`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetStepRejections()`, `TSSetMaxSNESFailures()`
    5000: @*/
    5001: PetscErrorCode TSGetSNESFailures(TS ts, PetscInt *fails)
    5002: {
    5003:   PetscFunctionBegin;
    5005:   PetscAssertPointer(fails, 2);
    5006:   *fails = ts->num_snes_failures;
    5007:   PetscFunctionReturn(PETSC_SUCCESS);
    5008: }

    5010: /*@
    5011:   TSSetMaxStepRejections - Sets the maximum number of step rejections allowed in a single time-step attempt before a time step fails in `TSSolve()` with `TS_DIVERGED_STEP_REJECTED`

    5013:   Not Collective

    5015:   Input Parameters:
    5016: + ts      - `TS` context
    5017: - rejects - maximum number of rejected steps, pass `PETSC_UNLIMITED` for unlimited

    5019:   Options Database Key:
    5020: . -ts_max_step_rejections - Maximum number of step rejections before a step fails

    5022:   Level: intermediate

    5024:   Developer Note:
    5025:   The options database name is incorrect.

    5027: .seealso: [](ch_ts), `TS`, `SNES`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxSNESFailures()`, `TSGetStepRejections()`, `TSGetSNESFailures()`, `TSSetErrorIfStepFails()`,
    5028:           `TSGetConvergedReason()`, `TSSolve()`, `TS_DIVERGED_STEP_REJECTED`
    5029: @*/
    5030: PetscErrorCode TSSetMaxStepRejections(TS ts, PetscInt rejects)
    5031: {
    5032:   PetscFunctionBegin;
    5034:   if (rejects == PETSC_UNLIMITED || rejects == -1) {
    5035:     ts->max_reject = PETSC_UNLIMITED;
    5036:   } else {
    5037:     PetscCheck(rejects >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a negative maximum number of rejections");
    5038:     ts->max_reject = rejects;
    5039:   }
    5040:   PetscFunctionReturn(PETSC_SUCCESS);
    5041: }

    5043: /*@
    5044:   TSSetMaxSNESFailures - Sets the maximum number of failed `SNES` solves allowed before `TSSolve()` is ended with a `TSConvergedReason` of `TS_DIVERGED_NONLINEAR_SOLVE`

    5046:   Not Collective

    5048:   Input Parameters:
    5049: + ts    - `TS` context
    5050: - fails - maximum number of failed nonlinear solves, pass `PETSC_UNLIMITED` to allow any number of failures.

    5052:   Options Database Key:
    5053: . -ts_max_snes_failures - Maximum number of nonlinear solve failures

    5055:   Level: intermediate

    5057: .seealso: [](ch_ts), `TS`, `SNES`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetStepRejections()`, `TSGetSNESFailures()`, `SNESGetConvergedReason()`,
    5058:           `TSGetConvergedReason()`, `TS_DIVERGED_NONLINEAR_SOLVE`, `TSConvergedReason`
    5059: @*/
    5060: PetscErrorCode TSSetMaxSNESFailures(TS ts, PetscInt fails)
    5061: {
    5062:   PetscFunctionBegin;
    5064:   if (fails == PETSC_UNLIMITED || fails == -1) {
    5065:     ts->max_snes_failures = PETSC_UNLIMITED;
    5066:   } else {
    5067:     PetscCheck(fails >= 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a negative maximum number of failures");
    5068:     ts->max_snes_failures = fails;
    5069:   }
    5070:   PetscFunctionReturn(PETSC_SUCCESS);
    5071: }

    5073: /*@
    5074:   TSSetErrorIfStepFails - Immediately error if no step succeeds during `TSSolve()`

    5076:   Not Collective

    5078:   Input Parameters:
    5079: + ts  - `TS` context
    5080: - err - `PETSC_TRUE` to error if no step succeeds, `PETSC_FALSE` to return without failure

    5082:   Options Database Key:
    5083: . -ts_error_if_step_fails - Error if no step succeeds

    5085:   Level: intermediate

    5087: .seealso: [](ch_ts), `TS`, `TSGetSNESIterations()`, `TSGetKSPIterations()`, `TSSetMaxStepRejections()`, `TSGetStepRejections()`, `TSGetSNESFailures()`, `TSGetConvergedReason()`
    5088: @*/
    5089: PetscErrorCode TSSetErrorIfStepFails(TS ts, PetscBool err)
    5090: {
    5091:   PetscFunctionBegin;
    5093:   ts->errorifstepfailed = err;
    5094:   PetscFunctionReturn(PETSC_SUCCESS);
    5095: }

    5097: /*@
    5098:   TSGetAdapt - Get the adaptive controller context for the current method

    5100:   Collective if controller has not yet been created

    5102:   Input Parameter:
    5103: . ts - time stepping context

    5105:   Output Parameter:
    5106: . adapt - adaptive controller

    5108:   Level: intermediate

    5110: .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSAdaptSetType()`, `TSAdaptChoose()`
    5111: @*/
    5112: PetscErrorCode TSGetAdapt(TS ts, TSAdapt *adapt)
    5113: {
    5114:   PetscFunctionBegin;
    5116:   PetscAssertPointer(adapt, 2);
    5117:   if (!ts->adapt) {
    5118:     PetscCall(TSAdaptCreate(PetscObjectComm((PetscObject)ts), &ts->adapt));
    5119:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ts->adapt, (PetscObject)ts, 1));
    5120:   }
    5121:   *adapt = ts->adapt;
    5122:   PetscFunctionReturn(PETSC_SUCCESS);
    5123: }

    5125: /*@
    5126:   TSSetTolerances - Set tolerances for local truncation error when using an adaptive controller

    5128:   Logically Collective

    5130:   Input Parameters:
    5131: + ts    - time integration context
    5132: . atol  - scalar absolute tolerances
    5133: . vatol - vector of absolute tolerances or `NULL`, used in preference to `atol` if present
    5134: . rtol  - scalar relative tolerances
    5135: - vrtol - vector of relative tolerances or `NULL`, used in preference to `rtol` if present

    5137:   Options Database Keys:
    5138: + -ts_rtol rtol - relative tolerance for local truncation error
    5139: - -ts_atol atol - Absolute tolerance for local truncation error

    5141:   Level: beginner

    5143:   Notes:
    5144:   `PETSC_CURRENT` or `PETSC_DETERMINE` may be used for `atol` or `rtol` to indicate the current value
    5145:   or the default value from when the object's type was set.

    5147:   With PETSc's implicit schemes for DAE problems, the calculation of the local truncation error
    5148:   (LTE) includes both the differential and the algebraic variables. If one wants the LTE to be
    5149:   computed only for the differential or the algebraic part then this can be done using the vector of
    5150:   tolerances vatol. For example, by setting the tolerance vector with the desired tolerance for the
    5151:   differential part and infinity for the algebraic part, the LTE calculation will include only the
    5152:   differential variables.

    5154:   Fortran Note:
    5155:   Use `PETSC_CURRENT_INTEGER` or `PETSC_DETERMINE_INTEGER`.

    5157: .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSErrorWeightedNorm()`, `TSGetTolerances()`
    5158: @*/
    5159: PetscErrorCode TSSetTolerances(TS ts, PetscReal atol, Vec vatol, PetscReal rtol, Vec vrtol)
    5160: {
    5161:   PetscFunctionBegin;
    5162:   if (atol == (PetscReal)PETSC_DETERMINE) {
    5163:     ts->atol = ts->default_atol;
    5164:   } else if (atol != (PetscReal)PETSC_CURRENT) {
    5165:     PetscCheck(atol >= 0.0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g must be non-negative", (double)atol);
    5166:     ts->atol = atol;
    5167:   }

    5169:   if (vatol) {
    5170:     PetscCall(PetscObjectReference((PetscObject)vatol));
    5171:     PetscCall(VecDestroy(&ts->vatol));
    5172:     ts->vatol = vatol;
    5173:   }

    5175:   if (rtol == (PetscReal)PETSC_DETERMINE) {
    5176:     ts->rtol = ts->default_rtol;
    5177:   } else if (rtol != (PetscReal)PETSC_CURRENT) {
    5178:     PetscCheck(rtol >= 0.0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_OUTOFRANGE, "Relative tolerance %g must be non-negative", (double)rtol);
    5179:     ts->rtol = rtol;
    5180:   }

    5182:   if (vrtol) {
    5183:     PetscCall(PetscObjectReference((PetscObject)vrtol));
    5184:     PetscCall(VecDestroy(&ts->vrtol));
    5185:     ts->vrtol = vrtol;
    5186:   }
    5187:   PetscFunctionReturn(PETSC_SUCCESS);
    5188: }

    5190: /*@
    5191:   TSGetTolerances - Get tolerances for local truncation error when using adaptive controller

    5193:   Logically Collective

    5195:   Input Parameter:
    5196: . ts - time integration context

    5198:   Output Parameters:
    5199: + atol  - scalar absolute tolerances, `NULL` to ignore
    5200: . vatol - vector of absolute tolerances, `NULL` to ignore
    5201: . rtol  - scalar relative tolerances, `NULL` to ignore
    5202: - vrtol - vector of relative tolerances, `NULL` to ignore

    5204:   Level: beginner

    5206: .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSErrorWeightedNorm()`, `TSSetTolerances()`
    5207: @*/
    5208: PetscErrorCode TSGetTolerances(TS ts, PetscReal *atol, Vec *vatol, PetscReal *rtol, Vec *vrtol)
    5209: {
    5210:   PetscFunctionBegin;
    5211:   if (atol) *atol = ts->atol;
    5212:   if (vatol) *vatol = ts->vatol;
    5213:   if (rtol) *rtol = ts->rtol;
    5214:   if (vrtol) *vrtol = ts->vrtol;
    5215:   PetscFunctionReturn(PETSC_SUCCESS);
    5216: }

    5218: /*@
    5219:   TSErrorWeightedNorm - compute a weighted norm of the difference between two state vectors based on supplied absolute and relative tolerances

    5221:   Collective

    5223:   Input Parameters:
    5224: + ts        - time stepping context
    5225: . U         - state vector, usually ts->vec_sol
    5226: . Y         - state vector to be compared to U
    5227: - wnormtype - norm type, either `NORM_2` or `NORM_INFINITY`

    5229:   Output Parameters:
    5230: + norm  - weighted norm, a value of 1.0 achieves a balance between absolute and relative tolerances
    5231: . norma - weighted norm, a value of 1.0 means that the error meets the absolute tolerance set by the user
    5232: - normr - weighted norm, a value of 1.0 means that the error meets the relative tolerance set by the user

    5234:   Options Database Key:
    5235: . -ts_adapt_wnormtype wnormtype - 2, INFINITY

    5237:   Level: developer

    5239: .seealso: [](ch_ts), `TS`, `VecErrorWeightedNorms()`, `TSErrorWeightedENorm()`
    5240: @*/
    5241: PetscErrorCode TSErrorWeightedNorm(TS ts, Vec U, Vec Y, NormType wnormtype, PetscReal *norm, PetscReal *norma, PetscReal *normr)
    5242: {
    5243:   PetscInt norma_loc, norm_loc, normr_loc;

    5245:   PetscFunctionBegin;
    5250:   PetscAssertPointer(norm, 5);
    5251:   PetscAssertPointer(norma, 6);
    5252:   PetscAssertPointer(normr, 7);
    5253:   PetscCall(VecErrorWeightedNorms(U, Y, NULL, wnormtype, ts->atol, ts->vatol, ts->rtol, ts->vrtol, ts->adapt->ignore_max, norm, &norm_loc, norma, &norma_loc, normr, &normr_loc));
    5254:   if (wnormtype == NORM_2) {
    5255:     if (norm_loc) *norm = PetscSqrtReal(PetscSqr(*norm) / norm_loc);
    5256:     if (norma_loc) *norma = PetscSqrtReal(PetscSqr(*norma) / norma_loc);
    5257:     if (normr_loc) *normr = PetscSqrtReal(PetscSqr(*normr) / normr_loc);
    5258:   }
    5259:   PetscCheck(!PetscIsInfOrNanScalar(*norm), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
    5260:   PetscCheck(!PetscIsInfOrNanScalar(*norma), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norma");
    5261:   PetscCheck(!PetscIsInfOrNanScalar(*normr), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in normr");
    5262:   PetscFunctionReturn(PETSC_SUCCESS);
    5263: }

    5265: /*@
    5266:   TSErrorWeightedENorm - compute a weighted error norm based on supplied absolute and relative tolerances

    5268:   Collective

    5270:   Input Parameters:
    5271: + ts        - time stepping context
    5272: . E         - error vector
    5273: . U         - state vector, usually ts->vec_sol
    5274: . Y         - state vector, previous time step
    5275: - wnormtype - norm type, either `NORM_2` or `NORM_INFINITY`

    5277:   Output Parameters:
    5278: + norm  - weighted norm, a value of 1.0 achieves a balance between absolute and relative tolerances
    5279: . norma - weighted norm, a value of 1.0 means that the error meets the absolute tolerance set by the user
    5280: - normr - weighted norm, a value of 1.0 means that the error meets the relative tolerance set by the user

    5282:   Options Database Key:
    5283: . -ts_adapt_wnormtype wnormtype - 2, INFINITY

    5285:   Level: developer

    5287: .seealso: [](ch_ts), `TS`, `VecErrorWeightedNorms()`, `TSErrorWeightedNorm()`
    5288: @*/
    5289: PetscErrorCode TSErrorWeightedENorm(TS ts, Vec E, Vec U, Vec Y, NormType wnormtype, PetscReal *norm, PetscReal *norma, PetscReal *normr)
    5290: {
    5291:   PetscInt norma_loc, norm_loc, normr_loc;

    5293:   PetscFunctionBegin;
    5295:   PetscCall(VecErrorWeightedNorms(U, Y, E, wnormtype, ts->atol, ts->vatol, ts->rtol, ts->vrtol, ts->adapt->ignore_max, norm, &norm_loc, norma, &norma_loc, normr, &normr_loc));
    5296:   if (wnormtype == NORM_2) {
    5297:     if (norm_loc) *norm = PetscSqrtReal(PetscSqr(*norm) / norm_loc);
    5298:     if (norma_loc) *norma = PetscSqrtReal(PetscSqr(*norma) / norma_loc);
    5299:     if (normr_loc) *normr = PetscSqrtReal(PetscSqr(*normr) / normr_loc);
    5300:   }
    5301:   PetscCheck(!PetscIsInfOrNanScalar(*norm), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
    5302:   PetscCheck(!PetscIsInfOrNanScalar(*norma), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in norma");
    5303:   PetscCheck(!PetscIsInfOrNanScalar(*normr), PetscObjectComm((PetscObject)ts), PETSC_ERR_FP, "Infinite or not-a-number generated in normr");
    5304:   PetscFunctionReturn(PETSC_SUCCESS);
    5305: }

    5307: /*@
    5308:   TSSetCFLTimeLocal - Set the local CFL constraint relative to forward Euler

    5310:   Logically Collective

    5312:   Input Parameters:
    5313: + ts      - time stepping context
    5314: - cfltime - maximum stable time step if using forward Euler (value can be different on each process)

    5316:   Note:
    5317:   After calling this function, the global CFL time can be obtained by calling TSGetCFLTime()

    5319:   Level: intermediate

    5321: .seealso: [](ch_ts), `TSGetCFLTime()`, `TSADAPTCFL`
    5322: @*/
    5323: PetscErrorCode TSSetCFLTimeLocal(TS ts, PetscReal cfltime)
    5324: {
    5325:   PetscFunctionBegin;
    5327:   ts->cfltime_local = cfltime;
    5328:   ts->cfltime       = -1.;
    5329:   PetscFunctionReturn(PETSC_SUCCESS);
    5330: }

    5332: /*@
    5333:   TSGetCFLTime - Get the maximum stable time step according to CFL criteria applied to forward Euler

    5335:   Collective

    5337:   Input Parameter:
    5338: . ts - time stepping context

    5340:   Output Parameter:
    5341: . cfltime - maximum stable time step for forward Euler

    5343:   Level: advanced

    5345: .seealso: [](ch_ts), `TSSetCFLTimeLocal()`
    5346: @*/
    5347: PetscErrorCode TSGetCFLTime(TS ts, PetscReal *cfltime)
    5348: {
    5349:   PetscFunctionBegin;
    5350:   if (ts->cfltime < 0) PetscCallMPI(MPIU_Allreduce(&ts->cfltime_local, &ts->cfltime, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)ts)));
    5351:   *cfltime = ts->cfltime;
    5352:   PetscFunctionReturn(PETSC_SUCCESS);
    5353: }

    5355: /*@
    5356:   TSVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu

    5358:   Input Parameters:
    5359: + ts - the `TS` context.
    5360: . xl - lower bound.
    5361: - xu - upper bound.

    5363:   Level: advanced

    5365:   Note:
    5366:   If this routine is not called then the lower and upper bounds are set to
    5367:   `PETSC_NINFINITY` and `PETSC_INFINITY` respectively during `SNESSetUp()`.

    5369: .seealso: [](ch_ts), `TS`
    5370: @*/
    5371: PetscErrorCode TSVISetVariableBounds(TS ts, Vec xl, Vec xu)
    5372: {
    5373:   SNES snes;

    5375:   PetscFunctionBegin;
    5376:   PetscCall(TSGetSNES(ts, &snes));
    5377:   PetscCall(SNESVISetVariableBounds(snes, xl, xu));
    5378:   PetscFunctionReturn(PETSC_SUCCESS);
    5379: }

    5381: /*@
    5382:   TSComputeLinearStability - computes the linear stability function at a point

    5384:   Collective

    5386:   Input Parameters:
    5387: + ts - the `TS` context
    5388: . xr - real part of input argument
    5389: - xi - imaginary part of input argument

    5391:   Output Parameters:
    5392: + yr - real part of function value
    5393: - yi - imaginary part of function value

    5395:   Level: developer

    5397: .seealso: [](ch_ts), `TS`, `TSSetRHSFunction()`, `TSComputeIFunction()`
    5398: @*/
    5399: PetscErrorCode TSComputeLinearStability(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi)
    5400: {
    5401:   PetscFunctionBegin;
    5403:   PetscUseTypeMethod(ts, linearstability, xr, xi, yr, yi);
    5404:   PetscFunctionReturn(PETSC_SUCCESS);
    5405: }

    5407: /*@
    5408:   TSRestartStep - Flags the solver to restart the next step

    5410:   Collective

    5412:   Input Parameter:
    5413: . ts - the `TS` context obtained from `TSCreate()`

    5415:   Level: advanced

    5417:   Notes:
    5418:   Multistep methods like `TSBDF` or Runge-Kutta methods with FSAL property require restarting the solver in the event of
    5419:   discontinuities. These discontinuities may be introduced as a consequence of explicitly modifications to the solution
    5420:   vector (which PETSc attempts to detect and handle) or problem coefficients (which PETSc is not able to detect). For
    5421:   the sake of correctness and maximum safety, users are expected to call `TSRestart()` whenever they introduce
    5422:   discontinuities in callback routines (e.g. prestep and poststep routines, or implicit/rhs function routines with
    5423:   discontinuous source terms).

    5425: .seealso: [](ch_ts), `TS`, `TSBDF`, `TSSolve()`, `TSSetPreStep()`, `TSSetPostStep()`
    5426: @*/
    5427: PetscErrorCode TSRestartStep(TS ts)
    5428: {
    5429:   PetscFunctionBegin;
    5431:   ts->steprestart = PETSC_TRUE;
    5432:   PetscFunctionReturn(PETSC_SUCCESS);
    5433: }

    5435: /*@
    5436:   TSRollBack - Rolls back one time step

    5438:   Collective

    5440:   Input Parameter:
    5441: . ts - the `TS` context obtained from `TSCreate()`

    5443:   Level: advanced

    5445: .seealso: [](ch_ts), `TS`, `TSGetStepRollBack()`, `TSCreate()`, `TSSetUp()`, `TSDestroy()`, `TSSolve()`, `TSSetPreStep()`, `TSSetPreStage()`, `TSInterpolate()`
    5446: @*/
    5447: PetscErrorCode TSRollBack(TS ts)
    5448: {
    5449:   PetscFunctionBegin;
    5451:   PetscCheck(!ts->steprollback, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "TSRollBack already called");
    5452:   PetscTryTypeMethod(ts, rollback);
    5453:   PetscCall(VecCopy(ts->vec_sol0, ts->vec_sol));
    5454:   ts->time_step  = ts->ptime - ts->ptime_prev;
    5455:   ts->ptime      = ts->ptime_prev;
    5456:   ts->ptime_prev = ts->ptime_prev_rollback;
    5457:   ts->steps--;
    5458:   ts->steprollback = PETSC_TRUE;
    5459:   PetscFunctionReturn(PETSC_SUCCESS);
    5460: }

    5462: /*@
    5463:   TSGetStepRollBack - Get the internal flag indicating if you are rolling back a step

    5465:   Not collective

    5467:   Input Parameter:
    5468: . ts - the `TS` context obtained from `TSCreate()`

    5470:   Output Parameter:
    5471: . flg - the rollback flag

    5473:   Level: advanced

    5475: .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSRollBack()`
    5476: @*/
    5477: PetscErrorCode TSGetStepRollBack(TS ts, PetscBool *flg)
    5478: {
    5479:   PetscFunctionBegin;
    5481:   PetscAssertPointer(flg, 2);
    5482:   *flg = ts->steprollback;
    5483:   PetscFunctionReturn(PETSC_SUCCESS);
    5484: }

    5486: /*@
    5487:   TSGetStepResize - Get the internal flag indicating if the current step is after a resize.

    5489:   Not collective

    5491:   Input Parameter:
    5492: . ts - the `TS` context obtained from `TSCreate()`

    5494:   Output Parameter:
    5495: . flg - the resize flag

    5497:   Level: advanced

    5499: .seealso: [](ch_ts), `TS`, `TSCreate()`, `TSSetResize()`
    5500: @*/
    5501: PetscErrorCode TSGetStepResize(TS ts, PetscBool *flg)
    5502: {
    5503:   PetscFunctionBegin;
    5505:   PetscAssertPointer(flg, 2);
    5506:   *flg = ts->stepresize;
    5507:   PetscFunctionReturn(PETSC_SUCCESS);
    5508: }

    5510: /*@
    5511:   TSGetStages - Get the number of stages and stage values

    5513:   Input Parameter:
    5514: . ts - the `TS` context obtained from `TSCreate()`

    5516:   Output Parameters:
    5517: + ns - the number of stages
    5518: - Y  - the current stage vectors

    5520:   Level: advanced

    5522:   Note:
    5523:   Both `ns` and `Y` can be `NULL`.

    5525: .seealso: [](ch_ts), `TS`, `TSCreate()`
    5526: @*/
    5527: PetscErrorCode TSGetStages(TS ts, PetscInt *ns, Vec **Y)
    5528: {
    5529:   PetscFunctionBegin;
    5531:   if (ns) PetscAssertPointer(ns, 2);
    5532:   if (Y) PetscAssertPointer(Y, 3);
    5533:   if (!ts->ops->getstages) {
    5534:     if (ns) *ns = 0;
    5535:     if (Y) *Y = NULL;
    5536:   } else PetscUseTypeMethod(ts, getstages, ns, Y);
    5537:   PetscFunctionReturn(PETSC_SUCCESS);
    5538: }

    5540: /*@C
    5541:   TSComputeIJacobianDefaultColor - Computes the Jacobian using finite differences and coloring to exploit matrix sparsity.

    5543:   Collective

    5545:   Input Parameters:
    5546: + ts    - the `TS` context
    5547: . t     - current timestep
    5548: . U     - state vector
    5549: . Udot  - time derivative of state vector
    5550: . shift - shift to apply, see note below
    5551: - ctx   - an optional user context

    5553:   Output Parameters:
    5554: + J - Jacobian matrix (not altered in this routine)
    5555: - B - newly computed Jacobian matrix to use with preconditioner (generally the same as `J`)

    5557:   Level: intermediate

    5559:   Notes:
    5560:   If F(t,U,Udot)=0 is the DAE, the required Jacobian is

    5562:   dF/dU + shift*dF/dUdot

    5564:   Most users should not need to explicitly call this routine, as it
    5565:   is used internally within the nonlinear solvers.

    5567:   This will first try to get the coloring from the `DM`.  If the `DM` type has no coloring
    5568:   routine, then it will try to get the coloring from the matrix.  This requires that the
    5569:   matrix have nonzero entries precomputed.

    5571: .seealso: [](ch_ts), `TS`, `TSSetIJacobian()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
    5572: @*/
    5573: PetscErrorCode TSComputeIJacobianDefaultColor(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal shift, Mat J, Mat B, PetscCtx ctx)
    5574: {
    5575:   SNES          snes;
    5576:   MatFDColoring color;
    5577:   PetscBool     hascolor, matcolor = PETSC_FALSE;

    5579:   PetscFunctionBegin;
    5580:   PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_fd_color_use_mat", &matcolor, NULL));
    5581:   PetscCall(PetscObjectQuery((PetscObject)B, "TSMatFDColoring", (PetscObject *)&color));
    5582:   if (!color) {
    5583:     DM         dm;
    5584:     ISColoring iscoloring;

    5586:     PetscCall(TSGetDM(ts, &dm));
    5587:     PetscCall(DMHasColoring(dm, &hascolor));
    5588:     if (hascolor && !matcolor) {
    5589:       PetscCall(DMCreateColoring(dm, IS_COLORING_GLOBAL, &iscoloring));
    5590:       PetscCall(MatFDColoringCreate(B, iscoloring, &color));
    5591:       PetscCall(MatFDColoringSetFunction(color, (MatFDColoringFn *)SNESTSFormFunction, (void *)ts));
    5592:       PetscCall(MatFDColoringSetFromOptions(color));
    5593:       PetscCall(MatFDColoringSetUp(B, iscoloring, color));
    5594:       PetscCall(ISColoringDestroy(&iscoloring));
    5595:     } else {
    5596:       MatColoring mc;

    5598:       PetscCall(MatColoringCreate(B, &mc));
    5599:       PetscCall(MatColoringSetDistance(mc, 2));
    5600:       PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
    5601:       PetscCall(MatColoringSetFromOptions(mc));
    5602:       PetscCall(MatColoringApply(mc, &iscoloring));
    5603:       PetscCall(MatColoringDestroy(&mc));
    5604:       PetscCall(MatFDColoringCreate(B, iscoloring, &color));
    5605:       PetscCall(MatFDColoringSetFunction(color, (MatFDColoringFn *)SNESTSFormFunction, (void *)ts));
    5606:       PetscCall(MatFDColoringSetFromOptions(color));
    5607:       PetscCall(MatFDColoringSetUp(B, iscoloring, color));
    5608:       PetscCall(ISColoringDestroy(&iscoloring));
    5609:     }
    5610:     PetscCall(PetscObjectCompose((PetscObject)B, "TSMatFDColoring", (PetscObject)color));
    5611:     PetscCall(PetscObjectDereference((PetscObject)color));
    5612:   }
    5613:   PetscCall(TSGetSNES(ts, &snes));
    5614:   PetscCall(MatFDColoringApply(B, color, U, snes));
    5615:   if (J != B) {
    5616:     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
    5617:     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
    5618:   }
    5619:   PetscFunctionReturn(PETSC_SUCCESS);
    5620: }

    5622: /*@C
    5623:   TSSetFunctionDomainError - Set a function that tests if the current state vector is valid

    5625:   Logically collective

    5627:   Input Parameters:
    5628: + ts   - the `TS` context
    5629: - func - function called within `TSFunctionDomainError()`

    5631:   Calling sequence of `func`:
    5632: + ts     - the `TS` context
    5633: . time   - the current time (of the stage)
    5634: . state  - the state to check if it is valid
    5635: - accept - (output parameter) `PETSC_FALSE` if the state is not acceptable, `PETSC_TRUE` if acceptable

    5637:   Level: intermediate

    5639:   Notes:
    5640:   `accept` must be collectively specified.
    5641:   If an implicit ODE solver is being used then, in addition to providing this routine, the
    5642:   user's code should call `SNESSetFunctionDomainError()` when domain errors occur during
    5643:   function evaluations where the functions are provided by `TSSetIFunction()` or `TSSetRHSFunction()`.
    5644:   Use `TSGetSNES()` to obtain the `SNES` object

    5646:   Developer Notes:
    5647:   The naming of this function is inconsistent with the `SNESSetFunctionDomainError()`
    5648:   since one takes a function pointer and the other does not.

    5650: .seealso: [](ch_ts), `TSAdaptCheckStage()`, `TSFunctionDomainError()`, `SNESSetFunctionDomainError()`, `TSGetSNES()`
    5651: @*/
    5652: PetscErrorCode TSSetFunctionDomainError(TS ts, PetscErrorCode (*func)(TS ts, PetscReal time, Vec state, PetscBool *accept))
    5653: {
    5654:   PetscFunctionBegin;
    5656:   ts->functiondomainerror = func;
    5657:   PetscFunctionReturn(PETSC_SUCCESS);
    5658: }

    5660: /*@
    5661:   TSFunctionDomainError - Checks if the current state is valid

    5663:   Collective

    5665:   Input Parameters:
    5666: + ts        - the `TS` context
    5667: . stagetime - time of the simulation
    5668: - Y         - state vector to check.

    5670:   Output Parameter:
    5671: . accept - Set to `PETSC_FALSE` if the current state vector is valid.

    5673:   Level: developer

    5675:   Note:
    5676:   This function is called by the `TS` integration routines and calls the user provided function (set with `TSSetFunctionDomainError()`)
    5677:   to check if the current state is valid.

    5679: .seealso: [](ch_ts), `TS`, `TSSetFunctionDomainError()`
    5680: @*/
    5681: PetscErrorCode TSFunctionDomainError(TS ts, PetscReal stagetime, Vec Y, PetscBool *accept)
    5682: {
    5683:   PetscFunctionBegin;
    5687:   PetscAssertPointer(accept, 4);
    5688:   *accept = PETSC_TRUE;
    5689:   if (ts->functiondomainerror) PetscCall((*ts->functiondomainerror)(ts, stagetime, Y, accept));
    5690:   PetscFunctionReturn(PETSC_SUCCESS);
    5691: }

    5693: /*@
    5694:   TSClone - This function clones a time step `TS` object.

    5696:   Collective

    5698:   Input Parameter:
    5699: . tsin - The input `TS`

    5701:   Output Parameter:
    5702: . tsout - The output `TS` (cloned)

    5704:   Level: developer

    5706:   Notes:
    5707:   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.
    5708:   It will likely be replaced in the future with a mechanism of switching methods on the fly.

    5710:   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
    5711: .vb
    5712:  SNES snes_dup = NULL;
    5713:  TSGetSNES(ts,&snes_dup);
    5714:  TSSetSNES(ts,snes_dup);
    5715: .ve

    5717: .seealso: [](ch_ts), `TS`, `SNES`, `TSCreate()`, `TSSetType()`, `TSSetUp()`, `TSDestroy()`, `TSSetProblemType()`
    5718: @*/
    5719: PetscErrorCode TSClone(TS tsin, TS *tsout)
    5720: {
    5721:   TS     t;
    5722:   SNES   snes_start;
    5723:   DM     dm;
    5724:   TSType type;

    5726:   PetscFunctionBegin;
    5727:   PetscAssertPointer(tsin, 1);
    5728:   *tsout = NULL;

    5730:   PetscCall(PetscHeaderCreate(t, TS_CLASSID, "TS", "Time stepping", "TS", PetscObjectComm((PetscObject)tsin), TSDestroy, TSView));

    5732:   /* General TS description */
    5733:   t->numbermonitors    = 0;
    5734:   t->setupcalled       = PETSC_FALSE;
    5735:   t->ksp_its           = 0;
    5736:   t->snes_its          = 0;
    5737:   t->nwork             = 0;
    5738:   t->rhsjacobian.time  = PETSC_MIN_REAL;
    5739:   t->rhsjacobian.scale = 1.;
    5740:   t->ijacobian.shift   = 1.;

    5742:   PetscCall(TSGetSNES(tsin, &snes_start));
    5743:   PetscCall(TSSetSNES(t, snes_start));

    5745:   PetscCall(TSGetDM(tsin, &dm));
    5746:   PetscCall(TSSetDM(t, dm));

    5748:   t->adapt = tsin->adapt;
    5749:   PetscCall(PetscObjectReference((PetscObject)t->adapt));

    5751:   t->trajectory = tsin->trajectory;
    5752:   PetscCall(PetscObjectReference((PetscObject)t->trajectory));

    5754:   t->event = tsin->event;
    5755:   if (t->event) t->event->refct++;

    5757:   t->problem_type      = tsin->problem_type;
    5758:   t->ptime             = tsin->ptime;
    5759:   t->ptime_prev        = tsin->ptime_prev;
    5760:   t->time_step         = tsin->time_step;
    5761:   t->max_time          = tsin->max_time;
    5762:   t->steps             = tsin->steps;
    5763:   t->max_steps         = tsin->max_steps;
    5764:   t->equation_type     = tsin->equation_type;
    5765:   t->atol              = tsin->atol;
    5766:   t->rtol              = tsin->rtol;
    5767:   t->max_snes_failures = tsin->max_snes_failures;
    5768:   t->max_reject        = tsin->max_reject;
    5769:   t->errorifstepfailed = tsin->errorifstepfailed;

    5771:   PetscCall(TSGetType(tsin, &type));
    5772:   PetscCall(TSSetType(t, type));

    5774:   t->vec_sol = NULL;

    5776:   t->cfltime          = tsin->cfltime;
    5777:   t->cfltime_local    = tsin->cfltime_local;
    5778:   t->exact_final_time = tsin->exact_final_time;

    5780:   t->ops[0] = tsin->ops[0];

    5782:   if (((PetscObject)tsin)->fortran_func_pointers) {
    5783:     PetscInt i;
    5784:     PetscCall(PetscMalloc((10) * sizeof(PetscFortranCallbackFn *), &((PetscObject)t)->fortran_func_pointers));
    5785:     for (i = 0; i < 10; i++) ((PetscObject)t)->fortran_func_pointers[i] = ((PetscObject)tsin)->fortran_func_pointers[i];
    5786:   }
    5787:   *tsout = t;
    5788:   PetscFunctionReturn(PETSC_SUCCESS);
    5789: }

    5791: static PetscErrorCode RHSWrapperFunction_TSRHSJacobianTest(PetscCtx ctx, Vec x, Vec y)
    5792: {
    5793:   TS ts = (TS)ctx;

    5795:   PetscFunctionBegin;
    5796:   PetscCall(TSComputeRHSFunction(ts, 0, x, y));
    5797:   PetscFunctionReturn(PETSC_SUCCESS);
    5798: }

    5800: /*@
    5801:   TSRHSJacobianTest - Compares the multiply routine provided to the `MATSHELL` with differencing on the `TS` given RHS function.

    5803:   Logically Collective

    5805:   Input Parameter:
    5806: . ts - the time stepping routine

    5808:   Output Parameter:
    5809: . flg - `PETSC_TRUE` if the multiply is likely correct

    5811:   Options Database Key:
    5812: . -ts_rhs_jacobian_test_mult -mat_shell_test_mult_view - run the test at each timestep of the integrator

    5814:   Level: advanced

    5816:   Note:
    5817:   This only works for problems defined using `TSSetRHSFunction()` and Jacobian NOT `TSSetIFunction()` and Jacobian

    5819: .seealso: [](ch_ts), `TS`, `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`, `TSRHSJacobianTestTranspose()`
    5820: @*/
    5821: PetscErrorCode TSRHSJacobianTest(TS ts, PetscBool *flg)
    5822: {
    5823:   Mat              J, B;
    5824:   TSRHSJacobianFn *func;
    5825:   void            *ctx;

    5827:   PetscFunctionBegin;
    5828:   PetscCall(TSGetRHSJacobian(ts, &J, &B, &func, &ctx));
    5829:   PetscCall((*func)(ts, 0.0, ts->vec_sol, J, B, ctx));
    5830:   PetscCall(MatShellTestMult(J, RHSWrapperFunction_TSRHSJacobianTest, ts->vec_sol, ts, flg));
    5831:   PetscFunctionReturn(PETSC_SUCCESS);
    5832: }

    5834: /*@
    5835:   TSRHSJacobianTestTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on the `TS` given RHS function.

    5837:   Logically Collective

    5839:   Input Parameter:
    5840: . ts - the time stepping routine

    5842:   Output Parameter:
    5843: . flg - `PETSC_TRUE` if the multiply is likely correct

    5845:   Options Database Key:
    5846: . -ts_rhs_jacobian_test_mult_transpose -mat_shell_test_mult_transpose_view - run the test at each timestep of the integrator

    5848:   Level: advanced

    5850:   Notes:
    5851:   This only works for problems defined using `TSSetRHSFunction()` and Jacobian NOT `TSSetIFunction()` and Jacobian

    5853: .seealso: [](ch_ts), `TS`, `Mat`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`, `TSRHSJacobianTest()`
    5854: @*/
    5855: PetscErrorCode TSRHSJacobianTestTranspose(TS ts, PetscBool *flg)
    5856: {
    5857:   Mat              J, B;
    5858:   void            *ctx;
    5859:   TSRHSJacobianFn *func;

    5861:   PetscFunctionBegin;
    5862:   PetscCall(TSGetRHSJacobian(ts, &J, &B, &func, &ctx));
    5863:   PetscCall((*func)(ts, 0.0, ts->vec_sol, J, B, ctx));
    5864:   PetscCall(MatShellTestMultTranspose(J, RHSWrapperFunction_TSRHSJacobianTest, ts->vec_sol, ts, flg));
    5865:   PetscFunctionReturn(PETSC_SUCCESS);
    5866: }

    5868: /*@
    5869:   TSSetUseSplitRHSFunction - Use the split RHSFunction when a multirate method is used.

    5871:   Logically Collective

    5873:   Input Parameters:
    5874: + ts                   - timestepping context
    5875: - use_splitrhsfunction - `PETSC_TRUE` indicates that the split RHSFunction will be used

    5877:   Options Database Key:
    5878: . -ts_use_splitrhsfunction (true|false) - use the split RHS function for multirate solvers

    5880:   Level: intermediate

    5882:   Note:
    5883:   This is only for multirate methods

    5885: .seealso: [](ch_ts), `TS`, `TSGetUseSplitRHSFunction()`
    5886: @*/
    5887: PetscErrorCode TSSetUseSplitRHSFunction(TS ts, PetscBool use_splitrhsfunction)
    5888: {
    5889:   PetscFunctionBegin;
    5891:   ts->use_splitrhsfunction = use_splitrhsfunction;
    5892:   PetscFunctionReturn(PETSC_SUCCESS);
    5893: }

    5895: /*@
    5896:   TSGetUseSplitRHSFunction - Gets whether to use the split RHSFunction when a multirate method is used.

    5898:   Not Collective

    5900:   Input Parameter:
    5901: . ts - timestepping context

    5903:   Output Parameter:
    5904: . use_splitrhsfunction - `PETSC_TRUE` indicates that the split RHSFunction will be used

    5906:   Level: intermediate

    5908: .seealso: [](ch_ts), `TS`, `TSSetUseSplitRHSFunction()`
    5909: @*/
    5910: PetscErrorCode TSGetUseSplitRHSFunction(TS ts, PetscBool *use_splitrhsfunction)
    5911: {
    5912:   PetscFunctionBegin;
    5914:   *use_splitrhsfunction = ts->use_splitrhsfunction;
    5915:   PetscFunctionReturn(PETSC_SUCCESS);
    5916: }

    5918: /*@
    5919:   TSSetMatStructure - sets the relationship between the nonzero structure of the RHS Jacobian matrix to the IJacobian matrix.

    5921:   Logically  Collective

    5923:   Input Parameters:
    5924: + ts  - the time-stepper
    5925: - str - the structure (the default is `UNKNOWN_NONZERO_PATTERN`)

    5927:   Level: intermediate

    5929:   Note:
    5930:   When the relationship between the nonzero structures is known and supplied the solution process can be much faster

    5932: .seealso: [](ch_ts), `TS`, `MatAXPY()`, `MatStructure`
    5933:  @*/
    5934: PetscErrorCode TSSetMatStructure(TS ts, MatStructure str)
    5935: {
    5936:   PetscFunctionBegin;
    5938:   ts->axpy_pattern = str;
    5939:   PetscFunctionReturn(PETSC_SUCCESS);
    5940: }

    5942: /*@
    5943:   TSSetEvaluationTimes - sets the evaluation points. The solution will be computed and stored for each time requested

    5945:   Collective

    5947:   Input Parameters:
    5948: + ts          - the time-stepper
    5949: . n           - number of the time points
    5950: - time_points - array of the time points, must be increasing

    5952:   Options Database Key:
    5953: . -ts_eval_times t0,...,tn - Sets the evaluation times

    5955:   Level: intermediate

    5957:   Notes:
    5958:   The elements in `time_points` must be all increasing. They correspond to the intermediate points to be saved.

    5960:   `TS_EXACTFINALTIME_MATCHSTEP` must be used to make the last time step in each sub-interval match the intermediate points specified.

    5962:   The intermediate solutions are saved in a vector array that can be accessed with `TSGetEvaluationSolutions()`. Thus using evaluation times may
    5963:   pressure the memory system when using a large number of time points.

    5965: .seealso: [](ch_ts), `TS`, `TSGetEvaluationTimes()`, `TSGetEvaluationSolutions()`, `TSSetTimeSpan()`
    5966:  @*/
    5967: PetscErrorCode TSSetEvaluationTimes(TS ts, PetscInt n, PetscReal time_points[])
    5968: {
    5969:   PetscBool is_sorted;

    5971:   PetscFunctionBegin;
    5973:   if (ts->eval_times) { // Reset eval_times
    5974:     ts->eval_times->sol_idx        = 0;
    5975:     ts->eval_times->time_point_idx = 0;
    5976:     if (n != ts->eval_times->num_time_points) {
    5977:       PetscCall(PetscFree(ts->eval_times->time_points));
    5978:       PetscCall(PetscFree(ts->eval_times->sol_times));
    5979:       PetscCall(VecDestroyVecs(ts->eval_times->num_time_points, &ts->eval_times->sol_vecs));
    5980:     } else {
    5981:       PetscCall(PetscArrayzero(ts->eval_times->sol_times, n));
    5982:       for (PetscInt i = 0; i < n; i++) PetscCall(VecZeroEntries(ts->eval_times->sol_vecs[i]));
    5983:     }
    5984:   } else { // Create/initialize eval_times
    5985:     TSEvaluationTimes eval_times;
    5986:     PetscCall(PetscNew(&eval_times));
    5987:     PetscCall(PetscMalloc1(n, &eval_times->time_points));
    5988:     PetscCall(PetscMalloc1(n, &eval_times->sol_times));
    5989:     eval_times->reltol  = 1e-6;
    5990:     eval_times->abstol  = 10 * PETSC_MACHINE_EPSILON;
    5991:     eval_times->worktol = 0;
    5992:     ts->eval_times      = eval_times;
    5993:   }
    5994:   ts->eval_times->num_time_points = n;
    5995:   PetscCall(PetscSortedReal(n, time_points, &is_sorted));
    5996:   PetscCheck(is_sorted, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONG, "time_points array must be sorted");
    5997:   PetscCall(PetscArraycpy(ts->eval_times->time_points, time_points, n));
    5998:   // Note: ts->vec_sol not guaranteed to exist, so ts->eval_times->sol_vecs allocated at TSSolve time
    5999:   PetscFunctionReturn(PETSC_SUCCESS);
    6000: }

    6002: /*@C
    6003:   TSGetEvaluationTimes - gets the evaluation times set with `TSSetEvaluationTimes()`

    6005:   Not Collective

    6007:   Input Parameter:
    6008: . ts - the time-stepper

    6010:   Output Parameters:
    6011: + n           - number of the time points
    6012: - time_points - array of the time points

    6014:   Level: beginner

    6016:   Note:
    6017:   The values obtained are valid until the `TS` object is destroyed.

    6019:   Both `n` and `time_points` can be `NULL`.

    6021:   Also used to see time points set by `TSSetTimeSpan()`.

    6023: .seealso: [](ch_ts), `TS`, `TSSetEvaluationTimes()`, `TSGetEvaluationSolutions()`
    6024:  @*/
    6025: PetscErrorCode TSGetEvaluationTimes(TS ts, PetscInt *n, const PetscReal *time_points[])
    6026: {
    6027:   PetscFunctionBegin;
    6029:   if (n) PetscAssertPointer(n, 2);
    6030:   if (time_points) PetscAssertPointer(time_points, 3);
    6031:   if (!ts->eval_times) {
    6032:     if (n) *n = 0;
    6033:     if (time_points) *time_points = NULL;
    6034:   } else {
    6035:     if (n) *n = ts->eval_times->num_time_points;
    6036:     if (time_points) *time_points = ts->eval_times->time_points;
    6037:   }
    6038:   PetscFunctionReturn(PETSC_SUCCESS);
    6039: }

    6041: /*@C
    6042:   TSGetEvaluationSolutions - Get the number of solutions and the solutions at the evaluation time points specified

    6044:   Input Parameter:
    6045: . ts - the `TS` context obtained from `TSCreate()`

    6047:   Output Parameters:
    6048: + nsol      - the number of solutions
    6049: . sol_times - array of solution times corresponding to the solution vectors. See note below
    6050: - Sols      - the solution vectors

    6052:   Level: intermediate

    6054:   Notes:
    6055:   Both `nsol` and `Sols` can be `NULL`.

    6057:   Some time points in the evaluation points may be skipped by `TS` so that `nsol` is less than the number of points specified by `TSSetEvaluationTimes()`.
    6058:   For example, manipulating the step size, especially with a reduced precision, may cause `TS` to step over certain evaluation times.

    6060:   Also used to see view solutions requested by `TSSetTimeSpan()`.

    6062: .seealso: [](ch_ts), `TS`, `TSSetEvaluationTimes()`, `TSGetEvaluationTimes()`
    6063: @*/
    6064: PetscErrorCode TSGetEvaluationSolutions(TS ts, PetscInt *nsol, const PetscReal *sol_times[], Vec *Sols[])
    6065: {
    6066:   PetscFunctionBegin;
    6068:   if (nsol) PetscAssertPointer(nsol, 2);
    6069:   if (sol_times) PetscAssertPointer(sol_times, 3);
    6070:   if (Sols) PetscAssertPointer(Sols, 4);
    6071:   if (!ts->eval_times) {
    6072:     if (nsol) *nsol = 0;
    6073:     if (sol_times) *sol_times = NULL;
    6074:     if (Sols) *Sols = NULL;
    6075:   } else {
    6076:     if (nsol) *nsol = ts->eval_times->sol_idx;
    6077:     if (sol_times) *sol_times = ts->eval_times->sol_times;
    6078:     if (Sols) *Sols = ts->eval_times->sol_vecs;
    6079:   }
    6080:   PetscFunctionReturn(PETSC_SUCCESS);
    6081: }

    6083: /*@
    6084:   TSSetTimeSpan - sets the time span. The solution will be computed and stored for each time requested in the span

    6086:   Collective

    6088:   Input Parameters:
    6089: + ts         - the time-stepper
    6090: . n          - number of the time points (>=2)
    6091: - span_times - array of the time points, must be increasing. The first element and the last element are the initial time and the final time respectively.

    6093:   Options Database Key:
    6094: . -ts_time_span t0,...,tf - Sets the time span

    6096:   Level: intermediate

    6098:   Notes:
    6099:   This function is identical to `TSSetEvaluationTimes()`, except that it also sets the initial time and final time for the `ts` to the first and last `span_times` entries.

    6101:   The elements in `span_times` must be all increasing. They correspond to the intermediate points to be saved.

    6103:   `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 `TSGetEvaluationSolutions()`. Thus using time span may
    6106:   pressure the memory system when using a large number of span points.

    6108: .seealso: [](ch_ts), `TS`, `TSSetEvaluationTimes()`, `TSGetEvaluationTimes()`, `TSGetEvaluationSolutions()`
    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:   PetscCall(TSSetEvaluationTimes(ts, n, span_times));
    6116:   PetscCall(TSSetTime(ts, span_times[0]));
    6117:   PetscCall(TSSetMaxTime(ts, span_times[n - 1]));
    6118:   PetscFunctionReturn(PETSC_SUCCESS);
    6119: }

    6121: /*@
    6122:   TSPruneIJacobianColor - Remove nondiagonal zeros in the Jacobian matrix and update the `MatMFFD` coloring information.

    6124:   Collective

    6126:   Input Parameters:
    6127: + ts - the `TS` context
    6128: . J  - Jacobian matrix (not altered in this routine)
    6129: - B  - newly computed Jacobian matrix to use with preconditioner

    6131:   Level: intermediate

    6133:   Notes:
    6134:   This function improves the `MatFDColoring` performance when the Jacobian matrix was over-allocated or contains
    6135:   many constant zeros entries, which is typically the case when the matrix is generated by a `DM`
    6136:   and multiple fields are involved.

    6138:   Users need to make sure that the Jacobian matrix is properly filled to reflect the sparsity
    6139:   structure. For `MatFDColoring`, the values of nonzero entries are not important. So one can
    6140:   usually call `TSComputeIJacobian()` with randomized input vectors to generate a dummy Jacobian.
    6141:   `TSComputeIJacobian()` should be called before `TSSolve()` but after `TSSetUp()`.

    6143: .seealso: [](ch_ts), `TS`, `MatFDColoring`, `TSComputeIJacobianDefaultColor()`, `MatEliminateZeros()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
    6144: @*/
    6145: PetscErrorCode TSPruneIJacobianColor(TS ts, Mat J, Mat B)
    6146: {
    6147:   MatColoring   mc            = NULL;
    6148:   ISColoring    iscoloring    = NULL;
    6149:   MatFDColoring matfdcoloring = NULL;

    6151:   PetscFunctionBegin;
    6152:   /* Generate new coloring after eliminating zeros in the matrix */
    6153:   PetscCall(MatEliminateZeros(B, PETSC_TRUE));
    6154:   PetscCall(MatColoringCreate(B, &mc));
    6155:   PetscCall(MatColoringSetDistance(mc, 2));
    6156:   PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
    6157:   PetscCall(MatColoringSetFromOptions(mc));
    6158:   PetscCall(MatColoringApply(mc, &iscoloring));
    6159:   PetscCall(MatColoringDestroy(&mc));
    6160:   /* Replace the old coloring with the new one */
    6161:   PetscCall(MatFDColoringCreate(B, iscoloring, &matfdcoloring));
    6162:   PetscCall(MatFDColoringSetFunction(matfdcoloring, (MatFDColoringFn *)SNESTSFormFunction, (void *)ts));
    6163:   PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
    6164:   PetscCall(MatFDColoringSetUp(B, iscoloring, matfdcoloring));
    6165:   PetscCall(PetscObjectCompose((PetscObject)B, "TSMatFDColoring", (PetscObject)matfdcoloring));
    6166:   PetscCall(PetscObjectDereference((PetscObject)matfdcoloring));
    6167:   PetscCall(ISColoringDestroy(&iscoloring));
    6168:   PetscFunctionReturn(PETSC_SUCCESS);
    6169: }