Actual source code: ssp.c
1: /*
2: Code for Timestepping with explicit SSP.
3: */
4: #include <private/tsimpl.h> /*I "petscts.h" I*/
6: PetscFList TSSSPList = 0;
7: #define TSSSPType char*
9: #define TSSSPRKS2 "rks2"
10: #define TSSSPRKS3 "rks3"
11: #define TSSSPRK104 "rk104"
13: typedef struct {
14: PetscErrorCode (*onestep)(TS,PetscReal,PetscReal,Vec);
15: PetscInt nstages;
16: Vec *work;
17: PetscInt nwork;
18: PetscBool workout;
19: } TS_SSP;
24: static PetscErrorCode SSPGetWorkVectors(TS ts,PetscInt n,Vec **work)
25: {
26: TS_SSP *ssp = (TS_SSP*)ts->data;
30: if (ssp->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Work vectors already gotten");
31: if (ssp->nwork < n) {
32: if (ssp->nwork > 0) {
33: VecDestroyVecs(ssp->nwork,&ssp->work);
34: }
35: VecDuplicateVecs(ts->vec_sol,n,&ssp->work);
36: ssp->nwork = n;
37: }
38: *work = ssp->work;
39: ssp->workout = PETSC_TRUE;
40: return(0);
41: }
45: static PetscErrorCode SSPRestoreWorkVectors(TS ts,PetscInt n,Vec **work)
46: {
47: TS_SSP *ssp = (TS_SSP*)ts->data;
50: if (!ssp->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Work vectors have not been gotten");
51: if (*work != ssp->work) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong work vectors checked out");
52: ssp->workout = PETSC_FALSE;
53: *work = PETSC_NULL;
54: return(0);
55: }
60: /* Optimal second order SSP Runge-Kutta, low-storage, c_eff=(s-1)/s */
61: /* Pseudocode 2 of Ketcheson 2008 */
62: static PetscErrorCode SSPStep_RK_2(TS ts,PetscReal t0,PetscReal dt,Vec sol)
63: {
64: TS_SSP *ssp = (TS_SSP*)ts->data;
65: Vec *work,F;
66: PetscInt i,s;
70: s = ssp->nstages;
71: SSPGetWorkVectors(ts,2,&work);
72: F = work[1];
73: VecCopy(sol,work[0]);
74: for (i=0; i<s-1; i++) {
75: TSComputeRHSFunction(ts,t0+dt*(i/(s-1.)),work[0],F);
76: VecAXPY(work[0],dt/(s-1.),F);
77: }
78: TSComputeRHSFunction(ts,t0+dt,work[0],F);
79: VecAXPBYPCZ(sol,(s-1.)/s,dt/s,1./s,work[0],F);
80: SSPRestoreWorkVectors(ts,2,&work);
81: return(0);
82: }
86: /* Optimal third order SSP Runge-Kutta, low-storage, c_eff=(sqrt(s)-1)/sqrt(s), where sqrt(s) is an integer */
87: /* Pseudocode 2 of Ketcheson 2008 */
88: static PetscErrorCode SSPStep_RK_3(TS ts,PetscReal t0,PetscReal dt,Vec sol)
89: {
90: TS_SSP *ssp = (TS_SSP*)ts->data;
91: Vec *work,F;
92: PetscInt i,s,n,r;
93: PetscReal c;
97: s = ssp->nstages;
98: n = (PetscInt)(sqrt((PetscReal)s)+0.001);
99: r = s-n;
100: if (n*n != s) SETERRQ1(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: SSPGetWorkVectors(ts,3,&work);
102: F = work[2];
103: 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: TSComputeRHSFunction(ts,t0+c*dt,work[0],F);
107: VecAXPY(work[0],dt/r,F);
108: }
109: VecCopy(work[0],work[1]);
110: for ( ; i<n*(n+1)/2-1; i++) {
111: c = (i<n*(n+1)/2) ? 1.*i/(s-n) : (1.*i-n)/(s-n);
112: TSComputeRHSFunction(ts,t0+c*dt,work[0],F);
113: 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: TSComputeRHSFunction(ts,t0+c*dt,work[0],F);
118: VecAXPBYPCZ(work[0],1.*n/(2*n-1.),(n-1.)*dt/(r*(2*n-1)),(n-1.)/(2*n-1.),work[1],F);
119: i++;
120: }
121: for ( ; i<s; i++) {
122: c = (i<n*(n+1)/2) ? 1.*i/(s-n) : (1.*i-n)/(s-n);
123: TSComputeRHSFunction(ts,t0+c*dt,work[0],F);
124: VecAXPY(work[0],dt/r,F);
125: }
126: VecCopy(work[0],sol);
127: SSPRestoreWorkVectors(ts,3,&work);
128: return(0);
129: }
133: /* Optimal fourth order SSP Runge-Kutta, low-storage (2N), c_eff=0.6 */
134: /* SSPRK(10,4), Pseudocode 3 of Ketcheson 2008 */
135: static PetscErrorCode SSPStep_RK_10_4(TS ts,PetscReal t0,PetscReal dt,Vec sol)
136: {
137: const PetscReal c[10] = {0, 1./6, 2./6, 3./6, 4./6, 2./6, 3./6, 4./6, 5./6, 1};
138: Vec *work,F;
139: PetscInt i;
143: SSPGetWorkVectors(ts,3,&work);
144: F = work[2];
145: VecCopy(sol,work[0]);
146: for (i=0; i<5; i++) {
147: TSComputeRHSFunction(ts,t0+c[i],work[0],F);
148: VecAXPY(work[0],dt/6,F);
149: }
150: VecAXPBYPCZ(work[1],1./25,9./25,0,sol,work[0]);
151: VecAXPBY(work[0],15,-5,work[1]);
152: for ( ; i<9; i++) {
153: TSComputeRHSFunction(ts,t0+c[i],work[0],F);
154: VecAXPY(work[0],dt/6,F);
155: }
156: TSComputeRHSFunction(ts,t0+dt,work[0],F);
157: VecAXPBYPCZ(work[1],3./5,dt/10,1,work[0],F);
158: VecCopy(work[1],sol);
159: SSPRestoreWorkVectors(ts,3,&work);
160: return(0);
161: }
166: static PetscErrorCode TSSetUp_SSP(TS ts)
167: {
168: /* TS_SSP *ssp = (TS_SSP*)ts->data; */
172: return(0);
173: }
177: static PetscErrorCode TSStep_SSP(TS ts)
178: {
179: TS_SSP *ssp = (TS_SSP*)ts->data;
180: Vec sol = ts->vec_sol;
184: (*ssp->onestep)(ts,ts->ptime,ts->time_step,sol);
185: ts->ptime += ts->time_step;
186: ts->steps++;
187: return(0);
188: }
189: /*------------------------------------------------------------*/
192: static PetscErrorCode TSReset_SSP(TS ts)
193: {
194: TS_SSP *ssp = (TS_SSP*)ts->data;
198: if (ssp->work) {VecDestroyVecs(ssp->nwork,&ssp->work);}
199: ssp->nwork = 0;
200: ssp->workout = PETSC_FALSE;
201: return(0);
202: }
206: static PetscErrorCode TSDestroy_SSP(TS ts)
207: {
211: TSReset_SSP(ts);
212: PetscFree(ts->data);
213: return(0);
214: }
215: /*------------------------------------------------------------*/
219: static PetscErrorCode TSSSPSetType(TS ts,const TSSSPType type)
220: {
221: PetscErrorCode ierr,(*r)(TS,PetscReal,PetscReal,Vec);
222: TS_SSP *ssp = (TS_SSP*)ts->data;
225: PetscFListFind(TSSSPList,((PetscObject)ts)->comm,type,PETSC_TRUE,(void(**)(void))&r);
226: if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TS_SSP type %s given",type);
227: ssp->onestep = r;
228: return(0);
229: }
233: static PetscErrorCode TSSetFromOptions_SSP(TS ts)
234: {
235: char tname[256] = TSSSPRKS2;
236: TS_SSP *ssp = (TS_SSP*)ts->data;
238: PetscBool flg;
241: PetscOptionsHead("SSP ODE solver options");
242: {
243: PetscOptionsList("-ts_ssp_type","Type of SSP method","TSSSPSetType",TSSSPList,tname,tname,sizeof(tname),&flg);
244: if (flg) {
245: TSSSPSetType(ts,tname);
246: }
247: PetscOptionsInt("-ts_ssp_nstages","Number of stages","TSSSPSetNumStages",ssp->nstages,&ssp->nstages,PETSC_NULL);
248: }
249: PetscOptionsTail();
250: return(0);
251: }
255: static PetscErrorCode TSView_SSP(TS ts,PetscViewer viewer)
256: {
258: return(0);
259: }
261: /* ------------------------------------------------------------ */
263: /*MC
264: TSSSP - Explicit strong stability preserving ODE solver
266: Most hyperbolic conservation laws have exact solutions that are total variation diminishing (TVD) or total variation
267: bounded (TVB) although these solutions often contain discontinuities. Spatial discretizations such as Godunov's
268: scheme and high-resolution finite volume methods (TVD limiters, ENO/WENO) are designed to preserve these properties,
269: but they are usually formulated using a forward Euler time discretization or by coupling the space and time
270: discretization as in the classical Lax-Wendroff scheme. When the space and time discretization is coupled, it is very
271: difficult to produce schemes with high temporal accuracy while preserving TVD properties. An alternative is the
272: semidiscrete formulation where we choose a spatial discretization that is TVD with forward Euler and then choose a
273: time discretization that preserves the TVD property. Such integrators are called strong stability preserving (SSP).
275: Let c_eff be the minimum number of function evaluations required to step as far as one step of forward Euler while
276: still being SSP. Some theoretical bounds
278: 1. There are no explicit methods with c_eff > 1.
280: 2. There are no explicit methods beyond order 4 (for nonlinear problems) and c_eff > 0.
282: 3. There are no implicit methods with order greater than 1 and c_eff > 2.
284: This integrator provides Runge-Kutta methods of order 2, 3, and 4 with maximal values of c_eff. More stages allows
285: for larger values of c_eff which improves efficiency. These implementations are low-memory and only use 2 or 3 work
286: vectors regardless of the total number of stages, so e.g. 25-stage 3rd order methods may be an excellent choice.
288: Methods can be chosen with -ts_ssp_type {rks2,rks3,rk104}
290: rks2: Second order methods with any number s>1 of stages. c_eff = (s-1)/s
292: rks3: Third order methods with s=n^2 stages, n>1. c_eff = (s-n)/s
294: rk104: A 10-stage fourth order method. c_eff = 0.6
296: Level: beginner
298: References:
299: Ketcheson, Highly efficient strong stability preserving Runge-Kutta methods with low-storage implementations, SISC, 2008.
301: Gottlieb, Ketcheson, and Shu, High order strong stability preserving time discretizations, J Scientific Computing, 2009.
303: .seealso: TSCreate(), TS, TSSetType()
305: M*/
309: PetscErrorCode TSCreate_SSP(TS ts)
310: {
311: TS_SSP *ssp;
315: if (!TSSSPList) {
316: PetscFListAdd(&TSSSPList,TSSSPRKS2, "SSPStep_RK_2", (void(*)(void))SSPStep_RK_2);
317: PetscFListAdd(&TSSSPList,TSSSPRKS3, "SSPStep_RK_3", (void(*)(void))SSPStep_RK_3);
318: PetscFListAdd(&TSSSPList,TSSSPRK104, "SSPStep_RK_10_4",(void(*)(void))SSPStep_RK_10_4);
319: }
321: ts->ops->setup = TSSetUp_SSP;
322: ts->ops->step = TSStep_SSP;
323: ts->ops->reset = TSReset_SSP;
324: ts->ops->destroy = TSDestroy_SSP;
325: ts->ops->setfromoptions = TSSetFromOptions_SSP;
326: ts->ops->view = TSView_SSP;
328: PetscNewLog(ts,TS_SSP,&ssp);
329: ts->data = (void*)ssp;
331: TSSSPSetType(ts,TSSSPRKS2);
332: ssp->nstages = 5;
333: return(0);
334: }