Actual source code: tsadapt.c
1: #include <petsc/private/tsimpl.h>
3: PetscClassId TSADAPT_CLASSID;
5: static PetscFunctionList TSAdaptList;
6: static PetscBool TSAdaptPackageInitialized;
7: static PetscBool TSAdaptRegisterAllCalled;
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);
16: /*@C
17: TSAdaptRegister - adds a TSAdapt implementation
19: Not Collective, No Fortran Support
21: Input Parameters:
22: + sname - name of user-defined adaptivity scheme
23: - function - routine to create method context
25: Level: advanced
27: Notes:
28: `TSAdaptRegister()` may be called multiple times to add several user-defined families.
30: Example Usage:
31: .vb
32: TSAdaptRegister("my_scheme", MySchemeCreate);
33: .ve
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
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: }
50: /*@C
51: TSAdaptRegisterAll - Registers all of the adaptivity schemes in `TSAdapt`
53: Not Collective
55: Level: advanced
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: }
73: /*@C
74: TSAdaptFinalizePackage - This function destroys everything in the `TS` package. It is
75: called from `PetscFinalize()`.
77: Level: developer
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: }
90: /*@C
91: TSAdaptInitializePackage - This function initializes everything in the `TSAdapt` package. It is
92: called from `TSInitializePackage()`.
94: Level: developer
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: }
109: /*@
110: TSAdaptSetType - sets the approach used for the error adapter
112: Logicially Collective
114: Input Parameters:
115: + adapt - the `TS` adapter, most likely obtained with `TSGetAdapt()`
116: - type - one of the `TSAdaptType`
118: Options Database Key:
119: . -ts_adapt_type <basic or dsp or none> - to set the adapter type
121: Level: intermediate
123: .seealso: [](ch_ts), `TSGetAdapt()`, `TSAdaptDestroy()`, `TSAdaptType`, `TSAdaptGetType()`
124: @*/
125: PetscErrorCode TSAdaptSetType(TSAdapt adapt, TSAdaptType type)
126: {
127: PetscBool match;
128: PetscErrorCode (*r)(TSAdapt);
130: PetscFunctionBegin;
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: }
144: /*@
145: TSAdaptGetType - gets the `TS` adapter method type (as a string).
147: Not Collective
149: Input Parameter:
150: . adapt - The `TS` adapter, most likely obtained with `TSGetAdapt()`
152: Output Parameter:
153: . type - The name of `TS` adapter method
155: Level: intermediate
157: .seealso: `TSAdapt`, `TSAdaptType`, `TSAdaptSetType()`
158: @*/
159: PetscErrorCode TSAdaptGetType(TSAdapt adapt, TSAdaptType *type)
160: {
161: PetscFunctionBegin;
163: PetscAssertPointer(type, 2);
164: *type = ((PetscObject)adapt)->type_name;
165: PetscFunctionReturn(PETSC_SUCCESS);
166: }
168: PetscErrorCode TSAdaptSetOptionsPrefix(TSAdapt adapt, const char prefix[])
169: {
170: PetscFunctionBegin;
172: PetscCall(PetscObjectSetOptionsPrefix((PetscObject)adapt, prefix));
173: PetscFunctionReturn(PETSC_SUCCESS);
174: }
176: /*@
177: TSAdaptLoad - Loads a TSAdapt that has been stored in binary with `TSAdaptView()`.
179: Collective
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()`
187: Level: intermediate
189: Note:
190: The type is determined by the data in the file, any type set into the `TSAdapt` before this call is ignored.
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];
199: PetscFunctionBegin;
202: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
203: PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");
205: PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
206: PetscCall(TSAdaptSetType(adapt, type));
207: PetscTryTypeMethod(adapt, load, viewer);
208: PetscFunctionReturn(PETSC_SUCCESS);
209: }
211: PetscErrorCode TSAdaptView(TSAdapt adapt, PetscViewer viewer)
212: {
213: PetscBool iascii, isbinary, isnone, isglee;
215: PetscFunctionBegin;
217: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)adapt), &viewer));
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];
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: }
256: /*@
257: TSAdaptReset - Resets a `TSAdapt` context to its defaults
259: Collective
261: Input Parameter:
262: . adapt - the `TSAdapt` context obtained from `TSGetAdapt()` or `TSAdaptCreate()`
264: Level: developer
266: .seealso: [](ch_ts), `TSGetAdapt()`, `TSAdapt`, `TSAdaptCreate()`, `TSAdaptDestroy()`
267: @*/
268: PetscErrorCode TSAdaptReset(TSAdapt adapt)
269: {
270: PetscFunctionBegin;
272: PetscTryTypeMethod(adapt, reset);
273: PetscFunctionReturn(PETSC_SUCCESS);
274: }
276: PetscErrorCode TSAdaptDestroy(TSAdapt *adapt)
277: {
278: PetscFunctionBegin;
279: if (!*adapt) PetscFunctionReturn(PETSC_SUCCESS);
281: if (--((PetscObject)*adapt)->refct > 0) {
282: *adapt = NULL;
283: PetscFunctionReturn(PETSC_SUCCESS);
284: }
286: PetscCall(TSAdaptReset(*adapt));
288: PetscTryTypeMethod(*adapt, destroy);
289: PetscCall(PetscViewerDestroy(&(*adapt)->monitor));
290: PetscCall(PetscHeaderDestroy(adapt));
291: PetscFunctionReturn(PETSC_SUCCESS);
292: }
294: /*@
295: TSAdaptSetMonitor - Monitor the choices made by the adaptive controller
297: Collective
299: Input Parameters:
300: + adapt - adaptive controller context
301: - flg - `PETSC_TRUE` to active a monitor, `PETSC_FALSE` to disable
303: Options Database Key:
304: . -ts_adapt_monitor - to turn on monitoring
306: Level: intermediate
308: .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptChoose()`
309: @*/
310: PetscErrorCode TSAdaptSetMonitor(TSAdapt adapt, PetscBool flg)
311: {
312: PetscFunctionBegin;
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: }
323: /*@C
324: TSAdaptSetCheckStage - Set a callback to check convergence for a stage
326: Logically Collective
328: Input Parameters:
329: + adapt - adaptive controller context
330: - func - stage check function
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
339: Level: advanced
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;
347: adapt->checkstage = func;
348: PetscFunctionReturn(PETSC_SUCCESS);
349: }
351: /*@
352: TSAdaptSetAlwaysAccept - Set whether to always accept steps regardless of
353: any error or stability condition not meeting the prescribed goal.
355: Logically Collective
357: Input Parameters:
358: + adapt - time step adaptivity context, usually gotten with `TSGetAdapt()`
359: - flag - whether to always accept steps
361: Options Database Key:
362: . -ts_adapt_always_accept - to always accept steps
364: Level: intermediate
366: .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptChoose()`
367: @*/
368: PetscErrorCode TSAdaptSetAlwaysAccept(TSAdapt adapt, PetscBool flag)
369: {
370: PetscFunctionBegin;
373: adapt->always_accept = flag;
374: PetscFunctionReturn(PETSC_SUCCESS);
375: }
377: /*@
378: TSAdaptSetSafety - Set safety factors for time step adaptor
380: Logically Collective
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
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
391: Level: intermediate
393: Note:
394: Use `PETSC_CURRENT` to keep the current value for either parameter
396: Fortran Note:
397: Use `PETSC_CURRENT_REAL`
399: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptGetSafety()`, `TSAdaptChoose()`
400: @*/
401: PetscErrorCode TSAdaptSetSafety(TSAdapt adapt, PetscReal safety, PetscReal reject_safety)
402: {
403: PetscFunctionBegin;
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: }
416: /*@
417: TSAdaptGetSafety - Get safety factors for time step adapter
419: Not Collective
421: Input Parameter:
422: . adapt - adaptive controller context
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
428: Level: intermediate
430: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptSetSafety()`, `TSAdaptChoose()`
431: @*/
432: PetscErrorCode TSAdaptGetSafety(TSAdapt adapt, PetscReal *safety, PetscReal *reject_safety)
433: {
434: PetscFunctionBegin;
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: }
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.
447: Logically Collective
449: Input Parameters:
450: + adapt - adaptive controller context
451: - max_ignore - threshold for solution components that are ignored during error estimation
453: Options Database Key:
454: . -ts_adapt_max_ignore <max_ignore> - to set the threshold
456: Level: intermediate
458: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptGetMaxIgnore()`, `TSAdaptChoose()`
459: @*/
460: PetscErrorCode TSAdaptSetMaxIgnore(TSAdapt adapt, PetscReal max_ignore)
461: {
462: PetscFunctionBegin;
465: adapt->ignore_max = max_ignore;
466: PetscFunctionReturn(PETSC_SUCCESS);
467: }
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).
473: Not Collective
475: Input Parameter:
476: . adapt - adaptive controller context
478: Output Parameter:
479: . max_ignore - threshold for solution components that are ignored during error estimation
481: Level: intermediate
483: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptSetMaxIgnore()`, `TSAdaptChoose()`
484: @*/
485: PetscErrorCode TSAdaptGetMaxIgnore(TSAdapt adapt, PetscReal *max_ignore)
486: {
487: PetscFunctionBegin;
489: PetscAssertPointer(max_ignore, 2);
490: *max_ignore = adapt->ignore_max;
491: PetscFunctionReturn(PETSC_SUCCESS);
492: }
494: /*@
495: TSAdaptSetClip - Sets the admissible decrease/increase factor in step size in the time step adapter
497: Logically collective
499: Input Parameters:
500: + adapt - adaptive controller context
501: . low - admissible decrease factor
502: - high - admissible increase factor
504: Options Database Key:
505: . -ts_adapt_clip <low>,<high> - to set admissible time step decrease and increase factors
507: Level: intermediate
509: Note:
510: Use `PETSC_CURRENT` to keep the current value for either parameter
512: Fortran Note:
513: Use `PETSC_CURRENT_REAL`
515: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptGetClip()`, `TSAdaptSetScaleSolveFailed()`
516: @*/
517: PetscErrorCode TSAdaptSetClip(TSAdapt adapt, PetscReal low, PetscReal high)
518: {
519: PetscFunctionBegin;
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: }
531: /*@
532: TSAdaptGetClip - Gets the admissible decrease/increase factor in step size in the time step adapter
534: Not Collective
536: Input Parameter:
537: . adapt - adaptive controller context
539: Output Parameters:
540: + low - optional, admissible decrease factor
541: - high - optional, admissible increase factor
543: Level: intermediate
545: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptSetClip()`, `TSAdaptSetScaleSolveFailed()`
546: @*/
547: PetscErrorCode TSAdaptGetClip(TSAdapt adapt, PetscReal *low, PetscReal *high)
548: {
549: PetscFunctionBegin;
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: }
558: /*@
559: TSAdaptSetScaleSolveFailed - Scale step size by this factor if solve fails
561: Logically Collective
563: Input Parameters:
564: + adapt - adaptive controller context
565: - scale - scale
567: Options Database Key:
568: . -ts_adapt_scale_solve_failed <scale> - to set scale step by this factor if solve fails
570: Level: intermediate
572: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptGetScaleSolveFailed()`, `TSAdaptGetClip()`
573: @*/
574: PetscErrorCode TSAdaptSetScaleSolveFailed(TSAdapt adapt, PetscReal scale)
575: {
576: PetscFunctionBegin;
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: }
585: /*@
586: TSAdaptGetScaleSolveFailed - Gets the admissible decrease/increase factor in step size
588: Not Collective
590: Input Parameter:
591: . adapt - adaptive controller context
593: Output Parameter:
594: . scale - scale factor
596: Level: intermediate
598: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptChoose()`, `TSAdaptSetScaleSolveFailed()`, `TSAdaptSetClip()`
599: @*/
600: PetscErrorCode TSAdaptGetScaleSolveFailed(TSAdapt adapt, PetscReal *scale)
601: {
602: PetscFunctionBegin;
604: if (scale) PetscAssertPointer(scale, 2);
605: if (scale) *scale = adapt->scale_solve_failed;
606: PetscFunctionReturn(PETSC_SUCCESS);
607: }
609: /*@
610: TSAdaptSetStepLimits - Set the minimum and maximum step sizes to be considered by the time step controller
612: Logically Collective
614: Input Parameters:
615: + adapt - time step adaptivity context, usually gotten with `TSGetAdapt()`
616: . hmin - minimum time step
617: - hmax - maximum time step
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
623: Level: intermediate
625: Note:
626: Use `PETSC_CURRENT` to keep the current value for either parameter
628: Fortran Note:
629: Use `PETSC_CURRENT_REAL`
631: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptGetStepLimits()`, `TSAdaptChoose()`
632: @*/
633: PetscErrorCode TSAdaptSetStepLimits(TSAdapt adapt, PetscReal hmin, PetscReal hmax)
634: {
635: PetscFunctionBegin;
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: }
649: /*@
650: TSAdaptGetStepLimits - Get the minimum and maximum step sizes to be considered by the time step controller
652: Not Collective
654: Input Parameter:
655: . adapt - time step adaptivity context, usually gotten with `TSGetAdapt()`
657: Output Parameters:
658: + hmin - minimum time step
659: - hmax - maximum time step
661: Level: intermediate
663: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptSetStepLimits()`, `TSAdaptChoose()`
664: @*/
665: PetscErrorCode TSAdaptGetStepLimits(TSAdapt adapt, PetscReal *hmin, PetscReal *hmax)
666: {
667: PetscFunctionBegin;
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: }
676: /*@C
677: TSAdaptSetFromOptions - Sets various `TSAdapt` parameters from user options.
679: Collective
681: Input Parameters:
682: + adapt - the `TSAdapt` context
683: - PetscOptionsObject - object created by `PetscOptionsBegin()`
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
697: Level: advanced
699: Note:
700: This function is automatically called by `TSSetFromOptions()`
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;
712: PetscFunctionBegin;
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));
720: PetscCall(PetscOptionsBool("-ts_adapt_always_accept", "Always accept the step", "TSAdaptSetAlwaysAccept", adapt->always_accept, &flg, &set));
721: if (set) PetscCall(TSAdaptSetAlwaysAccept(adapt, flg));
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));
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]));
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));
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));
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));
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");
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));
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));
756: PetscTryTypeMethod(adapt, setfromoptions, PetscOptionsObject);
757: PetscOptionsHeadEnd();
758: PetscFunctionReturn(PETSC_SUCCESS);
759: }
761: /*@
762: TSAdaptCandidatesClear - clear any previously set candidate schemes
764: Logically Collective
766: Input Parameter:
767: . adapt - adaptive controller
769: Level: developer
771: .seealso: [](ch_ts), `TSAdapt`, `TSAdaptCreate()`, `TSAdaptCandidateAdd()`, `TSAdaptChoose()`
772: @*/
773: PetscErrorCode TSAdaptCandidatesClear(TSAdapt adapt)
774: {
775: PetscFunctionBegin;
777: PetscCall(PetscMemzero(&adapt->candidates, sizeof(adapt->candidates)));
778: PetscFunctionReturn(PETSC_SUCCESS);
779: }
781: /*@C
782: TSAdaptCandidateAdd - add a candidate scheme for the adaptive controller to select from
784: Logically Collective; No Fortran Support
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
795: Level: developer
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;
803: PetscFunctionBegin;
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;
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: }
822: /*@C
823: TSAdaptCandidatesGet - Get the list of candidate orders of accuracy and cost
825: Not Collective
827: Input Parameter:
828: . adapt - time step adaptivity context
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
837: Level: developer
839: Note:
840: The current scheme is always returned in the first slot
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;
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: }
856: /*@C
857: TSAdaptChoose - choose which method and step size to use for the next step
859: Collective
861: Input Parameters:
862: + adapt - adaptive controller
863: . ts - time stepper
864: - h - current step size
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
871: Level: developer
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.
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;
887: PetscFunctionBegin;
890: if (next_sc) PetscAssertPointer(next_sc, 4);
891: PetscAssertPointer(next_h, 5);
892: PetscAssertPointer(accept, 6);
893: if (next_sc) *next_sc = 0;
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));
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));
913: PetscCall(PetscViewerASCIISubtractTab(adapt->monitor, ((PetscObject)adapt)->tablevel));
914: }
915: PetscFunctionReturn(PETSC_SUCCESS);
916: }
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;
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;
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;
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()");
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: }
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.
986: Logicially Collective
988: Input Parameters:
989: + adapt - adaptive controller context
990: - cnt - the number of timesteps
992: Options Database Key:
993: . -ts_adapt_time_step_increase_delay cnt - number of steps to delay the increase
995: Level: advanced
997: Notes:
998: This is to prevent an adaptor from bouncing back and forth between two nearby timesteps. The default is 0.
1000: The successful use of this option is problem dependent
1002: Developer Notes:
1003: There is no theory to support this option
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: }
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)
1017: Collective
1019: Input Parameters:
1020: + adapt - adaptive controller context
1021: . ts - time stepper
1022: . t - Current simulation time
1023: - Y - Current solution vector
1025: Output Parameter:
1026: . accept - `PETSC_TRUE` to accept the stage, `PETSC_FALSE` to reject
1028: Level: developer
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;
1037: PetscFunctionBegin;
1040: PetscAssertPointer(accept, 5);
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: }
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: }
1090: /*@
1091: TSAdaptCreate - create an adaptive controller context for time stepping
1093: Collective
1095: Input Parameter:
1096: . comm - The communicator
1098: Output Parameter:
1099: . inadapt - new `TSAdapt` object
1101: Level: developer
1103: Note:
1104: `TSAdapt` creation is handled by `TS`, so users should not need to call this function.
1106: .seealso: [](ch_ts), `TSAdapt`, `TSGetAdapt()`, `TSAdaptSetType()`, `TSAdaptDestroy()`
1107: @*/
1108: PetscErrorCode TSAdaptCreate(MPI_Comm comm, TSAdapt *inadapt)
1109: {
1110: TSAdapt adapt;
1112: PetscFunctionBegin;
1113: PetscAssertPointer(inadapt, 2);
1114: PetscCall(TSAdaptInitializePackage());
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: }