Module Arkode.MRIStep

module MRIStep: sig .. end

MRIStep Time-Stepping Module for two-rate initial value problems.

This module solves problems of the form $\dot{y} = f_s(t, y) + f_f(t, y)$, $y(t_0) = y_0$.

Its interface is structured as follows.

  1. Linear solvers
  2. Inner steppers
  3. Coupilng coefficients
  4. Solver initialization and use
  5. Modifying the solver
  6. Querying the solver
  7. Additional root finding functions

include Arkode.Common
type ('d, 'k) session = ('d, 'k, Arkode.mristep) session 

A session with the MRIStep time-stepping solver.

An example session with MRIStep (arkode_mri_skel.ml):

open Sundials
module MRIStep = Arkode.MRIStep
module ARKStep = Arkode.ARKStep

(* 1. Define right-hand-side functions. *)
let fslow _t y yd = yd.{0} <- y.{1};
                    yd.{1} <- 0.0
let ffast _t _y yd = yd.{0} <- 0.0;
                     yd.{1} <- -9.81

(* 2. Optionally define a root function. *)
let g _t y gout = gout.{0} <- 1.0 -. y.{0}

(* 3. Set vector of initial values.
      The length of this vector determines the problem size. *)
let y = RealArray.of_list [ 10.0; 0.0 ]
let ynv = Nvector_serial.wrap y

(* 4. Create an ARKStep solver for the fast (inner) integration *)
let sf = ARKStep.(init (explicit ffast) default_tolerances 0.0 ynv)

(* 5. Create and initialize a solver session. *)
let slowstep = 0.01
let s = MRIStep.(init (explicit fslow)
                      default_tolerances
                      InnerStepper.(from_arkstep sf)
                      ~roots:(1, g) ~slowstep 0.0 ynv);;

(* 6. Set optional inputs, e.g.,
      call [set_*] functions to change solver parameters. *)
MRIStep.set_stop_time s 10.0;;
MRIStep.set_all_root_directions s RootDirs.Increasing;;

(* 7. Advance the solution in time,
      by repeatedly calling [evolve_normal] or [evolve_one_step]. *)
let rec go (t, r) =
  Printf.printf "% .10e\t% .10e\t% .10e\n" t y.{0} y.{1};
  match r with
  | MRIStep.Success -> go (MRIStep.evolve_normal s (t +. 0.5) ynv)
  | MRIStep.RootsFound -> begin
        y.{1} <- -0.8 *. y.{1};
        MRIStep.reinit s t ynv;
        ARKStep.reinit sf t ynv;
        go (t, MRIStep.Success)
      end
  | MRIStep.StopTimeReached -> ();;

Printf.printf "time\ty\ty'\n";;
go (0.0, MRIStep.Success);;

(* 8. Get optional outputs,
      call the [get_*] functions to examine solver statistics. *)
let ns = MRIStep.get_num_steps s
      
