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: }