# ODE-solvers [![Crates.io](https://img.shields.io/crates/v/ode_solvers.svg)](https://crates.io/crates/ode_solvers/) [![Docs](https://docs.rs/ode_solvers/badge.svg)](https://docs.rs/ode_solvers) [![Crates.io](https://img.shields.io/crates/l/ode_solvers.svg)](https://opensource.org/licenses/BSD-3-Clause) [Homepage](https://srenevey.github.io/ode-solvers/) [Documentation](https://docs.rs/ode_solvers) Numerical methods to solve ordinary differential equations (ODEs) in Rust. ## Installation To start using the crate in a project, the following dependency must be added in the project's Cargo.toml file: ```rust [dependencies] ode_solvers = "0.5.0" ``` Then, in the main file, add ```rust use ode_solvers::*; ``` ## Type alias definition The numerical integration methods implemented in the crate support multi-dimensional systems. In order to define the dimension of the system, declare a type alias for the state vector. For instance ```rust type State = Vector3; ``` The state representation of the system is based on the SVector<T,D> structure defined in the [nalgebra](https://nalgebra.org/) crate. For convenience, ode-solvers re-exports six types to work with systems of dimension 1 to 6: Vector1<T>,..., Vector6<T>. For higher dimensions, the user should import the nalgebra crate and define a SVector<T,D> where the second type parameter of SVector is a dimension. For instance, for a 9-dimensional system, one would have: ```rust type State = SVector; ``` Alternativly, one can also use the DVector<T> structure from the [nalgebra](https://nalgebra.org/) crate as the state representation. When using a DVector<T>, the number of rows in the DVector<T> defines the dimension of the system. ```rust type State = DVector; ``` ## System definition The system of first order ODEs must be defined in the `system` method of the `System` trait. Typically, this trait is defined for a structure containing some parameters of the model. The signature of the `System` trait is: ```rust pub trait System { fn system(&self, x: T, y: &V, dy: &mut V); fn solout(&self, _x: T, _y: &V, _dy: &V) -> bool { false } } ``` where `system` must contain the ODEs: the second argument is the independent variable (usually time), the third one is a vector containing the dependent variable(s), and the fourth one contains the derivative(s) of y with respect to x. The method `solout` is called after each successful integration step and stops the integration whenever it is evaluated as true. The implementation of that method is optional. See the examples for implementation details. ## Method selection The following explicit Runge-Kutta methods are implemented in the current version of the crate: | Method | Name | Order | Error estimate order | Dense output order | | -------------- | ------ | ----- | -------------------- | ------------------ | | Runge-Kutta 4 | Rk4 | 4 | N/A | N/A | | Dormand-Prince | Dopri5 | 5 | 4 | 4 | | Dormand-Prince | Dop853 | 8 | (5, 3) | 7 | These methods are defined in the modules rk4, dopri5, and dop853. The first step is to bring the desired module into scope: ```rust use ode_solvers::dopri5::*; ``` Then, a structure is created using the `new` or the `from_param` method of the corresponding struct. Refer to the [API documentation](https://docs.rs/ode_solvers) for a description of the input arguments. ```rust let mut stepper = Dopri5::new(system, x0, x_end, dx, y0, rtol, atol); ``` The system is integrated using ```rust let res = stepper.integrate(); ``` and the results are retrieved with ```rust let x_out = stepper.x_out(); let y_out = stepper.y_out(); ``` See the [homepage](https://srenevey.github.io/ode-solvers/) for more details.