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