TimeIntegrators
The time integration module implemented in Mantis is based on the framework developed by (Vos et al., 2011). This framework allows for an easy implementation of a variety of explicit, implicit, and implicit-explicit (IMEX) time stepping schemes, and is based on the concept of general linear methods (GLMs). See, for example, (Butcher, 2006), for more details. These methods are applicable to both ODEs and PDEs, so that both are available in Mantis.
GLMs: Notation and Theory
General linear methods can be characterised as follows (see (Butcher, 2006), (Vos et al., 2011)). Consider the initial value problem defined as the ODE
where
where
The above formulation can be cast into the following matrix form
which is often simplified (with some abuse of notation) to
Either way, the vectors
It is important to note that the in/output vectors can contain more than just the solution. The exact content depends on the specific method, but often includes previously computed stage derivatives. This is particularly important when creating and/or initialising new methods.
GLMs: Characterising a GLM
Any time integrator that fits in the above framework can thus be characterised by the four matrices Mantis,
| Matrix | Size |
|---|---|
num_stages x num_stages | |
num_steps x num_stages | |
num_stages x num_steps | |
num_steps x num_steps | |
num_stages x 1 |
GLMs: Extension to IMEX Schemes
The framework introduced by (Vos et al., 2011) extends the GLM idea to IMEX integrators. The ODE from the previous section is now split into
where
where
The matrix form is obtained in the same way as in the previous section.
IMEX GLMs are characterised in the same way as described in GLMs: Characterising a GLM. The only difference is that an IMEX GLM will have two
What are time integrators in Mantis?
The top-level type within the TimeIntegrators module is the AbstractTimeIntegrator{num_stages, num_steps} type.
Mantis.TimeIntegrators.AbstractTimeIntegrator Type
AbstractTimeIntegrator{num_stages, num_steps}Supertype for all time integrators.
Type parameters
num_stages: The number of stages for a multi-step scheme (such as the Runge-Kutta family). Since every scheme is at least a single-stage scheme,num_stages>= 1.num_steps: The number of steps for a multi-step scheme (such as the Adams-Bashforth family). Since every scheme is at least a single-step scheme,num_steps>= 1.
Note that you can always obtain the number of stages and steps using the following functions.
Mantis.TimeIntegrators.get_num_stages Function
get_num_stages(
::AbstractTimeIntegrator{num_stages, num_steps}
) where {num_stages, num_steps}Return the number of stages of the given AbstractTimeIntegrator.
Mantis.TimeIntegrators.get_num_steps Function
get_num_steps(
::AbstractTimeIntegrator{num_stages, num_steps}
) where {num_stages, num_steps}Return the number of steps of the given AbstractTimeIntegrator.
The AbstractTimeIntegrator{num_stages, num_steps} type has four concrete subtypes, each representing a specific class of time integrators.
Mantis.TimeIntegrators.Explicit Type
Explicit{num_stages, num_steps, NT, AA, AE, EE} <:
AbstractTimeIntegrator{num_stages, num_steps}Explicit time integration scheme.
Explicit time integrators are explicit in the ODE sense
Following (Vos et al., 2011), the explicit time integrators in this framework are considered explicit integrators when applied to ODEs. When applied to PDEs using a Galerkin method, one still has to solve a linear system. This can be referred to as an indirect explicit method in this case.
Fields
A,B,U,V,C: See the GLM characterisation for more details, including the matrix sizes. All matrices (and vector) are of typeSMatrix(orSVector, respectively) with the appropriate size andNTas eltype.time_levels::TimeLevels: Required information from previous steps. SeeTimeLevelsfor the details.order::Int: Order of the scheme.
Type parameters
num_stages,num_steps: See AbstractTimeIntegrator for the details.NT: Element type of theA,B,U,Vmatrices, andCvector.AA,AE,EE: Number of entries inA, (BandU), andV, respectively.
Mantis.TimeIntegrators.DiagonallyImplicit Type
DiagonallyImplicit{num_stages, num_steps, NT, AA, AE, EE} <:
AbstractTimeIntegrator{num_stages, num_steps}Diagonally implicit time integration scheme.
Fields
A,B,U,V,C: See the GLM characterisation for more details, including the matrix sizes. All matrices (and vector) are of typeSMatrix(orSVector, respectively) with the appropriate size andNTas eltype.time_levels::TimeLevels: Required information from previous steps. SeeTimeLevelsfor the details.order::Int: Order of the scheme.
Type parameters
num_stages,num_steps: See AbstractTimeIntegrator for the details.NT: Element type of theA,B,U,Vmatrices, andCvector.AA,AE,EE: Number of entries inA, (BandU), andV, respectively.
Mantis.TimeIntegrators.Implicit Type
Implicit{num_stages, num_steps, NT, AA, AE, EE} <:
AbstractTimeIntegrator{num_stages, num_steps}Implicit time integration scheme
Fields
A,B,U,V,C: See the GLM characterisation for more details, including the matrix sizes. All matrices (and vector) are of typeSMatrix(orSVector, respectively) with the appropriate size andNTas eltype.time_levels::TimeLevels: Required information from previous steps. SeeTimeLevelsfor the details.order::Int: Order of the scheme.
Type parameters
num_stages,num_steps: See AbstractTimeIntegrator for the details.NT: Element type of theA,B,U,Vmatrices, andCvector.AA,AE,EE: Number of entries inA, (BandU), andV, respectively.
Mantis.TimeIntegrators.IMEX Type
IMEX{num_stages, num_steps, NT, AA, AE, EE} <:
AbstractTimeIntegrator{num_stages, num_steps}Implicit-Explicit (IMEX) time integration scheme. Currently only supportes implicit parts which are diagonally implicit.
Fields
A_IM,A_EX,B_IMB_EX,U,V,C_IM,C_EX: See the GLM characterisation for more details, including the matrix sizes. All matrices (and vector) are of typeSMatrix(orSVector, respectively) with the appropriate size andNTas eltype.time_levels::TimeLevels: Required information from previous steps. SeeTimeLevelsfor the details.order::Int: Order of the scheme.
Type parameters
num_stages,num_steps: See AbstractTimeIntegrator for the details.NT: Element type of theA_IM,A_EX,B_IMB_EX,U, andVmatrices, andC_IM, andC_EXvectors.AA,AE,EE: Number of entries in (A_IMandA_EX), (B_IM,B_EXandU), andV, respectively.
The
Mantis.TimeIntegrators.check_implicit Function
check_implicit(A::AbstractMatrix)Check if the GLM matrix A belongs to an implicit or diagonally implicit scheme.
Returns
is_implicit::Bool: whether the scheme is fully implicit or notis_diagonally_implicit::Bool: whether the scheme is diagonally implicit. Note that both outputs are true for a fully implicit scheme, and that only this argument is true for a diagonally implicit scheme.
Since all schemes store the order of the scheme, you can always retrieve that information using the following getter.
Mantis.TimeIntegrators.get_order Function
get_order(scheme::AbstractTimeIntegrator)Return the order of the time integration scheme
sourceThe solution objects
The time integrators themselves do not store the solution. This is instead handled by the TimeIntegrationSolution-object.
Mantis.TimeIntegrators.TimeIntegrationSolution Type
TimeIntegrationSolution{T, S, NT, ST}Solution and current state of the time integration problem.
TimeIntegrationSolution does not store problem-specific information.
While a TimeIntegrationSolution stores most information, it does not store problem- specific information. See TimeIntegrationOperators for the problem-specific information.
Constructors
TimeIntegrationSolution( solution::Matrix{NT}, scheme::AbstractTimeIntegrator{num_stages, num_steps}, startup_scheme::Union{Nothing, AbstractTimeIntegrator}, remaining_startup_steps::Int, startup_solution::ST=nothing, ) where {NT, num_stages, num_steps, ST}: General constructor. Note that the eltype of the solution matrix will dictate the number type used in theTimeIntegrationSolution.
Fields
N::Int: Number varables in the system.solution::Matrix{NT}: Of size (N, num_steps).scheme::T: The time integration scheme.startup_scheme::S: The startup scheme, if provided. Will benothingif not provided. Defaults tonothing.remaining_startup_steps::Int: Remaining startup steps.solution_allocated::Matrix{NT}: Pre-allocated memory for calculations.F_alLocated::Matrix{NT}: Pre-allocated memory for calculations.G_alLocated::Matrix{NT}: Pre-allocated memory for calculations.startup_solution::ST: TheTimeIntegrationSolutionobject used for the startup procedure. This will contain information specific to the startup scheme and its current state. Will benothingif not provided. Defaults tonothing.stage_values::Vector{NT}: Pre-allocated memory for calculations.temp_var::Vector{NT}: Pre-allocated memory for calculations.
Type parameters
T: Type of the scheme.S: Type of the startup scheme.Nothingif no startup scheme is provided.NT: eltype of the solution and pre-allocated arrays.ST: Type of the startup solution object,Nothingif no startup solution is provided.
The TimeIntegrationSolution stores the information about the state of the time integration problem. You can inspect such objects through the following getters.
Mantis.TimeIntegrators.get_num_variables Function
get_num_variables(sol::TimeIntegrationSolution)Return the number of variables in the system.
sourceMantis.TimeIntegrators.get_solution Function
get_solution(sol::TimeIntegrationSolution{T, S, NT}) where {T, S, NT}Return the current solution values. This is a Matrix{NT} of size (N, num_steps), where N is the number of variables in the system.
Mantis.TimeIntegrators.get_scheme Function
get_scheme(sol::TimeIntegrationSolution)Return the time integration scheme used to obtain the solution.
sourceMantis.TimeIntegrators.get_startup_scheme Function
get_startup_scheme(sol::TimeIntegrationSolution)Return the startup scheme used to initialise the solution. Will be nothing if no startup scheme is present.
sourceMantis.TimeIntegrators.get_remaining_startup_steps Function
get_remaining_startup_steps(sol::TimeIntegrationSolution)Return the number of startup steps that still have to be performed. These are the steps that will be computed using the startup scheme instead of the main scheme.
sourceInternals: solution objects
We explain some internals related to the solution objects. However, this is considered an implementation detail.
Next to the information just mentioned, a TimeIntegrationSolution also stores the pre-allocated arrays and the solution object for the startup scheme (if present), which can be obtained with the following getters.
Mantis.TimeIntegrators.get_solution_allocated Function
get_solution_allocated(sol::TimeIntegrationSolution)Return the pre-allocated matrix for the solution. To obtain the solution itself, use get_solution.
Mantis.TimeIntegrators.get_F_allocated Function
get_F_allocated(sol::TimeIntegrationSolution)Return the pre-allocated matrix for the explicit stage derivatives.
sourceMantis.TimeIntegrators.get_G_allocated Function
get_G_allocated(sol::TimeIntegrationSolution)Return the pre-allocated matrix for the implicit stage derivatives
sourceMantis.TimeIntegrators.get_startup_solution Function
get_startup_solution(sol::TimeIntegrationSolution)Return the solution object corresponding to the startup scheme.
sourceMantis.TimeIntegrators.get_stage_allocated Function
get_stage_allocated(sol::TimeIntegrationSolution)Return the pre-allocated vector for the stage values.
sourceMantis.TimeIntegrators.get_temp_var Function
get_temp_var(sol::TimeIntegrationSolution)Return the pre-allocated vector for the temporary variable for the implicit schemes.
sourceDo not manually modify the pre-allocated arrays.
Modifying the pre-allocated arrays may lead to incorrect results or unexpected behaviour.
The above getters are internally used to access the pre-allocated arrays and to overwrite their values. You should not need these functions unless you are extending the integrate functionality to new types.
Adding problem-specific information
To use the TimeIntegrators-module, you have to specify which problem you want to solve. Information about the problem is collected in TimeIntegrationOperators. See GLMs: Notation and Theory and GLMs: Extension to IMEX Schemes for the notation.
Mantis.TimeIntegrators.TimeIntegrationOperators Type
TimeIntegrationOperators{EE, IS, IE}Defines the ODE-specific operators used in the time integration.
Makes a distiction between the explicit and implicit operators. EE, IS, and IE are the types of the explicit and implicit functions, which are Nothing if not defined. Note that at least EE or IS must be a function.
Constructors
define_explicit_ode(explicit_evaluate::Function): For fully explicit ODEs.define_diagonally_implicit_ode(implicit_solve::Function): For diagonally implicit ODEs.define_implicit_ode(implicit_solve::Function, implicit_evaluate::Function): For fully implicit ODEs.define_imex_ode(explicit_evaluate::Function, implicit_solve::Function): For IMEX ODEs.TimeIntegrationOperators( explicit_evaluate::Union{Nothing, Function}, implicit_solve::Union{Nothing, Function}, implicit_evaluate::Union{Nothing, Function}, ): Generic constructor.
Fields
explicitEvaluate!::EE: A function that evaluates the explicit part of the ODE, that is, the function that evaluates. See the manual section on TimeIntegrators for the terminology. This function must have the following inputs: (output, yn, t). It must also overwrite the output argument. The output argument will be a vector-like object of length N (the number of variables), as will yn. The argument t will be a number indicating the current time. implicitSolve!::IS: A function that solves the implicit part of the ODE, that is, the function that solves the equation, with . See the manual section on TimeIntegrators for the terminology. In case g is a linear operator, a direct solution method can be through the inverse operator , where is the identity function. This function must have the following inputs: (output, x, h, t). It must also overwrite the output argument. The output argument will be a matrix-like object of size (N, num_stages), as will yn. The arguments h will be either a number (for DiagonallyImplicit integrators) or a SMatrix of size (num_stages, num_stages) (for Implicit integrators) and t will be a number (for DiagonallyImplicit integrators) or an SVector of length num_stages (for Implicit integrators) indicating the current time(s). implicitEvaluate!::IE: A function that evaluates the implicit part of the ODE, that is, the function that evaluates. See the manual section on TimeIntegrators for the terminology. This function must have the following inputs: (output, yn, t). It must also overwrite the output argument. The output argument will be a vector-like object of length N (the number of variables), as will yn, and t will be a number indicating the current time.
Type parameters
EE:typeof(explicitEvaluate!)if initialised,Nothingotherwise.IS:typeof(implicitSolve!)if initialised,Nothingotherwise.IE:typeof(implicitEvaluate!)if initialised,Nothingotherwise.
There are various ways in which you can construct the above object, using the following functions.
The input functions are generic
This means that within these functions, you can choose how to treat your problem. For example, you can solve a non-linear system via the Newton-Rhapson method, as done in the Lorenz Attractor
Mantis.TimeIntegrators.define_explicit_ode Function
define_explicit_ode(explicit_evaluate::Function)Creates a TimeIntegrationOperators object for an explicit ODE.
Mantis.TimeIntegrators.define_diagonally_implicit_ode Function
define_diagonally_implicit_ode(
implicit_solve::Function, implicit_evaluate::Union{Nothing, Function}=nothing
)Creates a TimeIntegrationOperators object for a diagonally implicit ODE. The implicit_evaluate argument is needed when:
using a multi-step scheme (for the initialisation process).
using a diagonally implicit scheme that has at least one zero on the diagonal.
Mantis.TimeIntegrators.define_implicit_ode Function
define_implicit_ode(implicit_solve::Function, implicit_evaluate::Function)Creates a TimeIntegrationOperators object for an implicit ODE.
Mantis.TimeIntegrators.define_imex_ode Function
define_imex_ode(
explicit_evaluate::Function,
implicit_solve::Function,
implicit_evaluate::Union{Nothing, Function}=nothing
)Creates a TimeIntegrationOperators object for an IMEX ODE. The implicit_evaluate argument is needed when:
using a multi-step scheme (for the initialisation process).
using a diagonally implicit scheme that has at least one zero on the diagonal.
Time Integration
Now that the scheme, solution object, and the problem are all defined, we can perform the actual time integration.
Time Integrate
The integration happens by calling one of the following two methods.
Mantis.TimeIntegrators.time_integrate Function
time_integrate(
y_n::TimeIntegrationSolution,
ode::TimeIntegrationOperators,
t::Float64,
dt::Float64;
kwargs...,
)Perform a single time integration step using the given time integration scheme and ODE system operators. Creates a copy of the solution when called.
See also
Arguments
y_n::TimeIntegrationSolution: The current solution vector.ode::TimeIntegrationOperators: The ODE system operators.t::Float64: The current time.dt::Float64: The time step.kwargs...: Additional arguments passed to the ODE system.
Returns
TimeIntegrationSolution: The updated solution vector after one time step.
Mantis.TimeIntegrators.time_integrate! Function
time_integrate!(
y_n::TimeIntegrationSolution,
ode::TimeIntegrationOperators,
t::Float64,
dt::Float64;
kwargs...,
)Perform a single, in-place time integration step using the given time integration scheme and ODE system operators.
See also
Arguments
y_n::TimeIntegrationSolution: The current solution vector.ode::TimeIntegrationOperators: The ODE system operators.t::Float64: The current time.dt::Float64: The time step.kwargs...: Additional arguments passed to the ODE system.
Returns (in-place)
TimeIntegrationSolution: The updated solution vector after one time step.
Internals: time integration
We explain how the time integration is performed. However, this is considered an implementation detail.
The integration functions from Time Integrate end up calling the following internal integrator. This integrator function is specialised for different integrators and encodes how the time stepping is actually performed.
Mantis.TimeIntegrators._time_integrate! Function
_time_integrate!(
y_n::TimeIntegrationSolution,
scheme::Explicit{num_stages, num_steps},
ode::TimeIntegrationOperators,
t::Float64,
dt::Float64;
kwargs...,
) where {num_steps, num_stages}Perform a single time integration step using the given Explicit time integration scheme and ODE system operators. Implements algorithm 1 of (Vos et al., 2011) specifically for when the integrator is explicit.
Arguments
y_n::TimeIntegrationSolution: The current solution vector.scheme::Explicit{num_stages, num_steps}: The Explicit time integration scheme.ode::TimeIntegrationOperators: The ODE system operators.t::Float64: The current time.dt::Float64: The time step.kwargs...: Additional arguments passed to the ODE system.
Returns (in-place)
TimeIntegrationSolution{num_steps}: The updated solution vector after one time step.
_time_integrate!(
y_n::TimeIntegrationSolution,
scheme::DiagonallyImplicit{num_stages, num_steps},
ode::TimeIntegrationOperators,
t::Float64,
dt::Float64;
kwargs...,
) where {num_steps, num_stages}Perform a single time integration step using the given DiagonallyImplicit time integration scheme and ODE system operators. Implements algorithm 1 of (Vos et al., 2011) specifically for when the integrator in diagonally implicit.
Arguments
y_n::TimeIntegrationSolution{num_steps}: The current solution vector.scheme::DiagonallyImplicit{num_stages,num_steps}: The DiagonallyImplicit time integration scheme.ode::TimeIntegrationOperators: The ODE system operators.t::Float64: The current time.dt::Float64: The time step.kwargs...: Additional arguments passed to the ODE system.
Returns (in-place)
TimeIntegrationSolution{num_steps}: The updated solution vector after one time step.
_time_integrate!(
y_n::TimeIntegrationSolution,
scheme::Implicit{num_stages, num_steps},
ode::TimeIntegrationOperators,
t::Float64,
dt::Float64;
kwargs...,
) where {num_steps, num_stages}Perform a single time integration step using the given Implicit time integration scheme and ODE system operators.
Arguments
y_n::TimeIntegrationSolution{num_steps}: The current solution vector.scheme::Implicit{num_stages,num_steps}: The Implicit time integration scheme.ode::TimeIntegrationOperators: The ODE system operators.t::Float64: The current time.dt::Float64: The time step.kwargs...: Additional arguments passed to the ODE system.
Returns (in-place)
TimeIntegrationSolution{num_steps}: The updated solution vector after one time step.
_time_integrate!(
y_n::TimeIntegrationSolution,
scheme::IMEX{num_stages, num_steps},
ode::TimeIntegrationOperators,
t::Float64,
dt::Float64;
kwargs...,
) where {num_steps, num_stages}Perform a single time integration step using the given IMEX time integration scheme and ODE system operators. Implements algorithm 1 of (Vos et al., 2011) in full.
Arguments
y_n::TimeIntegrationSolution{num_steps}: The current solution vector.scheme::IMEX{num_stages,num_steps}: The IMEX time integration scheme.ode::TimeIntegrationOperators: The ODE system operators.t::Float64: The current time.dt::Float64: The time step.kwargs...: Additional arguments passed to the ODE system.
Returns (in-place)
TimeIntegrationSolution{num_steps}: The updated solution vector after one time step.
Initialisation
All integrators must be initialised. For multi-stage schemes, this is often just a matter of adding the initial condition. For multi-step schemes, this requires a startup scheme and more computation. To handle these different initialisation requirements, Mantis has a TimeLevels struct, as introduced in (Vos et al., 2011), to keep track of what needs to be initialised. Every time integrator has a TimeLevels struct to define what information is needed from previous steps.
Mantis.TimeIntegrators.TimeLevels Type
TimeLevelsThe length of the fields defines the structure of the input and output vectors for an integrator. The initialisation procedure uses this information to determine what needs to be initialised. Note that the vectors may be empty.
Constructors
TimeLevels( step_values::Vector{Int} step_derivatives_implicit::Vector{Int} step_derivatives_explicit::Vector{Int} ): Generic constructor.
Examples
Consider the CNAB2 scheme, which defines the input vector as
so, the TimeLevels input for this scheme is TimeLevels([0], [0], [0, 1]).
Consider the BDF3 scheme, which defines the input vector as
so, the TimeLevels input for this scheme is TimeLevels([0, 1, 2], Int[], Int[]).
Fields
step_values::Vector{Int}: The length of this vector determines how many previous solutions are needed. For multi-stage methods, this is often just[0]. For multi-step methods, this may include a longer history.step_derivatives_implicit::Vector{Int}: Required implicit step derivatives from previous steps. Note that this is. This is, for example, used in the Adams-Moulton schemes. step_derivatives_explicit::Vector{Int}: Required explicit step derivatives from previous steps. Note that this is. This is, for example, used in the Adams-Bashford schemes.
In general, the length of the arrays in the TimeLevels object is required. These lengths can be easily obtained using the following getters.
Mantis.TimeIntegrators.get_num_step_values Function
get_num_step_values(tl::TimeLevels)Return the number of step values that tl encodes.
Mantis.TimeIntegrators.get_num_implicit_derivatives Function
get_num_implicit_derivatives(tl::TimeLevels)Return the number of implicit derivatives that tl encodes.
Mantis.TimeIntegrators.get_num_explicit_derivatives Function
get_num_explicit_derivatives(tl::TimeLevels)Return the number of explicit derivatives that tl encodes.
The actual initialisation step(s) can be performed by calling the following function.
Mantis.TimeIntegrators.initialise_scheme Function
initialise_scheme(
y0::Matrix{T}, scheme::AbstractTimeIntegrator{num_stages, num_steps}
) where {T, num_stages, num_steps}Creates the TimeIntegrationSolution object with an initialised y0 vector.
Arguments
y0::Matrix{T}: The initial value of the solution matrix.scheme::AbstractTimeIntegrator{num_stages, num_steps}: The time integration scheme.
Returns
TimeIntegrationSolution{num_steps}: The initialised solution vector.
initialise_scheme(
y0::Vector{T}, scheme::AbstractTimeIntegrator{num_stages, num_steps}
) where {T, num_stages, num_steps}Initialise single-step schemes. The given input vector will be turned into a matrix of the appropriate size.
Arguments
y0::Vector{T}: The initial value of the solution vector.scheme::AbstractTimeIntegrator{num_stages, num_steps}: The time integration scheme.
initialise_scheme(
y0::Vector{T},
scheme::AbstractTimeIntegrator{num_stages_scheme, num_steps},
startup_scheme::AbstractTimeIntegrator{num_stages_startup, 1},
) where {T, num_stages_scheme, num_steps, num_stages_startup}Initialise multi-step schemes.
Arguments
y0::Vector{T}: The initial value of the solution vector.scheme::AbstractTimeIntegrator{num_stages_scheme, num_steps}: The time integration scheme.startup_scheme::AbstractTimeIntegrator{num_stages_startup, 1}: The startup scheme.
Returns
TimeIntegrationSolution{num_steps}: The initialised solution vector.
Other initialisation procedures
Mantis does not provide an exhaustive set of initialisation procedures. Some GLM schemes may require a different quantity to be initialised than what the initialise_scheme-method provides. If this is the case, you can always perform the initialisation manually. See Adding your own scheme for the details.
Pre-implemented schemes
Mantis provides a few pre-implemented schemes for convenience.
Pre-implemented explicit integrators in the Runge-Kutta family.
Mantis.TimeIntegrators.FORWARD_EULER Constant
FORWARD_EULERFrom Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.EXPLICIT_MIDPOINT Constant
EXPLICIT_MIDPOINTFrom Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.RALSTON2 Constant
RALSTON2From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.RALSTON3 Constant
RALSTON3From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.VDHW3 Constant
VDHW3Van der Houwen's/Wray's third-order method
From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.SSPRK3 Constant
SSPRK3Third-order Strong Stability Preserving Runge-Kutta.
From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.RK4_3_8 Constant
RK4_3_83/8-rule fourth-order method.
From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.RALSTON4 Constant
RALSTON4From Wikipedia's list of Runge-Kutta methods.
sourcePre-implemented (diagonally) implicit integrators in the Runge-Kutta family.
Mantis.TimeIntegrators.BACKWARD_EULER Constant
BACKWARD_EULERFrom Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.RADAU_IA_1 Constant
RADAU_IA_1From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.IMPLICIT_MIDPOINT Constant
IMPLICIT_MIDPOINTFrom Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.CRANK_NICOLSON Constant
CRANK_NICOLSONCrank-Nicolson method of order 2. From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.DIRK2 Constant
DIRK2Strongly S-stable, two-stage, DIRK scheme of order 2. See (Alexander, 1977) page 1012. For this scheme,
Mantis.TimeIntegrators.DIRK3 Constant
DIRK3Crouzeix's two-stage, 3rd order, A-stable DIRK scheme. See (Alexander, 1977) page 1008.
sourceMantis.TimeIntegrators.ESDIRK32 Constant
ESDIRK32Four-stage, 3rd order, stiffly accurate, A- and L-stable ESDIRK scheme. See (Kværnø, 2004) page 497.
sourceMantis.TimeIntegrators.RADAU_IA_3 Constant
RADAU_IA_3From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.DIRK4 Constant
DIRK4Crouzeix's three-stage, 4th order, A-stable DIRK scheme. See (Alexander, 1977) page 2.
sourceMantis.TimeIntegrators.GAUSS_LEGENDRE_4 Constant
GAUSS_LEGENDRE_4From Wikipedia's list of Runge-Kutta methods.
sourceMantis.TimeIntegrators.GAUSS_LEGENDRE_6 Constant
GAUSS_LEGENDRE_6From Wikipedia's list of Runge-Kutta methods.
sourcePre-implemented explicit multi-step integrators.
Pre-implemented (diagonally) implicit multi-step integrators.
Pre-implemented IMEX integrators.
Mantis.TimeIntegrators.BACKWARD_FORWARD_EULER Constant
BACKWARD_FORWARD_EULERSee equation A10 in (Vos et al., 2011).
sourceMantis.TimeIntegrators.MIDPOINT_IMEX Constant
MIDPOINT_IMEXIMEX combination of the implicit and explicit midpoint rules. See equation 4.14 in (Ern and Guermond, 2023).
sourceMantis.TimeIntegrators.IMEX331 Constant
IMEX3313-stage, 3rd order, A-stable IMEX scheme with optimal efficiency. See equation 4.18 in (Ern and Guermond, 2023).
sourceMantis.TimeIntegrators.CNAB2 Constant
CNAB2Second-order Crank-Nicolson/Adams-Bashforth linear multistep scheme. See equation A12 in (Vos et al., 2011).
sourceMantis.TimeIntegrators.SSSS2 Constant
SSSS2Stiffly stable splitting scheme of order 2. See (Karniadakis et al., 1991) table IV and (Vos et al., 2011) equation 59.
sourceYou can, of course, always initialise a new scheme yourself (see the concrete types in this section or Adding your own scheme).
Next to the pre-implemented schemes, Mantis also provides the following convenience function to take a Butcher-Tableau and turn it into a GLM-based time integrator.
Mantis.TimeIntegrators.butcher_tableau_to_glm Function
butcher_tableau_to_glm(
A::SMatrix{num_stages, num_stages, T},
B::SVector{num_stages, T},
C::SVector{num_stages, T},
order::Int,
) where {num_stages, T}Convert the given A, B, and C matrices from a Butcher Tableau into the GLM framework. Will automatically choose the correct type for the integrator.
Adding your own scheme
As an example of how to add your own time integrator, we look at how to implement an Almost Runge-Kutta (ARK) scheme. We use a specific scheme introduced in (Rattenbury, 2005).
This scheme requires a specialised initialisation, since it needs an estimate of the second derivative which is not accounted for in the available initialisations. As a result, this scheme is not part of Mantis.
Example: solving a simple ODE with an ARK scheme.
Consider the ODE:
which has exact solution
We can encode this in code as
using Mantis
import StaticArrays
const lambda = -4
const t_final = 1
y_0 = 1.0
function exact_sol(t)
return exp(lambda * t)
end
function test_ode_explicit_func!(output, yn, t)
for n in eachindex(output)
output[n] = lambda * yn[n]
end
return nothing
end
test_ode_explicit = TimeIntegrators.define_explicit_ode(test_ode_explicit_func!)Mantis.TimeIntegrators.TimeIntegrationOperators{typeof(Main.test_ode_explicit_func!), Nothing, Nothing}(Main.test_ode_explicit_func!, nothing, nothing)The ARK3 scheme that we use here has a known GLM-representation (see (Rattenbury, 2005), page 50). This method, however, requires its own initialisation, see (Rattenbury, 2005), pages 37-38. This initialisation, can be easily implemented as shown below. Note that the TimeLevels struct has more entries for the explicit forcing step. No other changes are required.
const ARK3 = TimeIntegrators.Explicit(
StaticArrays.SMatrix{3, 3}(0.0, 1/2, 0.0, 0.0, 0.0, 3/4, 0.0, 0.0, 0.0), # A
StaticArrays.SMatrix{3, 3}(0.0, 0.0, 3.0, 3/4, 0.0, -3.0, 0.0, 1.0, 2.0), # B
StaticArrays.SMatrix{3, 3}(1.0, 1.0, 1.0, 1/3, 1/6, 1/4, 1/18, 1/18, 0.0), # U
StaticArrays.SMatrix{3, 3}(1.0, 0.0, 0.0, 1/4, 0, -2.0, 0.0, 0.0, 0.0), # V
StaticArrays.SVector(1 / 3, 2 / 3, 1.0),
TimeIntegrators.TimeLevels(
[0], # y
Int[], # Δt G
[0, 1], # Δt F and Δt^2 F'
),
3,
)
dt = 0.1
yn = zeros(Float64, 1, 3)
yn[:, 1] .= [y_0]
yn[:, 2] .= lambda .* [y_0] .* dt
yn[:, 3] .= lambda^2 .* [y_0] .* dt^2
y_n = TimeIntegrators.TimeIntegrationSolution(yn, ARK3, nothing, 0)
for t in 0.0:dt:(t_final - dt)
TimeIntegrators.time_integrate!(y_n, test_ode_explicit, t, dt)
end