Integrators

Integrators contain useful properties for writing a time-integration scheme. They are defined in a class hierarchy. MultiStageDriver owns a pointer to an integrator. The type of integrator depends on the template parameter. By default it is the base class, and you can assign child integrator you like, but you must cast the pointer at runtime to access useful features of the child classes. Alternatively if you inherit from MultiStageDriver and specialize to a specific child class, you can avoid doing the cast.

StagedIntegrator

The base class is the StagedIntegrator. It contains a timestep dt, a total number of integration steps, nstages, a total number of scratch buffers required, nbuffers, and lists of strings containing suggested names for the stages and buffers, buffer_name and stage_name. All other integrators inherit from this one.

LowStorageIntegrator

The LowStorageIntegrator contains integrators in the 2S form as described in Ketchson (2010). These integrators are of the classic Shu Osher form:

\[\begin{split}u^{(0)} &= u^n \\ u^{(i)} &= \sum_{k=0}^{i-1} (\alpha_{i,k} u^{(k)} + \Delta t \beta_{i, k} F(t^n+c_k \Delta t, u^{(k)}))\\ u^{n+1} &= u^{(m)}\end{split}\]

where superscripts in parentheses mean subcycles in a Runge-Kutta integration and \(F\) is the right-hand-side of ODE system. Note that the time dependence of \(F\) is explicitly included in the above formulation. The difference between these low-storage methods and the classic SSPK methods is that the low-storage methods typically have sparse \(\alpha\) and \(\beta\) matrices, which are replaced by diagonal terms, named \(\gamma_0\) and \(\gamma_1\) respectively.

These methods can be generalized to support more general methods with the introduction of an additional \(\delta\) term for first averaging the updated stage with previous stages. This form is also described in Section 3.2.3 of the Athena++ paper.

The full update then takes the form:

\[\begin{split}u^{(1)} &:= u^{(1)} + \delta_s u^{(0)} \\ u^{(0)} &:= \gamma_{s0} u^{(0)} + \gamma_{s1} u^{(1)} + \beta_{s,s-1} \Delta t F(t^n+c_s\Delta t, u^{(0)})\end{split}\]

where here \(u^{(0)}\) and \(u^{(1)}\) are the two storage buffers required to compute the update for a given Runge-Kutta stage \(s\). While the \(\delta\), \(\beta\), \(\gamma_0\) and \(\gamma_1\) associated with a particular scheme are published in the literature, \(c\) is not. Instead, \(c\) is computed following the procedure outlined in Ketchson (2010) for obtaining the Butcher coefficients from their low-storage counterparts. A Mathematica notebook to calculate \(c\) is provided here.

The LowStorageIntegrator contains arrays for delta, beta, gam0, gam1, and c. Available integration methods are:

  • RK1, which is simply forward Euler.

  • RK2, which is Heun’s method.

  • VL2, 2nd-order Van Leer predictor-corrector from Stone and Gardiner 2009. Requires donor-cell reconstruction for the predictor stage.

  • RK3, a strong stability preserving variant.

  • RK4, a strong stability preserving variant.

ButcherIntegrator

The ButcherIntegrator provides a classic Butcher Tableau with arrays \(a\) to compute the stages, \(c\) to compute the time offsets, and \(b\) to compute the final update for a time step. Available integration methods are:

  • RK1, simple forward Euler.

  • RK2, Heun’s method.

  • RK4, The classic 4th-order method.

  • RK10, A recent version with fewer stages than Fehlberg’s classic RK8(9), computed by Faegin and tabulated here.