Add a Runge-Kutta scheme
Current \(Q\)-generators based on Runge-Kutta schemes are implemented in
qmat.qcoeff.butcher.
Those are based on Butcher tables from classical schemes available in the literature,
and the selected approach is to define one class for one scheme.
Standard scheme
To add a new RK method, search first for its section in the butcher.py file, depending on its type
(explicit or implicit) and its order. Then add a new class at the bottom of this section following this template :
@registerRK
class NewRK(RK):
"""Some new RK method from ..."""
A = ... # TODO
b = ... # TODO
c = ... # TODO
@property
def order(self): return ... # TODO
Here the registerRK decorator interfaces the classical register decorator for QGenerator classes,
but also :
checks if the dimensions of
A,bandcare consistentregisters the generator in a specific category with all RK-type generators
💡 You can use either the built-in
listor Numpynd.arrayto add the class attributesA,bandc.
Tip : for large Butcher table, you can also use this approach (from the CashKarp class) :
A = np.zeros((6, 6))
A[1, 0] = 1.0 / 5.0
A[2, :2] = [3.0 / 40.0, 9.0 / 40.0]
A[3, :3] = [0.3, -0.9, 1.2]
A[4, :4] = [-11.0 / 54.0, 5.0 / 2.0, -70.0 / 27.0, 35.0 / 27.0]
A[5, :5] = [1631.0 / 55296.0, 175.0 / 512.0, 575.0 / 13824.0, 44275.0 / 110592.0, 253.0 / 4096.0]
Convergence testing
To test your scheme … you don’t have to do anything 🥳 : all RK schemes are automatically tested thanks to the registration mechanism, that checks (in particular) the convergence order of each scheme (global truncation error).
⚠️ Depending on the implemented RK scheme, convergence test may fail … in that case no worries 😉 you’ll just have to adapt your scheme to the test, as explained below …
All convergence tests are done on the following Dahlquist problem :
u0 = 1 # unitary initial solution
lam = 1j # purely imaginary lambda
tEnd = 2*np.pi # one time period
They use three numbers of time-steps for the convergence analysis, depending on the order of the method (see here …).
But this automatic time-step size selection may not be adapted for methods with high error constant that require finer time-steps
to actually see the theoretical order.
In that case, simply add a CONV_TEST_NSTEPS class attribute storing a list with higher numbers of time-steps in increasing order, high enough so the convergence test passes.
📜 See SDIRK2_2 implementation for an usage example of
CONV_TEST_NSTEPS…
Embedded scheme
Butcher tables with additional coefficients for embedded method can also be added to new or existing RK schemes.
For that, simply define a b2 class attribute :
@registerRK
class NewRK(RK):
"""Some new RK method from ..."""
## previous coefficients ...
b2 = ... # embedded coefficients
Per default, \(Q\)-generators define the order of the embedded method (using those additional coefficient)
as one order less than the method’s order (that is, returned by the order property).
If this is not the case, then you should override the orderEmbedded property from the base class :
@registerRK
class NewRK(RK):
# ...
@property
def orderEmbedded(self):
return ... # effective embedded order