xref: /petsc/src/ts/adapt/interface/tsadapt.c (revision bb4b53ef092968f72b740b90dbab8a2b6700db0d)
1 #include <petsc/private/tsimpl.h> /*I  "petscts.h" I*/
2 
3 PetscClassId TSADAPT_CLASSID;
4 
5 static PetscFunctionList TSAdaptList;
6 static PetscBool         TSAdaptPackageInitialized;
7 static PetscBool         TSAdaptRegisterAllCalled;
8 
9 PETSC_EXTERN PetscErrorCode TSAdaptCreate_None(TSAdapt);
10 PETSC_EXTERN PetscErrorCode TSAdaptCreate_Basic(TSAdapt);
11 PETSC_EXTERN PetscErrorCode TSAdaptCreate_DSP(TSAdapt);
12 PETSC_EXTERN PetscErrorCode TSAdaptCreate_CFL(TSAdapt);
13 PETSC_EXTERN PetscErrorCode TSAdaptCreate_GLEE(TSAdapt);
14 PETSC_EXTERN PetscErrorCode TSAdaptCreate_History(TSAdapt);
15 
16 /*@C
17   TSAdaptRegister -  adds a TSAdapt implementation
18 
19   Not Collective, No Fortran Support
20 
21   Input Parameters:
22 + sname    - name of user-defined adaptivity scheme
23 - function - routine to create method context
24 
25   Level: advanced
26 
27   Notes:
28   `TSAdaptRegister()` may be called multiple times to add several user-defined families.
29 
30   Example Usage:
31 .vb
32    TSAdaptRegister("my_scheme", MySchemeCreate);
33 .ve
34 
35   Then, your scheme can be chosen with the procedural interface via
36 $     TSAdaptSetType(ts, "my_scheme")
37   or at runtime via the option
38 $     -ts_adapt_type my_scheme
39 
40 .seealso: [](ch_ts), `TSAdaptRegisterAll()`
41 @*/
42 PetscErrorCode TSAdaptRegister(const char sname[], PetscErrorCode (*function)(TSAdapt))
43 {
44   PetscFunctionBegin;
45   PetscCall(TSAdaptInitializePackage());
46   PetscCall(PetscFunctionListAdd(&TSAdaptList, sname, function));
47   PetscFunctionReturn(PETSC_SUCCESS);
48 }
49 
50 /*@C
51   TSAdaptRegisterAll - Registers all of the adaptivity schemes in `TSAdapt`
52 
53   Not Collective
54 
55   Level: advanced
56 
57 .seealso: [](ch_ts), `TSAdaptRegisterDestroy()`
58 @*/
59 PetscErrorCode TSAdaptRegisterAll(void)
60 {
61   PetscFunctionBegin;
62   if (TSAdaptRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
63   TSAdaptRegisterAllCalled = PETSC_TRUE;
64   PetscCall(TSAdaptRegister(TSADAPTNONE, TSAdaptCreate_None));
65   PetscCall(TSAdaptRegister(TSADAPTBASIC, TSAdaptCreate_Basic));
66   PetscCall(TSAdaptRegister(TSADAPTDSP, TSAdaptCreate_DSP));
67   PetscCall(TSAdaptRegister(TSADAPTCFL, TSAdaptCreate_CFL));
68   PetscCall(TSAdaptRegister(TSADAPTGLEE, TSAdaptCreate_GLEE));
69   PetscCall(TSAdaptRegister(TSADAPTHISTORY, TSAdaptCreate_History));
70   PetscFunctionReturn(PETSC_SUCCESS);
71 }
72 
73 /*@C
74   TSAdaptFinalizePackage - This function destroys everything in the `TS` package. It is
75   called from `PetscFinalize()`.
76 
77   Level: developer
78 
79 .seealso: [](ch_ts), `PetscFinalize()`
80 @*/
81 PetscErrorCode TSAdaptFinalizePackage(void)
82 {
83   PetscFunctionBegin;
84   PetscCall(PetscFunctionListDestroy(&TSAdaptList));
85   TSAdaptPackageInitialized = PETSC_FALSE;
86   TSAdaptRegisterAllCalled  = PETSC_FALSE;
87   PetscFunctionReturn(PETSC_SUCCESS);
88 }
89 
90 /*@C
91   TSAdaptInitializePackage - This function initializes everything in the `TSAdapt` package. It is
92   called from `TSInitializePackage()`.
93 
94   Level: developer
95 
96 .seealso: [](ch_ts), `PetscInitialize()`
97 @*/
98 PetscErrorCode TSAdaptInitializePackage(void)
99 {
100   PetscFunctionBegin;
101   if (TSAdaptPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
102   TSAdaptPackageInitialized = PETSC_TRUE;
103   PetscCall(PetscClassIdRegister("TSAdapt", &TSADAPT_CLASSID));
104   PetscCall(TSAdaptRegisterAll());
105   PetscCall(PetscRegisterFinalize(TSAdaptFinalizePackage));
106   PetscFunctionReturn(PETSC_SUCCESS);
107 }
108 
109 /*@
110   TSAdaptSetType - sets the approach used for the error adapter
111 
112   Logicially Collective
113 
114   Input Parameters:
115 + adapt - the `TS` adapter, most likely obtained with `TSGetAdapt()`
116 - type  - one of the `TSAdaptType`
117 
118   Options Database Key:
119 . -ts_adapt_type <basic or dsp or none> - to set the adapter type
120 
121   Level: intermediate
122 
123 .seealso: [](ch_ts), `TSGetAdapt()`, `TSAdaptDestroy()`, `TSAdaptType`, `TSAdaptGetType()`
124 @*/
125 PetscErrorCode TSAdaptSetType(TSAdapt adapt, TSAdaptType type)
126 {
127   PetscBool match;
128   PetscErrorCode (*r)(TSAdapt);
129 
130   PetscFunctionBegin;
131   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
132   PetscAssertPointer(type, 2);
133   PetscCall(PetscObjectTypeCompare((PetscObject)adapt, type, &match));
134   if (match) PetscFunctionReturn(PETSC_SUCCESS);
135   PetscCall(PetscFunctionListFind(TSAdaptList, type, &r));
136   PetscCheck(r, PetscObjectComm((PetscObject)adapt), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TSAdapt type \"%s\" given", type);
137   PetscTryTypeMethod(adapt, destroy);
138   PetscCall(PetscMemzero(adapt->ops, sizeof(struct _TSAdaptOps)));
139   PetscCall(PetscObjectChangeTypeName((PetscObject)adapt, type));
140   PetscCall((*r)(adapt));
141   PetscFunctionReturn(PETSC_SUCCESS);
142 }
143 
144 /*@
145   TSAdaptGetType - gets the `TS` adapter method type (as a string).
146 
147   Not Collective
148 
149   Input Parameter:
150 . adapt - The `TS` adapter, most likely obtained with `TSGetAdapt()`
151 
152   Output Parameter:
153 . type - The name of `TS` adapter method
154 
155   Level: intermediate
156 
157 .seealso: `TSAdapt`, `TSAdaptType`, `TSAdaptSetType()`
158 @*/
159 PetscErrorCode TSAdaptGetType(TSAdapt adapt, TSAdaptType *type)
160 {
161   PetscFunctionBegin;
162   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
163   PetscAssertPointer(type, 2);
164   *type = ((PetscObject)adapt)->type_name;
165   PetscFunctionReturn(PETSC_SUCCESS);
166 }
167 
168 PetscErrorCode TSAdaptSetOptionsPrefix(TSAdapt adapt, const char prefix[])
169 {
170   PetscFunctionBegin;
171   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
172   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)adapt, prefix));
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   TSAdaptLoad - Loads a TSAdapt that has been stored in binary with `TSAdaptView()`.
178 
179   Collective
180 
181   Input Parameters:
182 + adapt  - the newly loaded `TSAdapt`, this needs to have been created with `TSAdaptCreate()` or
183            some related function before a call to `TSAdaptLoad()`.
184 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
185            HDF5 file viewer, obtained from `PetscViewerHDF5Open()`
186 
187   Level: intermediate
188 
189   Note:
190   The type is determined by the data in the file, any type set into the `TSAdapt` before this call is ignored.
191 
192 .seealso: [](ch_ts), `PetscViewerBinaryOpen()`, `TSAdaptView()`, `MatLoad()`, `VecLoad()`, `TSAdapt`
193 @*/
194 PetscErrorCode TSAdaptLoad(TSAdapt adapt, PetscViewer viewer)
195 {
196   PetscBool isbinary;
197   char      type[256];
198 
199   PetscFunctionBegin;
200   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
201   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
202   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
203   PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");
204 
205   PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
206   PetscCall(TSAdaptSetType(adapt, type));
207   PetscTryTypeMethod(adapt, load, viewer);
208   PetscFunctionReturn(PETSC_SUCCESS);
209 }
210 
211 PetscErrorCode TSAdaptView(TSAdapt adapt, PetscViewer viewer)
212 {
213   PetscBool iascii, isbinary, isnone, isglee;
214 
215   PetscFunctionBegin;
216   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
217   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)adapt), &viewer));
218   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
219   PetscCheckSameComm(adapt, 1, viewer, 2);
220   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
221   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
222   if (iascii) {
223     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)adapt, viewer));
224     PetscCall(PetscObjectTypeCompare((PetscObject)adapt, TSADAPTNONE, &isnone));
225     PetscCall(PetscObjectTypeCompare((PetscObject)adapt, TSADAPTGLEE, &isglee));
226     if (!isnone) {
227       if (adapt->always_accept) PetscCall(PetscViewerASCIIPrintf(viewer, "  always accepting steps\n"));
228       PetscCall(PetscViewerASCIIPrintf(viewer, "  safety factor %g\n", (double)adapt->safety));
229       PetscCall(PetscViewerASCIIPrintf(viewer, "  extra safety factor after step rejection %g\n", (double)adapt->reject_safety));
230       PetscCall(PetscViewerASCIIPrintf(viewer, "  clip fastest increase %g\n", (double)adapt->clip[1]));
231       PetscCall(PetscViewerASCIIPrintf(viewer, "  clip fastest decrease %g\n", (double)adapt->clip[0]));
232       PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum allowed timestep %g\n", (double)adapt->dt_max));
233       PetscCall(PetscViewerASCIIPrintf(viewer, "  minimum allowed timestep %g\n", (double)adapt->dt_min));
234       PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum solution absolute value to be ignored %g\n", (double)adapt->ignore_max));
235     }
236     if (isglee) {
237       if (adapt->glee_use_local) {
238         PetscCall(PetscViewerASCIIPrintf(viewer, "  GLEE uses local error control\n"));
239       } else {
240         PetscCall(PetscViewerASCIIPrintf(viewer, "  GLEE uses global error control\n"));
241       }
242     }
243     PetscCall(PetscViewerASCIIPushTab(viewer));
244     PetscTryTypeMethod(adapt, view, viewer);
245     PetscCall(PetscViewerASCIIPopTab(viewer));
246   } else if (isbinary) {
247     char type[256];
248 
249     /* need to save FILE_CLASS_ID for adapt class */
250     PetscCall(PetscStrncpy(type, ((PetscObject)adapt)->type_name, 256));
251     PetscCall(PetscViewerBinaryWrite(viewer, type, 256, PETSC_CHAR));
252   } else PetscTryTypeMethod(adapt, view, viewer);
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 /*@
257   TSAdaptReset - Resets a `TSAdapt` context to its defaults
258 
259   Collective
260 
261   Input Parameter:
262 . adapt - the `TSAdapt` context obtained from `TSGetAdapt()` or `TSAdaptCreate()`
263 
264   Level: developer
265 
266 .seealso: [](ch_ts), `TSGetAdapt()`, `TSAdapt`, `TSAdaptCreate()`, `TSAdaptDestroy()`
267 @*/
268 PetscErrorCode TSAdaptReset(TSAdapt adapt)
269 {
270   PetscFunctionBegin;
271   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
272   PetscTryTypeMethod(adapt, reset);
273   PetscFunctionReturn(PETSC_SUCCESS);
274 }
275 
276 PetscErrorCode TSAdaptDestroy(TSAdapt *adapt)
277 {
278   PetscFunctionBegin;
279   if (!*adapt) PetscFunctionReturn(PETSC_SUCCESS);
280   PetscValidHeaderSpecific(*adapt, TSADAPT_CLASSID, 1);
281   if (--((PetscObject)*adapt)->refct > 0) {
282     *adapt = NULL;
283     PetscFunctionReturn(PETSC_SUCCESS);
284   }
285 
286   PetscCall(TSAdaptReset(*adapt));
287 
288   PetscTryTypeMethod(*adapt, destroy);
289   PetscCall(PetscViewerDestroy(&(*adapt)->monitor));
290   PetscCall(PetscHeaderDestroy(adapt));
291   PetscFunctionReturn(PETSC_SUCCESS);
292 }
293 
294 /*@
295   TSAdaptSetMonitor - Monitor the choices made by the adaptive controller
296 
297   Collective
298 
299   Input Parameters:
300 + adapt - adaptive controller context
301 - flg   - `PETSC_TRUE` to active a monitor, `PETSC_FALSE` to disable
302 
303   Options Database Key:
304 . -ts_adapt_monitor - to turn on monitoring
305 
306   Level: intermediate
307 
308 .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptChoose()`
309 @*/
310 PetscErrorCode TSAdaptSetMonitor(TSAdapt adapt, PetscBool flg)
311 {
312   PetscFunctionBegin;
313   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
314   PetscValidLogicalCollectiveBool(adapt, flg, 2);
315   if (flg) {
316     if (!adapt->monitor) PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)adapt), "stdout", &adapt->monitor));
317   } else {
318     PetscCall(PetscViewerDestroy(&adapt->monitor));
319   }
320   PetscFunctionReturn(PETSC_SUCCESS);
321 }
322 
323 /*@C
324   TSAdaptSetCheckStage - Set a callback to check convergence for a stage
325 
326   Logically Collective
327 
328   Input Parameters:
329 + adapt - adaptive controller context
330 - func  - stage check function
331 
332   Calling sequence:
333 + adapt  - adaptive controller context
334 . ts     - time stepping context
335 . t      - current time
336 . Y      - current solution vector
337 - accept - pending choice of whether to accept, can be modified by this routine
338 
339   Level: advanced
340 
341 .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptChoose()`
342 @*/
343 PetscErrorCode TSAdaptSetCheckStage(TSAdapt adapt, PetscErrorCode (*func)(TSAdapt adapt, TS ts, PetscReal t, Vec Y, PetscBool *accept))
344 {
345   PetscFunctionBegin;
346   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
347   adapt->checkstage = func;
348   PetscFunctionReturn(PETSC_SUCCESS);
349 }
350 
351 /*@
352   TSAdaptSetAlwaysAccept - Set whether to always accept steps regardless of
353   any error or stability condition not meeting the prescribed goal.
354 
355   Logically Collective
356 
357   Input Parameters:
358 + adapt - time step adaptivity context, usually gotten with `TSGetAdapt()`
359 - flag  - whether to always accept steps
360 
361   Options Database Key:
362 . -ts_adapt_always_accept - to always accept steps
363 
364   Level: intermediate
365 
366 .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptChoose()`
367 @*/
368 PetscErrorCode TSAdaptSetAlwaysAccept(TSAdapt adapt, PetscBool flag)
369 {
370   PetscFunctionBegin;
371   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
372   PetscValidLogicalCollectiveBool(adapt, flag, 2);
373   adapt->always_accept = flag;
374   PetscFunctionReturn(PETSC_SUCCESS);
375 }
376 
377 /*@
378   TSAdaptSetSafety - Set safety factors for time step adaptor
379 
380   Logically Collective
381 
382   Input Parameters:
383 + adapt         - adaptive controller context
384 . safety        - safety factor relative to target error/stability goal
385 - reject_safety - extra safety factor to apply if the last step was rejected
386 
387   Options Database Keys:
388 + -ts_adapt_safety <safety>               - to set safety factor
389 - -ts_adapt_reject_safety <reject_safety> - to set reject safety factor
390 
391   Level: intermediate
392 
393   Note:
394   Use `PETSC_CURRENT` to keep the current value for either parameter
395 
396   Fortran Note:
397   Use `PETSC_CURRENT_REAL`
398 
399 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptGetSafety()`, `TSAdaptChoose()`
400 @*/
401 PetscErrorCode TSAdaptSetSafety(TSAdapt adapt, PetscReal safety, PetscReal reject_safety)
402 {
403   PetscFunctionBegin;
404   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
405   PetscValidLogicalCollectiveReal(adapt, safety, 2);
406   PetscValidLogicalCollectiveReal(adapt, reject_safety, 3);
407   PetscCheck(safety == (PetscReal)PETSC_CURRENT || safety >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Safety factor %g must be non negative", (double)safety);
408   PetscCheck(safety == (PetscReal)PETSC_CURRENT || safety <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Safety factor %g must be less than one", (double)safety);
409   PetscCheck(reject_safety == (PetscReal)PETSC_CURRENT || reject_safety >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reject safety factor %g must be non negative", (double)reject_safety);
410   PetscCheck(reject_safety == (PetscReal)PETSC_CURRENT || reject_safety <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reject safety factor %g must be less than one", (double)reject_safety);
411   if (safety != (PetscReal)PETSC_CURRENT) adapt->safety = safety;
412   if (reject_safety != (PetscReal)PETSC_CURRENT) adapt->reject_safety = reject_safety;
413   PetscFunctionReturn(PETSC_SUCCESS);
414 }
415 
416 /*@
417   TSAdaptGetSafety - Get safety factors for time step adapter
418 
419   Not Collective
420 
421   Input Parameter:
422 . adapt - adaptive controller context
423 
424   Output Parameters:
425 + safety        - safety factor relative to target error/stability goal
426 - reject_safety - extra safety factor to apply if the last step was rejected
427 
428   Level: intermediate
429 
430 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptSetSafety()`, `TSAdaptChoose()`
431 @*/
432 PetscErrorCode TSAdaptGetSafety(TSAdapt adapt, PetscReal *safety, PetscReal *reject_safety)
433 {
434   PetscFunctionBegin;
435   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
436   if (safety) PetscAssertPointer(safety, 2);
437   if (reject_safety) PetscAssertPointer(reject_safety, 3);
438   if (safety) *safety = adapt->safety;
439   if (reject_safety) *reject_safety = adapt->reject_safety;
440   PetscFunctionReturn(PETSC_SUCCESS);
441 }
442 
443 /*@
444   TSAdaptSetMaxIgnore - Set error estimation threshold. Solution components below this threshold value will not be considered when computing error norms
445   for time step adaptivity (in absolute value). A negative value (default) of the threshold leads to considering all solution components.
446 
447   Logically Collective
448 
449   Input Parameters:
450 + adapt      - adaptive controller context
451 - max_ignore - threshold for solution components that are ignored during error estimation
452 
453   Options Database Key:
454 . -ts_adapt_max_ignore <max_ignore> - to set the threshold
455 
456   Level: intermediate
457 
458 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptGetMaxIgnore()`, `TSAdaptChoose()`
459 @*/
460 PetscErrorCode TSAdaptSetMaxIgnore(TSAdapt adapt, PetscReal max_ignore)
461 {
462   PetscFunctionBegin;
463   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
464   PetscValidLogicalCollectiveReal(adapt, max_ignore, 2);
465   adapt->ignore_max = max_ignore;
466   PetscFunctionReturn(PETSC_SUCCESS);
467 }
468 
469 /*@
470   TSAdaptGetMaxIgnore - Get error estimation threshold. Solution components below this threshold value will not be considered when computing error norms
471   for time step adaptivity (in absolute value).
472 
473   Not Collective
474 
475   Input Parameter:
476 . adapt - adaptive controller context
477 
478   Output Parameter:
479 . max_ignore - threshold for solution components that are ignored during error estimation
480 
481   Level: intermediate
482 
483 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptSetMaxIgnore()`, `TSAdaptChoose()`
484 @*/
485 PetscErrorCode TSAdaptGetMaxIgnore(TSAdapt adapt, PetscReal *max_ignore)
486 {
487   PetscFunctionBegin;
488   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
489   PetscAssertPointer(max_ignore, 2);
490   *max_ignore = adapt->ignore_max;
491   PetscFunctionReturn(PETSC_SUCCESS);
492 }
493 
494 /*@
495   TSAdaptSetClip - Sets the admissible decrease/increase factor in step size in the time step adapter
496 
497   Logically collective
498 
499   Input Parameters:
500 + adapt - adaptive controller context
501 . low   - admissible decrease factor
502 - high  - admissible increase factor
503 
504   Options Database Key:
505 . -ts_adapt_clip <low>,<high> - to set admissible time step decrease and increase factors
506 
507   Level: intermediate
508 
509   Note:
510   Use `PETSC_CURRENT` to keep the current value for either parameter
511 
512   Fortran Note:
513   Use `PETSC_CURRENT_REAL`
514 
515 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptGetClip()`, `TSAdaptSetScaleSolveFailed()`
516 @*/
517 PetscErrorCode TSAdaptSetClip(TSAdapt adapt, PetscReal low, PetscReal high)
518 {
519   PetscFunctionBegin;
520   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
521   PetscValidLogicalCollectiveReal(adapt, low, 2);
522   PetscValidLogicalCollectiveReal(adapt, high, 3);
523   PetscCheck(low == (PetscReal)PETSC_CURRENT || low >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Decrease factor %g must be non negative", (double)low);
524   PetscCheck(low == (PetscReal)PETSC_CURRENT || low <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Decrease factor %g must be less than one", (double)low);
525   PetscCheck(high == (PetscReal)PETSC_CURRENT || high >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Increase factor %g must be greater than one", (double)high);
526   if (low != (PetscReal)PETSC_CURRENT) adapt->clip[0] = low;
527   if (high != (PetscReal)PETSC_CURRENT) adapt->clip[1] = high;
528   PetscFunctionReturn(PETSC_SUCCESS);
529 }
530 
531 /*@
532   TSAdaptGetClip - Gets the admissible decrease/increase factor in step size in the time step adapter
533 
534   Not Collective
535 
536   Input Parameter:
537 . adapt - adaptive controller context
538 
539   Output Parameters:
540 + low  - optional, admissible decrease factor
541 - high - optional, admissible increase factor
542 
543   Level: intermediate
544 
545 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptSetClip()`, `TSAdaptSetScaleSolveFailed()`
546 @*/
547 PetscErrorCode TSAdaptGetClip(TSAdapt adapt, PetscReal *low, PetscReal *high)
548 {
549   PetscFunctionBegin;
550   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
551   if (low) PetscAssertPointer(low, 2);
552   if (high) PetscAssertPointer(high, 3);
553   if (low) *low = adapt->clip[0];
554   if (high) *high = adapt->clip[1];
555   PetscFunctionReturn(PETSC_SUCCESS);
556 }
557 
558 /*@
559   TSAdaptSetScaleSolveFailed - Scale step size by this factor if solve fails
560 
561   Logically Collective
562 
563   Input Parameters:
564 + adapt - adaptive controller context
565 - scale - scale
566 
567   Options Database Key:
568 . -ts_adapt_scale_solve_failed <scale> - to set scale step by this factor if solve fails
569 
570   Level: intermediate
571 
572 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptGetScaleSolveFailed()`, `TSAdaptGetClip()`
573 @*/
574 PetscErrorCode TSAdaptSetScaleSolveFailed(TSAdapt adapt, PetscReal scale)
575 {
576   PetscFunctionBegin;
577   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
578   PetscValidLogicalCollectiveReal(adapt, scale, 2);
579   PetscCheck(scale > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Scale factor %g must be positive", (double)scale);
580   PetscCheck(scale <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Scale factor %g must be less than one", (double)scale);
581   adapt->scale_solve_failed = scale;
582   PetscFunctionReturn(PETSC_SUCCESS);
583 }
584 
585 /*@
586   TSAdaptGetScaleSolveFailed - Gets the admissible decrease/increase factor in step size
587 
588   Not Collective
589 
590   Input Parameter:
591 . adapt - adaptive controller context
592 
593   Output Parameter:
594 . scale - scale factor
595 
596   Level: intermediate
597 
598 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptSetScaleSolveFailed()`, `TSAdaptSetClip()`
599 @*/
600 PetscErrorCode TSAdaptGetScaleSolveFailed(TSAdapt adapt, PetscReal *scale)
601 {
602   PetscFunctionBegin;
603   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
604   if (scale) PetscAssertPointer(scale, 2);
605   if (scale) *scale = adapt->scale_solve_failed;
606   PetscFunctionReturn(PETSC_SUCCESS);
607 }
608 
609 /*@
610   TSAdaptSetStepLimits - Set the minimum and maximum step sizes to be considered by the time step controller
611 
612   Logically Collective
613 
614   Input Parameters:
615 + adapt - time step adaptivity context, usually gotten with `TSGetAdapt()`
616 . hmin  - minimum time step
617 - hmax  - maximum time step
618 
619   Options Database Keys:
620 + -ts_adapt_dt_min <min> - to set minimum time step
621 - -ts_adapt_dt_max <max> - to set maximum time step
622 
623   Level: intermediate
624 
625   Note:
626   Use `PETSC_CURRENT` to keep the current value for either parameter
627 
628   Fortran Note:
629   Use `PETSC_CURRENT_REAL`
630 
631 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptGetStepLimits()`, `TSAdaptChoose()`
632 @*/
633 PetscErrorCode TSAdaptSetStepLimits(TSAdapt adapt, PetscReal hmin, PetscReal hmax)
634 {
635   PetscFunctionBegin;
636   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
637   PetscValidLogicalCollectiveReal(adapt, hmin, 2);
638   PetscValidLogicalCollectiveReal(adapt, hmax, 3);
639   PetscCheck(hmin == (PetscReal)PETSC_CURRENT || hmin >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Minimum time step %g must be non negative", (double)hmin);
640   PetscCheck(hmax == (PetscReal)PETSC_CURRENT || hmax >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Minimum time step %g must be non negative", (double)hmax);
641   if (hmin != (PetscReal)PETSC_CURRENT) adapt->dt_min = hmin;
642   if (hmax != (PetscReal)PETSC_CURRENT) adapt->dt_max = hmax;
643   hmin = adapt->dt_min;
644   hmax = adapt->dt_max;
645   PetscCheck(hmax > hmin, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Maximum time step %g must greater than minimum time step %g", (double)hmax, (double)hmin);
646   PetscFunctionReturn(PETSC_SUCCESS);
647 }
648 
649 /*@
650   TSAdaptGetStepLimits - Get the minimum and maximum step sizes to be considered by the time step controller
651 
652   Not Collective
653 
654   Input Parameter:
655 . adapt - time step adaptivity context, usually gotten with `TSGetAdapt()`
656 
657   Output Parameters:
658 + hmin - minimum time step
659 - hmax - maximum time step
660 
661   Level: intermediate
662 
663 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptSetStepLimits()`, `TSAdaptChoose()`
664 @*/
665 PetscErrorCode TSAdaptGetStepLimits(TSAdapt adapt, PetscReal *hmin, PetscReal *hmax)
666 {
667   PetscFunctionBegin;
668   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
669   if (hmin) PetscAssertPointer(hmin, 2);
670   if (hmax) PetscAssertPointer(hmax, 3);
671   if (hmin) *hmin = adapt->dt_min;
672   if (hmax) *hmax = adapt->dt_max;
673   PetscFunctionReturn(PETSC_SUCCESS);
674 }
675 
676 /*@C
677   TSAdaptSetFromOptions - Sets various `TSAdapt` parameters from user options.
678 
679   Collective
680 
681   Input Parameters:
682 + adapt              - the `TSAdapt` context
683 - PetscOptionsObject - object created by `PetscOptionsBegin()`
684 
685   Options Database Keys:
686 + -ts_adapt_type <type>                - algorithm to use for adaptivity
687 . -ts_adapt_always_accept              - always accept steps regardless of error/stability goals
688 . -ts_adapt_safety <safety>            - safety factor relative to target error/stability goal
689 . -ts_adapt_reject_safety <safety>     - extra safety factor to apply if the last step was rejected
690 . -ts_adapt_clip <low,high>            - admissible time step decrease and increase factors
691 . -ts_adapt_dt_min <min>               - minimum timestep to use
692 . -ts_adapt_dt_max <max>               - maximum timestep to use
693 . -ts_adapt_scale_solve_failed <scale> - scale timestep by this factor if a solve fails
694 . -ts_adapt_wnormtype <2 or infinity>  - type of norm for computing error estimates
695 - -ts_adapt_time_step_increase_delay   - number of timesteps to delay increasing the time step after it has been decreased due to failed solver
696 
697   Level: advanced
698 
699   Note:
700   This function is automatically called by `TSSetFromOptions()`
701 
702 .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptSetType()`, `TSAdaptSetAlwaysAccept()`, `TSAdaptSetSafety()`,
703           `TSAdaptSetClip()`, `TSAdaptSetScaleSolveFailed()`, `TSAdaptSetStepLimits()`, `TSAdaptSetMonitor()`
704 @*/
705 PetscErrorCode TSAdaptSetFromOptions(TSAdapt adapt, PetscOptionItems *PetscOptionsObject)
706 {
707   char      type[256] = TSADAPTBASIC;
708   PetscReal safety, reject_safety, clip[2], scale, hmin, hmax;
709   PetscBool set, flg;
710   PetscInt  two;
711 
712   PetscFunctionBegin;
713   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
714   /* This should use PetscOptionsBegin() if/when this becomes an object used outside of TS, but currently this
715    * function can only be called from inside TSSetFromOptions()  */
716   PetscOptionsHeadBegin(PetscOptionsObject, "TS Adaptivity options");
717   PetscCall(PetscOptionsFList("-ts_adapt_type", "Algorithm to use for adaptivity", "TSAdaptSetType", TSAdaptList, ((PetscObject)adapt)->type_name ? ((PetscObject)adapt)->type_name : type, type, sizeof(type), &flg));
718   if (flg || !((PetscObject)adapt)->type_name) PetscCall(TSAdaptSetType(adapt, type));
719 
720   PetscCall(PetscOptionsBool("-ts_adapt_always_accept", "Always accept the step", "TSAdaptSetAlwaysAccept", adapt->always_accept, &flg, &set));
721   if (set) PetscCall(TSAdaptSetAlwaysAccept(adapt, flg));
722 
723   safety        = adapt->safety;
724   reject_safety = adapt->reject_safety;
725   PetscCall(PetscOptionsReal("-ts_adapt_safety", "Safety factor relative to target error/stability goal", "TSAdaptSetSafety", safety, &safety, &set));
726   PetscCall(PetscOptionsReal("-ts_adapt_reject_safety", "Extra safety factor to apply if the last step was rejected", "TSAdaptSetSafety", reject_safety, &reject_safety, &flg));
727   if (set || flg) PetscCall(TSAdaptSetSafety(adapt, safety, reject_safety));
728 
729   two     = 2;
730   clip[0] = adapt->clip[0];
731   clip[1] = adapt->clip[1];
732   PetscCall(PetscOptionsRealArray("-ts_adapt_clip", "Admissible decrease/increase factor in step size", "TSAdaptSetClip", clip, &two, &set));
733   PetscCheck(!set || (two == 2), PetscObjectComm((PetscObject)adapt), PETSC_ERR_ARG_OUTOFRANGE, "Must give exactly two values to -ts_adapt_clip");
734   if (set) PetscCall(TSAdaptSetClip(adapt, clip[0], clip[1]));
735 
736   hmin = adapt->dt_min;
737   hmax = adapt->dt_max;
738   PetscCall(PetscOptionsReal("-ts_adapt_dt_min", "Minimum time step considered", "TSAdaptSetStepLimits", hmin, &hmin, &set));
739   PetscCall(PetscOptionsReal("-ts_adapt_dt_max", "Maximum time step considered", "TSAdaptSetStepLimits", hmax, &hmax, &flg));
740   if (set || flg) PetscCall(TSAdaptSetStepLimits(adapt, hmin, hmax));
741 
742   PetscCall(PetscOptionsReal("-ts_adapt_max_ignore", "Adaptor ignores (absolute) solution values smaller than this value", "", adapt->ignore_max, &adapt->ignore_max, &set));
743   PetscCall(PetscOptionsBool("-ts_adapt_glee_use_local", "GLEE adaptor uses local error estimation for step control", "", adapt->glee_use_local, &adapt->glee_use_local, &set));
744 
745   PetscCall(PetscOptionsReal("-ts_adapt_scale_solve_failed", "Scale step by this factor if solve fails", "TSAdaptSetScaleSolveFailed", adapt->scale_solve_failed, &scale, &set));
746   if (set) PetscCall(TSAdaptSetScaleSolveFailed(adapt, scale));
747 
748   PetscCall(PetscOptionsEnum("-ts_adapt_wnormtype", "Type of norm computed for error estimation", "", NormTypes, (PetscEnum)adapt->wnormtype, (PetscEnum *)&adapt->wnormtype, NULL));
749   PetscCheck(adapt->wnormtype == NORM_2 || adapt->wnormtype == NORM_INFINITY, PetscObjectComm((PetscObject)adapt), PETSC_ERR_SUP, "Only 2-norm and infinite norm supported");
750 
751   PetscCall(PetscOptionsInt("-ts_adapt_time_step_increase_delay", "Number of timesteps to delay increasing the time step after it has been decreased due to failed solver", "TSAdaptSetTimeStepIncreaseDelay", adapt->timestepjustdecreased_delay, &adapt->timestepjustdecreased_delay, NULL));
752 
753   PetscCall(PetscOptionsBool("-ts_adapt_monitor", "Print choices made by adaptive controller", "TSAdaptSetMonitor", adapt->monitor ? PETSC_TRUE : PETSC_FALSE, &flg, &set));
754   if (set) PetscCall(TSAdaptSetMonitor(adapt, flg));
755 
756   PetscTryTypeMethod(adapt, setfromoptions, PetscOptionsObject);
757   PetscOptionsHeadEnd();
758   PetscFunctionReturn(PETSC_SUCCESS);
759 }
760 
761 /*@
762   TSAdaptCandidatesClear - clear any previously set candidate schemes
763 
764   Logically Collective
765 
766   Input Parameter:
767 . adapt - adaptive controller
768 
769   Level: developer
770 
771 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptCreate()`, `TSAdaptCandidateAdd()`, `TSAdaptChoose()`
772 @*/
773 PetscErrorCode TSAdaptCandidatesClear(TSAdapt adapt)
774 {
775   PetscFunctionBegin;
776   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
777   PetscCall(PetscMemzero(&adapt->candidates, sizeof(adapt->candidates)));
778   PetscFunctionReturn(PETSC_SUCCESS);
779 }
780 
781 /*@C
782   TSAdaptCandidateAdd - add a candidate scheme for the adaptive controller to select from
783 
784   Logically Collective; No Fortran Support
785 
786   Input Parameters:
787 + adapt      - time step adaptivity context, obtained with `TSGetAdapt()` or `TSAdaptCreate()`
788 . name       - name of the candidate scheme to add
789 . order      - order of the candidate scheme
790 . stageorder - stage order of the candidate scheme
791 . ccfl       - stability coefficient relative to explicit Euler, used for CFL constraints
792 . cost       - relative measure of the amount of work required for the candidate scheme
793 - inuse      - indicates that this scheme is the one currently in use, this flag can only be set for one scheme
794 
795   Level: developer
796 
797 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptCandidatesClear()`, `TSAdaptChoose()`
798 @*/
799 PetscErrorCode TSAdaptCandidateAdd(TSAdapt adapt, const char name[], PetscInt order, PetscInt stageorder, PetscReal ccfl, PetscReal cost, PetscBool inuse)
800 {
801   PetscInt c;
802 
803   PetscFunctionBegin;
804   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
805   PetscCheck(order >= 1, PetscObjectComm((PetscObject)adapt), PETSC_ERR_ARG_OUTOFRANGE, "Classical order %" PetscInt_FMT " must be a positive integer", order);
806   if (inuse) {
807     PetscCheck(!adapt->candidates.inuse_set, PetscObjectComm((PetscObject)adapt), PETSC_ERR_ARG_WRONGSTATE, "Cannot set the inuse method twice, maybe forgot to call TSAdaptCandidatesClear()");
808     adapt->candidates.inuse_set = PETSC_TRUE;
809   }
810   /* first slot if this is the current scheme, otherwise the next available slot */
811   c = inuse ? 0 : !adapt->candidates.inuse_set + adapt->candidates.n;
812 
813   adapt->candidates.name[c]       = name;
814   adapt->candidates.order[c]      = order;
815   adapt->candidates.stageorder[c] = stageorder;
816   adapt->candidates.ccfl[c]       = ccfl;
817   adapt->candidates.cost[c]       = cost;
818   adapt->candidates.n++;
819   PetscFunctionReturn(PETSC_SUCCESS);
820 }
821 
822 /*@C
823   TSAdaptCandidatesGet - Get the list of candidate orders of accuracy and cost
824 
825   Not Collective
826 
827   Input Parameter:
828 . adapt - time step adaptivity context
829 
830   Output Parameters:
831 + n          - number of candidate schemes, always at least 1
832 . order      - the order of each candidate scheme
833 . stageorder - the stage order of each candidate scheme
834 . ccfl       - the CFL coefficient of each scheme
835 - cost       - the relative cost of each scheme
836 
837   Level: developer
838 
839   Note:
840   The current scheme is always returned in the first slot
841 
842 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptCandidatesClear()`, `TSAdaptCandidateAdd()`, `TSAdaptChoose()`
843 @*/
844 PetscErrorCode TSAdaptCandidatesGet(TSAdapt adapt, PetscInt *n, const PetscInt **order, const PetscInt **stageorder, const PetscReal **ccfl, const PetscReal **cost)
845 {
846   PetscFunctionBegin;
847   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
848   if (n) *n = adapt->candidates.n;
849   if (order) *order = adapt->candidates.order;
850   if (stageorder) *stageorder = adapt->candidates.stageorder;
851   if (ccfl) *ccfl = adapt->candidates.ccfl;
852   if (cost) *cost = adapt->candidates.cost;
853   PetscFunctionReturn(PETSC_SUCCESS);
854 }
855 
856 /*@C
857   TSAdaptChoose - choose which method and step size to use for the next step
858 
859   Collective
860 
861   Input Parameters:
862 + adapt - adaptive controller
863 . ts    - time stepper
864 - h     - current step size
865 
866   Output Parameters:
867 + next_sc - optional, scheme to use for the next step
868 . next_h  - step size to use for the next step
869 - accept  - `PETSC_TRUE` to accept the current step, `PETSC_FALSE` to repeat the current step with the new step size
870 
871   Level: developer
872 
873   Note:
874   The input value of parameter accept is retained from the last time step, so it will be `PETSC_FALSE` if the step is
875   being retried after an initial rejection.
876 
877 .seealso: [](ch_ts), `TSAdapt`, `TSAdaptCandidatesClear()`, `TSAdaptCandidateAdd()`
878 @*/
879 PetscErrorCode TSAdaptChoose(TSAdapt adapt, TS ts, PetscReal h, PetscInt *next_sc, PetscReal *next_h, PetscBool *accept)
880 {
881   PetscInt  ncandidates = adapt->candidates.n;
882   PetscInt  scheme      = 0;
883   PetscReal wlte        = -1.0;
884   PetscReal wltea       = -1.0;
885   PetscReal wlter       = -1.0;
886 
887   PetscFunctionBegin;
888   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
889   PetscValidHeaderSpecific(ts, TS_CLASSID, 2);
890   if (next_sc) PetscAssertPointer(next_sc, 4);
891   PetscAssertPointer(next_h, 5);
892   PetscAssertPointer(accept, 6);
893   if (next_sc) *next_sc = 0;
894 
895   /* Do not mess with adaptivity while handling events */
896   if (ts->event && ts->event->processing) {
897     *next_h = h;
898     *accept = PETSC_TRUE;
899     if (adapt->monitor) {
900       PetscCall(PetscViewerASCIIAddTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
901 
902       if (ts->event->iterctr == 0) {
903         /*
904           An event has been found, now finalising the event processing: performing the 1st and 2nd post-event steps.
905           Entering this if-branch means both these steps (set to either PETSC_DECIDE or numerical value) are managed
906           by the event handler. In this case the 1st post-event step is always accepted, without interference of TSAdapt.
907           Note: if the 2nd post-event step is not managed by the event handler (e.g. given 1st = numerical, 2nd = PETSC_DECIDE),
908           this if-branch is not entered, and TSAdapt may reject/adjust the proposed 1st post-event step.
909         */
910         PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt does not interfere, step %3" PetscInt_FMT " accepted. Processing post-event steps: 1-st accepted just now, 2-nd yet to come\n", ts->steps));
911       } else PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt does not interfere, step %3" PetscInt_FMT " accepted. Event handling in progress\n", ts->steps));
912 
913       PetscCall(PetscViewerASCIISubtractTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
914     }
915     PetscFunctionReturn(PETSC_SUCCESS);
916   }
917 
918   PetscUseTypeMethod(adapt, choose, ts, h, &scheme, next_h, accept, &wlte, &wltea, &wlter);
919   PetscCheck(scheme >= 0 && (ncandidates <= 0 || scheme < ncandidates), PetscObjectComm((PetscObject)adapt), PETSC_ERR_ARG_OUTOFRANGE, "Chosen scheme %" PetscInt_FMT " not in valid range 0..%" PetscInt_FMT, scheme, ncandidates - 1);
920   PetscCheck(*next_h >= 0, PetscObjectComm((PetscObject)adapt), PETSC_ERR_ARG_OUTOFRANGE, "Computed step size %g must be positive", (double)*next_h);
921   if (next_sc) *next_sc = scheme;
922 
923   if (*accept && ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
924     /* Increase/reduce step size if end time of next step is close to or overshoots max time */
925     PetscReal t   = ts->ptime + ts->time_step, tend, tmax, h1, hmax;
926     PetscReal a   = (PetscReal)(1.0 + adapt->matchstepfac[0]);
927     PetscReal b   = adapt->matchstepfac[1];
928     PetscReal eps = 10 * PETSC_MACHINE_EPSILON;
929 
930     /*
931       Logic in using 'dt_span_cached':
932       1. It always overrides *next_h, except (any of):
933          a) the current step was rejected,
934          b) the adaptor proposed to decrease the next step,
935          c) the adaptor proposed *next_h > dt_span_cached.
936       2. If *next_h was adjusted by tspan points (or the final point):
937            -- when dt_span_cached is filled (>0), it keeps its value,
938            -- when dt_span_cached is clear (==0), it gets the unadjusted version of *next_h.
939       3. If *next_h was not adjusted as in (2), dt_span_cached is cleared.
940       Note, if a combination (1.b || 1.c) && (3) takes place, this means that
941       dt_span_cached remains unused at the moment of clearing.
942       If (1.a) takes place, dt_span_cached keeps its value.
943       Also, dt_span_cached can be updated by the event handler, see tsevent.c.
944     */
945     if (h <= *next_h && *next_h <= adapt->dt_span_cached) *next_h = adapt->dt_span_cached; /* try employing the cache */
946     h1   = *next_h;
947     tend = t + h1;
948 
949     if (ts->tspan && ts->tspan->spanctr < ts->tspan->num_span_times) {
950       PetscCheck(ts->tspan->worktol == 0, PetscObjectComm((PetscObject)adapt), PETSC_ERR_PLIB, "Unexpected state (tspan->worktol != 0) in TSAdaptChoose()");
951       ts->tspan->worktol = ts->tspan->reltol * h1 + ts->tspan->abstol;
952       if (PetscIsCloseAtTol(t, ts->tspan->span_times[ts->tspan->spanctr], ts->tspan->worktol, 0)) /* hit a span time point */
953         if (ts->tspan->spanctr + 1 < ts->tspan->num_span_times) tmax = ts->tspan->span_times[ts->tspan->spanctr + 1];
954         else tmax = ts->max_time; /* hit the last span time point */
955       else tmax = ts->tspan->span_times[ts->tspan->spanctr];
956     } else tmax = ts->max_time;
957     tmax = PetscMin(tmax, ts->max_time);
958     hmax = tmax - t;
959     PetscCheck((hmax > eps) || (PetscAbsReal(hmax) <= eps && PetscIsCloseAtTol(t, ts->max_time, eps, 0)), PetscObjectComm((PetscObject)adapt), PETSC_ERR_PLIB, "Unexpected state: bad hmax in TSAdaptChoose()");
960 
961     if (t < tmax && tend > tmax) *next_h = hmax;
962     if (t < tmax && tend < tmax && h1 * b > hmax) *next_h = hmax / 2;
963     if (t < tmax && tend < tmax && h1 * a > hmax) *next_h = hmax;
964     if (ts->tspan && h1 != *next_h && !adapt->dt_span_cached) adapt->dt_span_cached = h1; /* cache the step size if it is to be changed    */
965     if (ts->tspan && h1 == *next_h && adapt->dt_span_cached) adapt->dt_span_cached = 0;   /* clear the cache if the step size is unchanged */
966   }
967   if (adapt->monitor) {
968     const char *sc_name = (scheme < ncandidates) ? adapt->candidates.name[scheme] : "";
969     PetscCall(PetscViewerASCIIAddTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
970     if (wlte < 0) {
971       PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt %s %s %" PetscInt_FMT ":%s step %3" PetscInt_FMT " %s t=%-11g+%10.3e dt=%-10.3e\n", ((PetscObject)adapt)->type_name, ((PetscObject)ts)->type_name, scheme, sc_name, ts->steps, *accept ? "accepted" : "rejected",
972                                        (double)ts->ptime, (double)h, (double)*next_h));
973     } else {
974       PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt %s %s %" PetscInt_FMT ":%s step %3" PetscInt_FMT " %s t=%-11g+%10.3e dt=%-10.3e wlte=%5.3g  wltea=%5.3g wlter=%5.3g\n", ((PetscObject)adapt)->type_name, ((PetscObject)ts)->type_name, scheme, sc_name, ts->steps, *accept ? "accepted" : "rejected",
975                                        (double)ts->ptime, (double)h, (double)*next_h, (double)wlte, (double)wltea, (double)wlter));
976     }
977     PetscCall(PetscViewerASCIISubtractTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
978   }
979   PetscFunctionReturn(PETSC_SUCCESS);
980 }
981 
982 /*@
983   TSAdaptSetTimeStepIncreaseDelay - The number of timesteps to wait after a decrease in the timestep due to failed solver
984   before increasing the time step.
985 
986   Logicially Collective
987 
988   Input Parameters:
989 + adapt - adaptive controller context
990 - cnt   - the number of timesteps
991 
992   Options Database Key:
993 . -ts_adapt_time_step_increase_delay cnt - number of steps to delay the increase
994 
995   Level: advanced
996 
997   Notes:
998   This is to prevent an adaptor from bouncing back and forth between two nearby timesteps. The default is 0.
999 
1000   The successful use of this option is problem dependent
1001 
1002   Developer Notes:
1003   There is no theory to support this option
1004 
1005 .seealso: [](ch_ts), `TSAdapt`
1006 @*/
1007 PetscErrorCode TSAdaptSetTimeStepIncreaseDelay(TSAdapt adapt, PetscInt cnt)
1008 {
1009   PetscFunctionBegin;
1010   adapt->timestepjustdecreased_delay = cnt;
1011   PetscFunctionReturn(PETSC_SUCCESS);
1012 }
1013 
1014 /*@
1015   TSAdaptCheckStage - checks whether to accept a stage, (e.g. reject and change time step size if nonlinear solve fails or solution vector is infeasible)
1016 
1017   Collective
1018 
1019   Input Parameters:
1020 + adapt - adaptive controller context
1021 . ts    - time stepper
1022 . t     - Current simulation time
1023 - Y     - Current solution vector
1024 
1025   Output Parameter:
1026 . accept - `PETSC_TRUE` to accept the stage, `PETSC_FALSE` to reject
1027 
1028   Level: developer
1029 
1030 .seealso: [](ch_ts), `TSAdapt`
1031 @*/
1032 PetscErrorCode TSAdaptCheckStage(TSAdapt adapt, TS ts, PetscReal t, Vec Y, PetscBool *accept)
1033 {
1034   SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING;
1035   PetscBool           func_accept, snes_div_func;
1036 
1037   PetscFunctionBegin;
1038   PetscValidHeaderSpecific(adapt, TSADAPT_CLASSID, 1);
1039   PetscValidHeaderSpecific(ts, TS_CLASSID, 2);
1040   PetscAssertPointer(accept, 5);
1041 
1042   PetscCall(TSFunctionDomainError(ts, t, Y, &func_accept));
1043   if (ts->snes) PetscCall(SNESGetConvergedReason(ts->snes, &snesreason));
1044   snes_div_func = (PetscBool)(snesreason == SNES_DIVERGED_FUNCTION_DOMAIN);
1045   if (func_accept && snesreason < 0 && !snes_div_func) {
1046     *accept = PETSC_FALSE;
1047     PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", nonlinear solve failure: %s\n", ts->steps, SNESConvergedReasons[snesreason]));
1048     if (++ts->num_snes_failures >= ts->max_snes_failures && ts->max_snes_failures != PETSC_UNLIMITED) {
1049       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
1050       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", nonlinear solve failures %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, ts->num_snes_failures));
1051       if (adapt->monitor) {
1052         PetscCall(PetscViewerASCIIAddTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
1053         PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt %s step %3" PetscInt_FMT " stage rejected t=%-11g+%10.3e, nonlinear solve failures %" PetscInt_FMT " greater than current TS allowed\n", ((PetscObject)adapt)->type_name, ts->steps,
1054                                          (double)ts->ptime, (double)ts->time_step, ts->num_snes_failures));
1055         PetscCall(PetscViewerASCIISubtractTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
1056       }
1057     }
1058   } else {
1059     *accept = (PetscBool)(func_accept && !snes_div_func);
1060     if (*accept && adapt->checkstage) PetscCall((*adapt->checkstage)(adapt, ts, t, Y, accept));
1061     if (!*accept) {
1062       const char *user_func = !func_accept ? "TSSetFunctionDomainError()" : "TSAdaptSetCheckStage";
1063       const char *snes_err  = "SNES invalid function domain";
1064       const char *err_msg   = snes_div_func && func_accept ? snes_err : user_func;
1065       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", solution rejected by %s\n", ts->steps, err_msg));
1066       if (adapt->monitor) {
1067         PetscCall(PetscViewerASCIIAddTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
1068         PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt %s step %3" PetscInt_FMT " stage rejected by %s\n", ((PetscObject)adapt)->type_name, ts->steps, err_msg));
1069         PetscCall(PetscViewerASCIISubtractTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
1070       }
1071     }
1072   }
1073 
1074   if (!(*accept) && !ts->reason) {
1075     PetscReal dt, new_dt;
1076     PetscCall(TSGetTimeStep(ts, &dt));
1077     new_dt = dt * adapt->scale_solve_failed;
1078     PetscCall(TSSetTimeStep(ts, new_dt));
1079     adapt->timestepjustdecreased += adapt->timestepjustdecreased_delay;
1080     if (adapt->monitor) {
1081       PetscCall(PetscViewerASCIIAddTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
1082       PetscCall(PetscViewerASCIIPrintf(adapt->monitor, "    TSAdapt %s step %3" PetscInt_FMT " stage rejected (SNES reason %s) t=%-11g+%10.3e retrying with dt=%-10.3e\n", ((PetscObject)adapt)->type_name, ts->steps, SNESConvergedReasons[snesreason],
1083                                        (double)ts->ptime, (double)dt, (double)new_dt));
1084       PetscCall(PetscViewerASCIISubtractTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
1085     }
1086   }
1087   PetscFunctionReturn(PETSC_SUCCESS);
1088 }
1089 
1090 /*@
1091   TSAdaptCreate - create an adaptive controller context for time stepping
1092 
1093   Collective
1094 
1095   Input Parameter:
1096 . comm - The communicator
1097 
1098   Output Parameter:
1099 . inadapt - new `TSAdapt` object
1100 
1101   Level: developer
1102 
1103   Note:
1104   `TSAdapt` creation is handled by `TS`, so users should not need to call this function.
1105 
1106 .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptSetType()`, `TSAdaptDestroy()`
1107 @*/
1108 PetscErrorCode TSAdaptCreate(MPI_Comm comm, TSAdapt *inadapt)
1109 {
1110   TSAdapt adapt;
1111 
1112   PetscFunctionBegin;
1113   PetscAssertPointer(inadapt, 2);
1114   PetscCall(TSAdaptInitializePackage());
1115 
1116   PetscCall(PetscHeaderCreate(adapt, TSADAPT_CLASSID, "TSAdapt", "Time stepping adaptivity", "TS", comm, TSAdaptDestroy, TSAdaptView));
1117   adapt->always_accept      = PETSC_FALSE;
1118   adapt->safety             = 0.9;
1119   adapt->reject_safety      = 0.5;
1120   adapt->clip[0]            = 0.1;
1121   adapt->clip[1]            = 10.;
1122   adapt->dt_min             = 1e-20;
1123   adapt->dt_max             = 1e+20;
1124   adapt->ignore_max         = -1.0;
1125   adapt->glee_use_local     = PETSC_TRUE;
1126   adapt->scale_solve_failed = 0.25;
1127   /* these two safety factors are not public, and they are used only in the TS_EXACTFINALTIME_MATCHSTEP case
1128      to prevent from situations were unreasonably small time steps are taken in order to match the final time */
1129   adapt->matchstepfac[0]             = 0.01; /* allow 1% step size increase in the last step */
1130   adapt->matchstepfac[1]             = 2.0;  /* halve last step if it is greater than what remains divided this factor */
1131   adapt->wnormtype                   = NORM_2;
1132   adapt->timestepjustdecreased_delay = 0;
1133   *inadapt                           = adapt;
1134   PetscFunctionReturn(PETSC_SUCCESS);
1135 }
1136