type [> Nvector_serial.kind ] serial_session = (Nvector_serial.data, [> Nvector_serial.kind ] as 'a) session 

Alias for sessions based on serial nvectors.

Linear solvers

type ('data, 'kind) linear_solver 

Linear solvers used by MRIStep.

type [> Nvector_serial.kind ] serial_linear_solver = (Nvector_serial.data, [> Nvector_serial.kind ] as 'a)
linear_solver

Alias for linear solvers that are restricted to serial nvectors.

module Dls: sig .. end

Direct Linear Solvers operating on dense, banded, and sparse matrices.

module Spils: sig .. end

Scaled Preconditioned Iterative Linear Solvers.

val matrix_embedded_solver : (unit, 'data, 'kind, [> `MatE ]) Sundials.LinearSolver.t ->
('data, 'kind) linear_solver

Create an MRIStep-specific linear solver from a generic matrix embedded solver.

Inner steppers

module InnerStepper: sig .. end

Integrators for problems on the MRIStep fast time-scale.

Coupling coefficients

module Coupling: sig .. end

Coupling coefficients between fast and slow time scales.

Solver initialization and use

type ('d, 'k) problem 

The form of the initial value problem.

val implicit : ?nlsolver:('data, 'kind, ('data, 'kind) session, [ `Nvec ])
Sundials_NonlinearSolver.t ->
?nlsrhsfn:'data rhsfn ->
?lsolver:('data, 'kind) linear_solver ->
?linearity:linearity -> 'data rhsfn -> ('data, 'kind) problem

Implicit slow right-hand-side function only. The fields are as follows.

If an nlsolver is not specified, then the Newton module is used by default.

The alternative implicit right-hand-side function for nonlinear system function evaluations is only supported for Sundials >= 5.8.0.

val explicit : 'data rhsfn -> ('data, 'kind) problem

Explicit slow right-hand-side function only. The argument specifies the explicit portion of the slow right-hand-side problem.

val imex : ?nlsolver:('data, 'kind, ('data, 'kind) session, [ `Nvec ])
Sundials_NonlinearSolver.t ->
?nlsrhsfn:'data rhsfn ->
?lsolver:('data, 'kind) linear_solver ->
?linearity:linearity ->
fsi:'data rhsfn ->
fse:'data rhsfn -> unit -> ('data, 'kind) problem

Slow problem with both implicit and explicit parts. The arguments are as described under Arkode.MRIStep.implicit and Arkode.MRIStep.explicit.

val init : ?context:Sundials.Context.t ->
('data, 'kind) problem ->
('data, 'kind) tolerance ->
('data, 'kind) InnerStepper.t ->
?coupling:Coupling.t ->
slowstep:float ->
?roots:int * 'data rootsfn ->
float -> ('data, 'kind) Nvector.t -> ('data, 'kind) session

Creates and initializes a session with the solver. The call

init problem tol inner ~slowstep:h_s ~roots:(nroots, g) t0 y0

has as arguments:

This function does everything necessary to initialize a session, i.e., it makes the calls referenced below. The Arkode.MRIStep.evolve_normal and Arkode.MRIStep.evolve_one_step functions may be called directly.

If the inner (fast) stepper uses a fixed step size h_f that does not evenly divide the time interval between the stages of the outer (slow) method, then the actual value used for the fast steps will be slightly smaller than h_f to ensure that $(c_i^s - c_{i-1}^s)h_s/h_f$ is an integer value. Specifically, the fast step for the ith slow stage will be $h = \frac{(c_i^s - c_{i-1}^s)h_s} {\left\lceil (c_i^s - c_{i-1}^s)h_s/h_f \right\rceil}$ .

If fixed step sizes and a stop time are used, then the fixed step size will be used for all steps except the final step, which may be shorter. To resume use of the previous fixed step size, another call to Arkode.MRIStep.set_fixed_step is required before calling either Arkode.MRIStep.evolve_normal or Arkode.MRIStep.evolve_one_step.

Neither Root finding nor non-identity mass matrices are supported in the inner session.

For Sundials < 5.4.0, the tolerance must be Arkode.Common.default_tolerances and the coupling, nlsolver, lsolver, and linearity arguments are not available.

By default, the session is created using the context returned by Sundials.Context.default, but this can be overridden by passing an optional context argument.

val evolve_normal : ('d, 'k) session ->
float -> ('d, 'k) Nvector.t -> float * solver_result

Integrates an ODE system over an interval. The call tret, r = evolve_normal s tout yout has as arguments

It returns tret, the time reached by the solver, which will be equal to tout if no errors occur, and, r, a Arkode.Common.solver_result.

val evolve_one_step : ('d, 'k) session ->
float -> ('d, 'k) Nvector.t -> float * solver_result

Like Arkode.MRIStep.evolve_normal but returns after one internal solver step.

val get_dky : ('d, 'k) session -> ('d, 'k) Nvector.t -> float -> int -> unit

Returns the interpolated solution or derivatives. get_dky s dky t k computes the kth derivative of the function at time t, i.e., $\frac{d^\mathtt{k}}{\mathit{dt}^\mathtt{k}}y(\mathtt{t})$, and stores it in dky. The arguments must satisfy $t_n - h_n \leq \mathtt{t} \leq t_n$—where $t_n$ denotes Arkode.MRIStep.get_current_time and $h_n$ denotes Arkode.MRIStep.get_last_step,— and $0 \leq \mathtt{k} \leq 3$.

This function may only be called after a successful return from either Arkode.MRIStep.evolve_normal or Arkode.MRIStep.evolve_one_step.

val reinit : ('d, 'k) session ->
?problem:('d, 'k) problem ->
?roots:int * 'd rootsfn -> float -> ('d, 'k) Nvector.t -> unit

Reinitializes the solver with new parameters and state values. The values of the independent variable, i.e., the simulation time, and the state variables must be given. If given, problem specifies new callback functions and solvers, and roots specifies a new root finding function. The new problem must have the same size as the previous one. The number of Runge Kutta stages for both the slow and fast methods in the new problem must not be larger than that of the previous one.

val reset : ('d, 'k) session -> float -> ('d, 'k) Nvector.t

Resets the state to the given independent variable value and dependent variable vector. All previously set options, internal counter values, and step-size/error histories are retained.

val resize : ('d, 'k) session ->
?resize_nvec:'d resize_fn -> ('d, 'k) Nvector.t -> float -> unit

Change the number of equations and unknowns between integrator steps. The call resize s ~resize_nvec:rfn ynew t0 has as arguments:

Modifying the solver (optional input functions)

val set_defaults : ('d, 'k) session -> unit

Resets all optional input parameters to their default values. Neither the problem-defining functions nor the root-finding functions are changed.

val set_interpolant_type : ('d, 'k) session -> interpolant_type -> unit

Specifies the interpolation module used for output value interpolation and implicit method predictors.

val set_interpolant_degree : ('d, 'k) session -> int -> unit

Specifies the degree of the polynomial interpolant used for output values and implicit method predictors.

val set_diagnostics : ?logfile:Sundials.Logfile.t -> ('d, 'k) session -> unit

Write step adaptivity and solver diagnostics on the standard output (or given file).

val clear_diagnostics : ('d, 'k) session -> unit

Do not write step adaptivity or solver diagnostics of a file.

val set_error_file : ('d, 'k) session -> Sundials.Logfile.t -> unit

Configure the default error handler to write messages to a file. By default it writes to Logfile.stderr.

val set_err_handler_fn : ('d, 'k) session ->
(Sundials.Util.error_details -> unit) -> unit

Specifies a custom function for handling error messages. The handler must not fail: any exceptions are trapped and discarded.

val clear_err_handler_fn : ('d, 'k) session -> unit

Restores the default error handling function.

val set_fixed_step : ('d, 'k) session -> float -> unit

Disables time step adaptivity and fix the step size for all internal steps. See the notes under Arkode.MRIStep.init.

val set_max_hnil_warns : ('d, 'k) session -> int -> unit

Specifies the maximum number of messages warning that t + h = t on the next internal step.

val set_max_num_steps : ('d, 'k) session -> int -> unit

Specifies the maximum number of steps taken in attempting to reach a given output time.

val set_stop_time : ('d, 'k) session -> float -> unit

Limits the value of the independent variable t when solving. By default no stop time is imposed.

type 'd pre_inner_fn = float -> 'd array -> unit 

A function to be called before each inner integration. This function may be used, for instance, to perform communications or memory transfers of forcing data supplied by the outer integrator to the inner integrator.

The first argument is the current value of the independent variable. The second is an array of outer forcing vectors.

The array and its contents should not be accessed after the function has returned
.

Within the function, raising a Sundials.RecoverableFailure exception indicates a recoverable error. Any other exception is treated as an unrecoverable error.

val set_pre_inner_fn : ('d, 'k) session -> 'd pre_inner_fn -> unit

Set the function called before each inner integration.

val clear_pre_inner_fn : ('d, 'k) session -> unit

Clear the function called before each inner integration.

type 'd post_inner_fn = float -> 'd -> unit 

A function to be called after each inner integration. This function may be used, for instance, to perform communications or memory transfers of state data supplied by the inner integrator to the outer integrator.

The first argument is the current value of the independent variable. The second is the current value of the dependent variable vector.

The dependent variable vector should not be accessed after the function has returned.

Within the function, raising a Sundials.RecoverableFailure exception indicates a recoverable error. Any other exception is treated as an unrecoverable error.

val set_post_inner_fn : ('d, 'k) session -> 'd post_inner_fn -> unit

Set the function called after each inner integration.

val clear_post_inner_fn : ('d, 'k) session -> unit

Clear the function called after each inner integration.

Optional inputs for time step adaptivity

val set_postprocess_step_fn : ('d, 'k) session -> 'd postprocess_step_fn -> unit

Set a post processing step function.

val clear_postprocess_step_fn : ('d, 'k) session -> unit

Clear the post processing step function.

Optional inputs for implicit stage solves

type 'd stage_predict_fn = float -> 'd -> unit 

A function to be called after the predictor algorithm to update the predictor.

The first argument is the current value of the independent variable. The second is the predicated stage solution which may be updated directly.

The array and its contents should not be accessed after the function has returned
.

All exceptions are treated as unrecoverable errors.

val set_stage_predict_fn : ('d, 'k) session -> 'd stage_predict_fn -> unit

Set the function called after the predictor algorithm and before the calculation of an implicit stage solution.

If a stage prediction function is set and the current predictor method, see Arkode.MRIStep.set_predictor_method, is MinimumCorrectionPredictor, then the TrivialPredictor will be used instead.

val clear_stage_predict_fn : ('d, 'k) session -> unit

Clear the function called after the predictor algorithm.

val set_nonlin_conv_coef : ('d, 'k) session -> float -> unit

Specifies the safety factor used in the nonlinear convergence test.

val set_nonlin_crdown : ('d, 'k) session -> float -> unit

Specifies the constant used in estimating the nonlinear solver convergence rate.

val set_nonlin_rdiv : ('d, 'k) session -> float -> unit

Specifies the nonlinear correction threshold beyond which the iteration will be declared divergent.

val set_delta_gamma_max : ('d, 'k) session -> float -> unit

Specifies a scaled step size ratio tolerance beyond which the linear solver setup routine will be signalled.

val set_lsetup_frequency : ('d, 'k) session -> int -> unit

Specifies the frequency of calls to the linear solver setup routine. Positive values specify the number of time steps between setup calls, negative values force recomputation at each Newton step, and zero values reset to the default (20).

val set_linear : ('d, 'k) session -> bool -> unit

Specifies that the implicit portion of the problem is linear. The flag indicates whether the Jacobian of $f_I(t,y)$, or, when using an iterative linear solver, the preconditioner is time-dependent (true) or not (false).

val set_nonlinear : ('d, 'k) session -> unit

Specifies that the implicit portion of the problem is nonlinear.

val set_predictor_method : ('d, 'k) session -> predictor_method -> unit

Specifies the method for predicting implicit solutions.

val set_max_nonlin_iters : ('d, 'k) session -> int -> unit

Specifies the maximum number of nonlinear solver iterations permitted per RK stage at each step.

Querying the solver (optional output functions)

val get_work_space : ('d, 'k) session -> int * int

Returns the real and integer workspace sizes.

val get_num_steps : ('d, 'k) session -> int

Returns the cumulative number of internal steps taken by the solver.

val get_last_step : ('d, 'k) session -> float

Returns the integration step size taken on the last successful internal step.

val get_num_rhs_evals : ('d, 'k) session -> int * int

The number of calls to the (outer) right-hand-side functions. Returns a pair nfse, nfsi = get_num_rhs_evals s, where nfse is the number of calls to the explicit part and nfsi is the number of calls to the implicit part.

val get_current_time : ('d, 'k) session -> float

Returns the the current internal time reached by the solver.

val get_current_state : ('d, 'k) session -> 'd

Returns the current state vector. This vector provides direct access to the data within the integrator.

val get_current_coupling : ('d, 'k) session -> Coupling.t

Returns the coupling table currently in use by the solver.

val write_coupling : ?logfile:Sundials.Logfile.t -> ('d, 'k) session -> unit

Output the current coupling table on the standard output (or given file).

val get_nonlin_system_data : ('d, 'k) session -> 'd nonlin_system_data

Gives direct access to the internal data required to construct the current nonlinear implicit system within a nonlinear solver. This function should be called inside the nonlinear system function. If the nonlinear solver uses the lsetup or lsolve functions, then the nonlinear solver system function must fill the zi and fi vectors with, respectively, the current state and corresponding evaluation of the right-hand-side function: $z_i = z_{\mathit{pred}} + z_{\mathit{cor}}$ and $F_i = f^S(t^S_{n,i}, z_i)$ where $z_{\mathit{cor}}$ is the first argument of the nonlinear solver system function. Within a custom linear solver, then the vectors zi and fi are only current after an evaluation of the nonlinear system function.

val compute_state : ('d, 'k) session ->
('d, 'k) Nvector.t -> ('d, 'k) Nvector.t -> unit

Computes the current stage state vector using the stored prediction and the supplied correction from the nonlinear solver. The call compute_state s zcor z computes $z_i(t) = z_{\mathit{pred}} + z_{\mathit{cor}}$ .

val get_current_gamma : ('d, 'k) session -> float

Returns the current value of $\gamma$ . This scalar appears in the internal Newton equation, either $A = I - \gamma J$ or $A = M - \gamma J$ .

val get_tol_scale_factor : ('d, 'k) session -> float

Returns a suggested factor by which the user's tolerances should be scaled when too much accuracy has been requested for some internal step.

val get_err_weights : ('d, 'k) session -> ('d, 'k) Nvector.t -> unit

Returns the solution error weights at the current time.

Implicit solver optional output functions

val get_num_lin_solv_setups : ('d, 'k) session -> int

Returns the number of calls made to the linear solver's setup function.

val get_num_nonlin_solv_iters : ('d, 'k) session -> int

Returns the cumulative number of nonlinear (functional or Newton) iterations.

val get_num_nonlin_solv_conv_fails : ('d, 'k) session -> int

Returns the cumulative number of nonlinear convergence failures.

val get_nonlin_solv_stats : ('d, 'k) session -> int * int

Returns both the numbers of nonlinear iterations performed nniters and nonlinear convergence failures nncfails.

val write_session : ?logfile:Sundials.Logfile.t -> ('d, 'k) session -> unit

Summarize the session on the standard output (or given file).

Additional root-finding functions

val set_root_direction : ('d, 'k) session -> Sundials.RootDirs.d array -> unit

set_root_direction s dir specifies the direction of zero-crossings to be located and returned. dir may contain one entry for each root function.

val set_all_root_directions : ('d, 'k) session -> Sundials.RootDirs.d -> unit

Like Arkode.MRIStep.set_root_direction but specifies a single direction for all root functions.

val set_no_inactive_root_warn : ('d, 'k) session -> unit

Disables issuing a warning if some root function appears to be identically zero at the beginning of the integration.

val get_num_roots : ('d, 'k) session -> int

Returns the number of root functions.

val get_root_info : ('d, 'k) session -> Sundials.Roots.t -> unit

Fills an array showing which functions were found to have a root.

val get_num_g_evals : ('d, 'k) session -> int

Returns the cumulative number of calls made to the user-supplied root function g.

val write_parameters : ?logfile:Sundials.Logfile.t -> ('d, 'k) session -> unit

Outputs all the solver parameters on the standard output (or given file).