pub use crate::integrators::integrator_trait::Integrator;
pub use crate::ode_state::ode_state_trait::OdeState;
pub struct Euler;
impl<T: OdeState> Integrator<T> for Euler {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
y.add_assign(&f(t, y).mul(h));
}
}
pub struct RK2;
impl<T: OdeState> Integrator<T> for RK2 {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (h / 2.0), &y.add(&k1.mul(h / 2.0)));
y.add_assign(&k2.mul(h));
}
}
pub struct RK2Heun;
impl<T: OdeState> Integrator<T> for RK2Heun {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + h, &y.add(&k1.mul(h)));
y.add_assign(&k1.add(&k2).mul(h / 2.0));
}
}
pub struct RK2Ralston;
impl<T: OdeState> Integrator<T> for RK2Ralston {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (2.0 * h / 3.0), &y.add(&k1.mul(2.0 * h / 3.0)));
y.add_assign(&k1.add(&k2.mul(3.0)).mul(h / 4.0));
}
}
pub struct RK3;
impl<T: OdeState> Integrator<T> for RK3 {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (h / 2.0), &y.add(&k1.mul(h / 2.0)));
let k3 = f(t + (h / 2.0), &y.sub(&k1.mul(h)).add(&k2.mul(2.0 * h)));
y.add_assign(&(k1.add(&k2.mul(4.0)).add(&k3)).mul(h / 6.0));
}
}
pub struct RK3Heun;
impl<T: OdeState> Integrator<T> for RK3Heun {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (h / 3.0), &y.add(&k1.mul(h / 3.0)));
let k3 = f(t + (2.0 * h / 3.0), &y.add(&k2.mul(2.0 * h / 3.0)));
y.add_assign(&k1.add(&k3.mul(3.0)).mul(h / 4.0));
}
}
pub struct RK3Ralston;
impl<T: OdeState> Integrator<T> for RK3Ralston {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (h / 2.0), &y.add(&k1.mul(h / 2.0)));
let k3 = f(t + (3.0 * h / 4.0), &y.add(&k2.mul(3.0 * h / 4.0)));
y.add_assign(&(k1.mul(2.0).add(&k2.mul(3.0)).add(&k3.mul(4.0))).mul(h / 9.0));
}
}
pub struct SSPRK3;
impl<T: OdeState> Integrator<T> for SSPRK3 {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + h, &y.add(&k1.mul(h)));
let k3 = f(
t + (h / 2.0),
&y.add(&k1.mul(h / 4.0).add(&k2.mul(h / 4.0))),
);
y.add_assign(&(k1.add(&k2).add(&k3.mul(4.0))).mul(h / 6.0));
}
}
pub struct RK4;
impl<T: OdeState> Integrator<T> for RK4 {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (h / 2.0), &y.add(&k1.mul(h / 2.0)));
let k3 = f(t + (h / 2.0), &y.add(&k2.mul(h / 2.0)));
let k4 = f(t + h, &y.add(&k3.mul(h)));
y.add_assign(&(k1.add(&k2.mul(2.0)).add(&k3.mul(2.0)).add(&k4)).mul(h / 6.0));
}
}
pub struct RK4Ralston;
impl<T: OdeState> Integrator<T> for RK4Ralston {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + 0.4 * h, &y.add(&k1.mul(0.4 * h)));
let k3 = f(
t + 0.45573725 * h,
&y.add(&k1.mul(0.29697761 * h).add(&k2.mul(0.15875964 * h))),
);
let k4 = f(
t + h,
&y.add(&k1.mul(0.21810040 * h))
.sub(&k2.mul(3.05096516 * h))
.add(&k3.mul(3.83286476 * h)),
);
y.add_assign(
&(k1.mul(0.17476028)
.sub(&k2.mul(0.55148066))
.add(&k3.mul(1.20553560))
.add(&k4.mul(0.17118478)))
.mul(h),
);
}
}
pub struct RK438;
impl<T: OdeState> Integrator<T> for RK438 {
fn propagate(f: &impl Fn(f64, &T) -> T, t: f64, h: f64, y: &mut T) {
let k1 = f(t, y);
let k2 = f(t + (h / 3.0), &y.add(&k1.mul(h / 3.0)));
let k3 = f(
t + (2.0 * h / 3.0),
&y.sub(&k1.mul(h / 3.0)).add(&k2.mul(h)),
);
let k4 = f(t + h, &y.add(&k1.mul(h)).sub(&k2.mul(h)).add(&k3.mul(h)));
y.add_assign(&(k1.add(&k2.mul(3.0)).add(&k3.mul(3.0)).add(&k4)).mul(h / 8.0));
}
}
#[cfg(test)]
mod tests {
use super::*;
fn rkx_test_helper<T: Integrator<f64>>(y_exp: f64) {
let f = |t: f64, x: &f64| -2.0 * x + t.powi(2);
let mut y = 1.0;
let t = 0.0;
let h = 0.1;
T::propagate(&f, t, h, &mut y);
assert_eq!(y, y_exp);
}
#[test]
fn test_euler() {
rkx_test_helper::<Euler>(0.8);
}
#[test]
fn test_rk2() {
rkx_test_helper::<RK2>(0.8202499999999999);
}
#[test]
fn test_rk2_heun() {
rkx_test_helper::<RK2Heun>(0.8205);
}
#[test]
fn test_rk2_ralston() {
rkx_test_helper::<RK2Ralston>(0.8203333333333334);
}
#[test]
fn test_rk3() {
rkx_test_helper::<RK3>(0.8188583333333334);
}
#[test]
fn test_rk3_heun() {
rkx_test_helper::<RK3Heun>(0.8189888888888889);
}
#[test]
fn test_rk3_ralston() {
rkx_test_helper::<RK3Ralston>(0.8189833333333334);
}
#[test]
fn test_rk3_ssprk3() {
rkx_test_helper::<SSPRK3>(0.8189666666666666);
}
#[test]
fn test_rk4() {
rkx_test_helper::<RK4>(0.8190508333333333);
}
#[test]
fn test_rk4_ralston() {
rkx_test_helper::<RK4Ralston>(0.8190506665171147);
}
#[test]
fn test_rk4_38() {
rkx_test_helper::<RK438>(0.8190505555555555);
}
}