1 /* 2 Code for Timestepping with explicit SSP. 3 */ 4 #include <petsc/private/tsimpl.h> /*I "petscts.h" I*/ 5 6 PetscFunctionList TSSSPList = NULL; 7 static PetscBool TSSSPPackageInitialized; 8 9 typedef struct { 10 PetscErrorCode (*onestep)(TS, PetscReal, PetscReal, Vec); 11 char *type_name; 12 PetscInt nstages; 13 Vec *work; 14 PetscInt nwork; 15 PetscBool workout; 16 } TS_SSP; 17 18 static PetscErrorCode TSSSPGetWorkVectors(TS ts, PetscInt n, Vec **work) 19 { 20 TS_SSP *ssp = (TS_SSP *)ts->data; 21 22 PetscFunctionBegin; 23 PetscCheck(!ssp->workout, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Work vectors already gotten"); 24 if (ssp->nwork < n) { 25 if (ssp->nwork > 0) PetscCall(VecDestroyVecs(ssp->nwork, &ssp->work)); 26 PetscCall(VecDuplicateVecs(ts->vec_sol, n, &ssp->work)); 27 ssp->nwork = n; 28 } 29 *work = ssp->work; 30 ssp->workout = PETSC_TRUE; 31 PetscFunctionReturn(PETSC_SUCCESS); 32 } 33 34 static PetscErrorCode TSSSPRestoreWorkVectors(TS ts, PetscInt n, Vec **work) 35 { 36 TS_SSP *ssp = (TS_SSP *)ts->data; 37 38 PetscFunctionBegin; 39 PetscCheck(ssp->workout, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Work vectors have not been gotten"); 40 PetscCheck(*work == ssp->work, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong work vectors checked out"); 41 ssp->workout = PETSC_FALSE; 42 *work = NULL; 43 PetscFunctionReturn(PETSC_SUCCESS); 44 } 45 46 /*MC 47 TSSSPRKS2 - Optimal second order SSP Runge-Kutta method, low-storage, c_eff=(s-1)/s. Pseudocode 2 of {cite}`ketcheson_2008` 48 49 Level: beginner 50 51 .seealso: [](ch_ts), `TSSSP`, `TSSSPSetType()`, `TSSSPSetNumStages()` 52 M*/ 53 static PetscErrorCode TSSSPStep_RK_2(TS ts, PetscReal t0, PetscReal dt, Vec sol) 54 { 55 TS_SSP *ssp = (TS_SSP *)ts->data; 56 Vec *work, F; 57 PetscInt i, s; 58 59 PetscFunctionBegin; 60 s = ssp->nstages; 61 PetscCall(TSSSPGetWorkVectors(ts, 2, &work)); 62 F = work[1]; 63 PetscCall(VecCopy(sol, work[0])); 64 for (i = 0; i < s - 1; i++) { 65 PetscReal stage_time = t0 + dt * (i / (s - 1.)); 66 PetscCall(TSPreStage(ts, stage_time)); 67 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 68 PetscCall(VecAXPY(work[0], dt / (s - 1.), F)); 69 } 70 PetscCall(TSComputeRHSFunction(ts, t0 + dt, work[0], F)); 71 PetscCall(VecAXPBYPCZ(sol, (s - 1.) / s, dt / s, 1. / s, work[0], F)); 72 PetscCall(TSSSPRestoreWorkVectors(ts, 2, &work)); 73 PetscFunctionReturn(PETSC_SUCCESS); 74 } 75 76 /*MC 77 TSSSPRKS3 - Optimal third order SSP Runge-Kutta, low-storage, $c_eff=(PetscSqrtReal(s)-1)/PetscSqrtReal(s)$, where `PetscSqrtReal`(s) is an integer 78 79 Pseudocode 2 of {cite}`ketcheson_2008` 80 81 Level: beginner 82 83 .seealso: [](ch_ts), `TSSSP`, `TSSSPSetType()`, `TSSSPSetNumStages()` 84 M*/ 85 static PetscErrorCode TSSSPStep_RK_3(TS ts, PetscReal t0, PetscReal dt, Vec sol) 86 { 87 TS_SSP *ssp = (TS_SSP *)ts->data; 88 Vec *work, F; 89 PetscInt i, s, n, r; 90 PetscReal c, stage_time; 91 92 PetscFunctionBegin; 93 s = ssp->nstages; 94 n = (PetscInt)(PetscSqrtReal((PetscReal)s) + 0.001); 95 r = s - n; 96 PetscCheck(n * n == s, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for optimal third order schemes with %" PetscInt_FMT " stages, must be a square number at least 4", s); 97 PetscCall(TSSSPGetWorkVectors(ts, 3, &work)); 98 F = work[2]; 99 PetscCall(VecCopy(sol, work[0])); 100 for (i = 0; i < (n - 1) * (n - 2) / 2; i++) { 101 c = (i < n * (n + 1) / 2) ? 1. * i / (s - n) : (1. * i - n) / (s - n); 102 stage_time = t0 + c * dt; 103 PetscCall(TSPreStage(ts, stage_time)); 104 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 105 PetscCall(VecAXPY(work[0], dt / r, F)); 106 } 107 PetscCall(VecCopy(work[0], work[1])); 108 for (; i < n * (n + 1) / 2 - 1; i++) { 109 c = (i < n * (n + 1) / 2) ? 1. * i / (s - n) : (1. * i - n) / (s - n); 110 stage_time = t0 + c * dt; 111 PetscCall(TSPreStage(ts, stage_time)); 112 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 113 PetscCall(VecAXPY(work[0], dt / r, F)); 114 } 115 { 116 c = (i < n * (n + 1) / 2) ? 1. * i / (s - n) : (1. * i - n) / (s - n); 117 stage_time = t0 + c * dt; 118 PetscCall(TSPreStage(ts, stage_time)); 119 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 120 PetscCall(VecAXPBYPCZ(work[0], 1. * n / (2 * n - 1.), (n - 1.) * dt / (r * (2 * n - 1)), (n - 1.) / (2 * n - 1.), work[1], F)); 121 i++; 122 } 123 for (; i < s; i++) { 124 c = (i < n * (n + 1) / 2) ? 1. * i / (s - n) : (1. * i - n) / (s - n); 125 stage_time = t0 + c * dt; 126 PetscCall(TSPreStage(ts, stage_time)); 127 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 128 PetscCall(VecAXPY(work[0], dt / r, F)); 129 } 130 PetscCall(VecCopy(work[0], sol)); 131 PetscCall(TSSSPRestoreWorkVectors(ts, 3, &work)); 132 PetscFunctionReturn(PETSC_SUCCESS); 133 } 134 135 /*MC 136 TSSSPRKS104 - Optimal fourth order SSP Runge-Kutta, low-storage (2N), c_eff=0.6 137 138 SSPRK(10,4), Pseudocode 3 of {cite}`ketcheson_2008` 139 140 Level: beginner 141 142 .seealso: [](ch_ts), `TSSSP`, `TSSSPSetType()` 143 M*/ 144 static PetscErrorCode TSSSPStep_RK_10_4(TS ts, PetscReal t0, PetscReal dt, Vec sol) 145 { 146 const PetscReal c[10] = {0, 1. / 6, 2. / 6, 3. / 6, 4. / 6, 2. / 6, 3. / 6, 4. / 6, 5. / 6, 1}; 147 Vec *work, F; 148 PetscInt i; 149 PetscReal stage_time; 150 151 PetscFunctionBegin; 152 PetscCall(TSSSPGetWorkVectors(ts, 3, &work)); 153 F = work[2]; 154 PetscCall(VecCopy(sol, work[0])); 155 for (i = 0; i < 5; i++) { 156 stage_time = t0 + c[i] * dt; 157 PetscCall(TSPreStage(ts, stage_time)); 158 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 159 PetscCall(VecAXPY(work[0], dt / 6, F)); 160 } 161 PetscCall(VecAXPBYPCZ(work[1], 1. / 25, 9. / 25, 0, sol, work[0])); 162 PetscCall(VecAXPBY(work[0], 15, -5, work[1])); 163 for (; i < 9; i++) { 164 stage_time = t0 + c[i] * dt; 165 PetscCall(TSPreStage(ts, stage_time)); 166 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 167 PetscCall(VecAXPY(work[0], dt / 6, F)); 168 } 169 stage_time = t0 + dt; 170 PetscCall(TSPreStage(ts, stage_time)); 171 PetscCall(TSComputeRHSFunction(ts, stage_time, work[0], F)); 172 PetscCall(VecAXPBYPCZ(work[1], 3. / 5, dt / 10, 1, work[0], F)); 173 PetscCall(VecCopy(work[1], sol)); 174 PetscCall(TSSSPRestoreWorkVectors(ts, 3, &work)); 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 static PetscErrorCode TSSetUp_SSP(TS ts) 179 { 180 PetscFunctionBegin; 181 PetscCall(TSCheckImplicitTerm(ts)); 182 PetscCall(TSGetAdapt(ts, &ts->adapt)); 183 PetscCall(TSAdaptCandidatesClear(ts->adapt)); 184 PetscFunctionReturn(PETSC_SUCCESS); 185 } 186 187 static PetscErrorCode TSStep_SSP(TS ts) 188 { 189 TS_SSP *ssp = (TS_SSP *)ts->data; 190 Vec sol = ts->vec_sol; 191 PetscBool stageok, accept = PETSC_TRUE; 192 PetscReal next_time_step = ts->time_step; 193 194 PetscFunctionBegin; 195 PetscCall((*ssp->onestep)(ts, ts->ptime, ts->time_step, sol)); 196 PetscCall(TSPostStage(ts, ts->ptime, 0, &sol)); 197 PetscCall(TSAdaptCheckStage(ts->adapt, ts, ts->ptime + ts->time_step, sol, &stageok)); 198 if (!stageok) { 199 ts->reason = TS_DIVERGED_STEP_REJECTED; 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 203 PetscCall(TSAdaptChoose(ts->adapt, ts, ts->time_step, NULL, &next_time_step, &accept)); 204 if (!accept) { 205 ts->reason = TS_DIVERGED_STEP_REJECTED; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 ts->ptime += ts->time_step; 210 ts->time_step = next_time_step; 211 PetscFunctionReturn(PETSC_SUCCESS); 212 } 213 214 static PetscErrorCode TSReset_SSP(TS ts) 215 { 216 TS_SSP *ssp = (TS_SSP *)ts->data; 217 218 PetscFunctionBegin; 219 if (ssp->work) PetscCall(VecDestroyVecs(ssp->nwork, &ssp->work)); 220 ssp->nwork = 0; 221 ssp->workout = PETSC_FALSE; 222 PetscFunctionReturn(PETSC_SUCCESS); 223 } 224 225 static PetscErrorCode TSDestroy_SSP(TS ts) 226 { 227 TS_SSP *ssp = (TS_SSP *)ts->data; 228 229 PetscFunctionBegin; 230 PetscCall(TSReset_SSP(ts)); 231 PetscCall(PetscFree(ssp->type_name)); 232 PetscCall(PetscFree(ts->data)); 233 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPGetType_C", NULL)); 234 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPSetType_C", NULL)); 235 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPGetNumStages_C", NULL)); 236 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPSetNumStages_C", NULL)); 237 PetscFunctionReturn(PETSC_SUCCESS); 238 } 239 240 /*@ 241 TSSSPSetType - set the `TSSSP` time integration scheme to use 242 243 Logically Collective 244 245 Input Parameters: 246 + ts - time stepping object 247 - ssptype - type of scheme to use 248 249 Options Database Keys: 250 + -ts_ssp_type <rks2> - Type of `TSSSP` method (one of) rks2 rks3 rk104 251 - -ts_ssp_nstages<rks2: 5, rks3: 9> - Number of stages 252 253 Level: beginner 254 255 .seealso: [](ch_ts), `TSSSP`, `TSSSPGetType()`, `TSSSPSetNumStages()`, `TSSSPRKS2`, `TSSSPRKS3`, `TSSSPRK104` 256 @*/ 257 PetscErrorCode TSSSPSetType(TS ts, TSSSPType ssptype) 258 { 259 PetscFunctionBegin; 260 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 261 PetscAssertPointer(ssptype, 2); 262 PetscTryMethod(ts, "TSSSPSetType_C", (TS, TSSSPType), (ts, ssptype)); 263 PetscFunctionReturn(PETSC_SUCCESS); 264 } 265 266 /*@ 267 TSSSPGetType - get the `TSSSP` time integration scheme 268 269 Logically Collective 270 271 Input Parameter: 272 . ts - time stepping object 273 274 Output Parameter: 275 . type - type of scheme being used 276 277 Level: beginner 278 279 .seealso: [](ch_ts), `TSSSP`, `TSSSPSetType()`, `TSSSPSetNumStages()`, `TSSSPRKS2`, `TSSSPRKS3`, `TSSSPRK104` 280 @*/ 281 PetscErrorCode TSSSPGetType(TS ts, TSSSPType *type) 282 { 283 PetscFunctionBegin; 284 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 285 PetscUseMethod(ts, "TSSSPGetType_C", (TS, TSSSPType *), (ts, type)); 286 PetscFunctionReturn(PETSC_SUCCESS); 287 } 288 289 /*@ 290 TSSSPSetNumStages - set the number of stages to use with the `TSSSP` method. Must be called after 291 `TSSSPSetType()`. 292 293 Logically Collective 294 295 Input Parameters: 296 + ts - time stepping object 297 - nstages - number of stages 298 299 Options Database Keys: 300 + -ts_ssp_type <rks2> - Type of `TSSSP` method (one of) rks2 rks3 rk104 301 - -ts_ssp_nstages<rks2: 5, rks3: 9> - Number of stages 302 303 Level: beginner 304 305 .seealso: [](ch_ts), `TSSSP`, `TSSSPGetNumStages()`, `TSSSPRKS2`, `TSSSPRKS3`, `TSSSPRK104` 306 @*/ 307 PetscErrorCode TSSSPSetNumStages(TS ts, PetscInt nstages) 308 { 309 PetscFunctionBegin; 310 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 311 PetscTryMethod(ts, "TSSSPSetNumStages_C", (TS, PetscInt), (ts, nstages)); 312 PetscFunctionReturn(PETSC_SUCCESS); 313 } 314 315 /*@ 316 TSSSPGetNumStages - get the number of stages in the `TSSSP` time integration scheme 317 318 Logically Collective 319 320 Input Parameter: 321 . ts - time stepping object 322 323 Output Parameter: 324 . nstages - number of stages 325 326 Level: beginner 327 328 .seealso: [](ch_ts), `TSSSP`, `TSSSPGetType()`, `TSSSPSetNumStages()`, `TSSSPRKS2`, `TSSSPRKS3`, `TSSSPRK104` 329 @*/ 330 PetscErrorCode TSSSPGetNumStages(TS ts, PetscInt *nstages) 331 { 332 PetscFunctionBegin; 333 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 334 PetscUseMethod(ts, "TSSSPGetNumStages_C", (TS, PetscInt *), (ts, nstages)); 335 PetscFunctionReturn(PETSC_SUCCESS); 336 } 337 338 static PetscErrorCode TSSSPSetType_SSP(TS ts, TSSSPType type) 339 { 340 TS_SSP *ssp = (TS_SSP *)ts->data; 341 PetscErrorCode (*r)(TS, PetscReal, PetscReal, Vec); 342 PetscBool flag; 343 344 PetscFunctionBegin; 345 PetscCall(PetscFunctionListFind(TSSSPList, type, &r)); 346 PetscCheck(r, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown TS_SSP type %s given", type); 347 ssp->onestep = r; 348 PetscCall(PetscFree(ssp->type_name)); 349 PetscCall(PetscStrallocpy(type, &ssp->type_name)); 350 ts->default_adapt_type = TSADAPTNONE; 351 PetscCall(PetscStrcmp(type, TSSSPRKS2, &flag)); 352 if (flag) { 353 ssp->nstages = 5; 354 } else { 355 PetscCall(PetscStrcmp(type, TSSSPRKS3, &flag)); 356 if (flag) { 357 ssp->nstages = 9; 358 } else { 359 ssp->nstages = 5; 360 } 361 } 362 PetscFunctionReturn(PETSC_SUCCESS); 363 } 364 static PetscErrorCode TSSSPGetType_SSP(TS ts, TSSSPType *type) 365 { 366 TS_SSP *ssp = (TS_SSP *)ts->data; 367 368 PetscFunctionBegin; 369 *type = ssp->type_name; 370 PetscFunctionReturn(PETSC_SUCCESS); 371 } 372 static PetscErrorCode TSSSPSetNumStages_SSP(TS ts, PetscInt nstages) 373 { 374 TS_SSP *ssp = (TS_SSP *)ts->data; 375 376 PetscFunctionBegin; 377 ssp->nstages = nstages; 378 PetscFunctionReturn(PETSC_SUCCESS); 379 } 380 static PetscErrorCode TSSSPGetNumStages_SSP(TS ts, PetscInt *nstages) 381 { 382 TS_SSP *ssp = (TS_SSP *)ts->data; 383 384 PetscFunctionBegin; 385 *nstages = ssp->nstages; 386 PetscFunctionReturn(PETSC_SUCCESS); 387 } 388 389 static PetscErrorCode TSSetFromOptions_SSP(TS ts, PetscOptionItems PetscOptionsObject) 390 { 391 char tname[256] = TSSSPRKS2; 392 TS_SSP *ssp = (TS_SSP *)ts->data; 393 PetscBool flg; 394 395 PetscFunctionBegin; 396 PetscOptionsHeadBegin(PetscOptionsObject, "SSP ODE solver options"); 397 { 398 PetscCall(PetscOptionsFList("-ts_ssp_type", "Type of SSP method", "TSSSPSetType", TSSSPList, tname, tname, sizeof(tname), &flg)); 399 if (flg) PetscCall(TSSSPSetType(ts, tname)); 400 PetscCall(PetscOptionsInt("-ts_ssp_nstages", "Number of stages", "TSSSPSetNumStages", ssp->nstages, &ssp->nstages, NULL)); 401 } 402 PetscOptionsHeadEnd(); 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 static PetscErrorCode TSView_SSP(TS ts, PetscViewer viewer) 407 { 408 TS_SSP *ssp = (TS_SSP *)ts->data; 409 PetscBool ascii; 410 411 PetscFunctionBegin; 412 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &ascii)); 413 if (ascii) PetscCall(PetscViewerASCIIPrintf(viewer, " Scheme: %s\n", ssp->type_name)); 414 PetscFunctionReturn(PETSC_SUCCESS); 415 } 416 417 /*MC 418 TSSSP - Explicit strong stability preserving ODE solver {cite}`ketcheson_2008` {cite}`gottliebketchesonshu2009` 419 420 Most hyperbolic conservation laws have exact solutions that are total variation diminishing (TVD) or total variation 421 bounded (TVB) although these solutions often contain discontinuities. Spatial discretizations such as Godunov's 422 scheme and high-resolution finite volume methods (TVD limiters, ENO/WENO) are designed to preserve these properties, 423 but they are usually formulated using a forward Euler time discretization or by coupling the space and time 424 discretization as in the classical Lax-Wendroff scheme. When the space and time discretization is coupled, it is very 425 difficult to produce schemes with high temporal accuracy while preserving TVD properties. An alternative is the 426 semidiscrete formulation where we choose a spatial discretization that is TVD with forward Euler and then choose a 427 time discretization that preserves the TVD property. Such integrators are called strong stability preserving (SSP). 428 429 Let c_eff be the minimum number of function evaluations required to step as far as one step of forward Euler while 430 still being SSP. Some theoretical bounds 431 432 1. There are no explicit methods with c_eff > 1. 433 434 2. There are no explicit methods beyond order 4 (for nonlinear problems) and c_eff > 0. 435 436 3. There are no implicit methods with order greater than 1 and c_eff > 2. 437 438 This integrator provides Runge-Kutta methods of order 2, 3, and 4 with maximal values of c_eff. More stages allows 439 for larger values of c_eff which improves efficiency. These implementations are low-memory and only use 2 or 3 work 440 vectors regardless of the total number of stages, so e.g. 25-stage 3rd order methods may be an excellent choice. 441 442 Methods can be chosen with -ts_ssp_type {rks2,rks3,rk104} 443 444 rks2: Second order methods with any number s>1 of stages. c_eff = (s-1)/s 445 446 rks3: Third order methods with s=n^2 stages, n>1. c_eff = (s-n)/s 447 448 rk104: A 10-stage fourth order method. c_eff = 0.6 449 450 Level: beginner 451 452 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()` 453 M*/ 454 PETSC_EXTERN PetscErrorCode TSCreate_SSP(TS ts) 455 { 456 TS_SSP *ssp; 457 458 PetscFunctionBegin; 459 PetscCall(TSSSPInitializePackage()); 460 461 ts->ops->setup = TSSetUp_SSP; 462 ts->ops->step = TSStep_SSP; 463 ts->ops->reset = TSReset_SSP; 464 ts->ops->destroy = TSDestroy_SSP; 465 ts->ops->setfromoptions = TSSetFromOptions_SSP; 466 ts->ops->view = TSView_SSP; 467 468 PetscCall(PetscNew(&ssp)); 469 ts->data = (void *)ssp; 470 471 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPGetType_C", TSSSPGetType_SSP)); 472 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPSetType_C", TSSSPSetType_SSP)); 473 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPGetNumStages_C", TSSSPGetNumStages_SSP)); 474 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSSPSetNumStages_C", TSSSPSetNumStages_SSP)); 475 476 PetscCall(TSSSPSetType(ts, TSSSPRKS2)); 477 PetscFunctionReturn(PETSC_SUCCESS); 478 } 479 480 /*@C 481 TSSSPInitializePackage - This function initializes everything in the `TSSSP` package. It is called 482 from `TSInitializePackage()`. 483 484 Level: developer 485 486 .seealso: [](ch_ts), `PetscInitialize()`, `TSSSPFinalizePackage()`, `TSInitializePackage()` 487 @*/ 488 PetscErrorCode TSSSPInitializePackage(void) 489 { 490 PetscFunctionBegin; 491 if (TSSSPPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS); 492 TSSSPPackageInitialized = PETSC_TRUE; 493 PetscCall(PetscFunctionListAdd(&TSSSPList, TSSSPRKS2, TSSSPStep_RK_2)); 494 PetscCall(PetscFunctionListAdd(&TSSSPList, TSSSPRKS3, TSSSPStep_RK_3)); 495 PetscCall(PetscFunctionListAdd(&TSSSPList, TSSSPRK104, TSSSPStep_RK_10_4)); 496 PetscCall(PetscRegisterFinalize(TSSSPFinalizePackage)); 497 PetscFunctionReturn(PETSC_SUCCESS); 498 } 499 500 /*@C 501 TSSSPFinalizePackage - This function destroys everything in the `TSSSP` package. It is 502 called from `PetscFinalize()`. 503 504 Level: developer 505 506 .seealso: [](ch_ts), `PetscFinalize()`, `TSSSPInitiallizePackage()`, `TSInitializePackage()` 507 @*/ 508 PetscErrorCode TSSSPFinalizePackage(void) 509 { 510 PetscFunctionBegin; 511 TSSSPPackageInitialized = PETSC_FALSE; 512 PetscCall(PetscFunctionListDestroy(&TSSSPList)); 513 PetscFunctionReturn(PETSC_SUCCESS); 514 } 515