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