xref: /petsc/src/ts/impls/explicit/ssp/ssp.c (revision d52a580b706c59ca78066c1e38754e45b6b56e2b)
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