use crate::linear_algebra::Vector;
use crate::scalar::Numeric;
pub struct Rk4;
impl Rk4 {
pub fn step<const N: usize, T, F>(f: &F, t: T, y: &Vector<N, T>, dt: T) -> Vector<N, T>
where
T: Numeric,
F: Fn(T, &Vector<N, T>) -> Vector<N, T>,
{
let half = T::HALF * dt;
let k1 = f(t, y);
let k2 = f(t + half, &(*y + k1.scale(half)));
let k3 = f(t + half, &(*y + k2.scale(half)));
let k4 = f(t + dt, &(*y + k3.scale(dt)));
let sixth = dt / T::from_f64(6.0);
*y + (k1 + k2.scale(T::TWO) + k3.scale(T::TWO) + k4).scale(sixth)
}
pub fn integrate<const N: usize, T, F, O>(
f: &F,
t0: T,
y0: &Vector<N, T>,
dt: T,
steps: usize,
mut observer: O,
) -> Vector<N, T>
where
T: Numeric,
F: Fn(T, &Vector<N, T>) -> Vector<N, T>,
O: FnMut(T, &Vector<N, T>),
{
let mut t = t0;
let mut y = *y0;
observer(t, &y);
for _ in 0..steps {
y = Self::step(f, t, &y, dt);
t += dt;
observer(t, &y);
}
y
}
}