Files
differential-equations/src/integrator/mod.rs
2025-08-12 15:54:23 -04:00

61 lines
1.5 KiB
Rust

use nalgebra::SVector;
use super::ode::ODE;
pub mod dormand_prince;
// pub mod rosenbrock;
/// Integrator Trait
pub trait Integrator<const D: usize> {
const ORDER: usize;
const STAGES: usize;
const ADAPTIVE: bool;
const DENSE: bool;
/// Returns a new y value, then possibly an error value, and possibly a dense output
/// coefficient set
fn step<P>(
&self,
ode: &ODE<D, P>,
h: f64,
) -> (SVector<f64, D>, Option<f64>, Option<Vec<SVector<f64, D>>>);
fn interpolate(
&self,
t_start: f64,
t_end: f64,
dense: &[SVector<f64, D>],
t: f64,
) -> SVector<f64, D>;
}
#[cfg(test)]
mod tests {
use super::dormand_prince::*;
use super::*;
use approx::assert_relative_eq;
use nalgebra::Vector3;
#[test]
fn test_dopri() {
type Params = ();
fn derivative(_t: f64, y: Vector3<f64>, _p: &Params) -> Vector3<f64> {
y
}
let y0 = Vector3::new(1.0, 1.0, 1.0);
let mut ode = ODE::new(&derivative, 0.0, 4.0, y0, ());
let dp45 = DormandPrince45::new().a_tol(1e-12).r_tol(1e-4);
// Test that y'(t) = y(t) solves to y(t) = e^t for rkf54
// and also that the error seems reasonable
let step = 0.001;
while ode.t < ode.t_end {
let (new_y, err, _) = dp45.step(&ode, step);
ode.y = new_y;
ode.t += step;
assert_relative_eq!(ode.y[0], ode.t.exp(), max_relative = 0.01);
assert!(err.unwrap() < 1.0);
}
}
}