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