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