conspire/math/integrate/dormand_prince/
mod.rs#[cfg(test)]
mod test;
use super::{
super::{
interpolate::InterpolateSolution, Tensor, TensorArray, TensorRank0, TensorVec, Vector,
},
Explicit, IntegrationError,
};
use crate::{ABS_TOL, REL_TOL};
use std::ops::{Mul, Sub};
const C_44_45: TensorRank0 = 44.0 / 45.0;
const C_56_15: TensorRank0 = 56.0 / 15.0;
const C_32_9: TensorRank0 = 32.0 / 9.0;
const C_8_9: TensorRank0 = 8.0 / 9.0;
const C_19372_6561: TensorRank0 = 19372.0 / 6561.0;
const C_25360_2187: TensorRank0 = 25360.0 / 2187.0;
const C_64448_6561: TensorRank0 = 64448.0 / 6561.0;
const C_212_729: TensorRank0 = 212.0 / 729.0;
const C_9017_3168: TensorRank0 = 9017.0 / 3168.0;
const C_355_33: TensorRank0 = 355.0 / 33.0;
const C_46732_5247: TensorRank0 = 46732.0 / 5247.0;
const C_49_176: TensorRank0 = 49.0 / 176.0;
const C_5103_18656: TensorRank0 = 5103.0 / 18656.0;
const C_35_384: TensorRank0 = 35.0 / 384.0;
const C_500_1113: TensorRank0 = 500.0 / 1113.0;
const C_125_192: TensorRank0 = 125.0 / 192.0;
const C_2187_6784: TensorRank0 = 2187.0 / 6784.0;
const C_11_84: TensorRank0 = 11.0 / 84.0;
const C_71_57600: TensorRank0 = 71.0 / 57600.0;
const C_71_16695: TensorRank0 = 71.0 / 16695.0;
const C_71_1920: TensorRank0 = 71.0 / 1920.0;
const C_17253_339200: TensorRank0 = 17253.0 / 339200.0;
const C_22_525: TensorRank0 = 22.0 / 525.0;
#[derive(Debug)]
pub struct DormandPrince {
pub abs_tol: TensorRank0,
pub rel_tol: TensorRank0,
pub dt_beta: TensorRank0,
pub dt_expn: TensorRank0,
pub dt_init: TensorRank0,
}
impl Default for DormandPrince {
fn default() -> Self {
Self {
abs_tol: ABS_TOL,
rel_tol: REL_TOL,
dt_beta: 0.9,
dt_expn: 5.0,
dt_init: 0.1,
}
}
}
impl<Y, U> Explicit<Y, U> for DormandPrince
where
Self: InterpolateSolution<Y, U>,
Y: Tensor + TensorArray,
for<'a> &'a Y: Mul<TensorRank0, Output = Y> + Sub<&'a Y, Output = Y>,
U: TensorVec<Item = Y>,
{
fn integrate(
&self,
function: impl Fn(&TensorRank0, &Y) -> Y,
time: &[TensorRank0],
initial_condition: Y,
) -> Result<(Vector, U), IntegrationError> {
if time.len() < 2 {
return Err(IntegrationError::LengthTimeLessThanTwo);
} else if time[0] >= time[time.len() - 1] {
return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
}
let mut t = time[0];
let mut dt = self.dt_init * time[time.len() - 1];
let mut e;
let mut k_1 = function(&t, &initial_condition);
let mut k_2;
let mut k_3;
let mut k_4;
let mut k_5;
let mut k_6;
let mut k_7;
let mut t_sol = Vector::zero(0);
t_sol.push(time[0]);
let mut y = initial_condition.clone();
let mut y_sol = U::zero(0);
y_sol.push(initial_condition.clone());
let mut y_trial;
while t < time[time.len() - 1] {
k_2 = function(&(t + 0.2 * dt), &(&k_1 * (0.2 * dt) + &y));
k_3 = function(
&(t + 0.3 * dt),
&(&k_1 * (0.075 * dt) + &k_2 * (0.225 * dt) + &y),
);
k_4 = function(
&(t + 0.8 * dt),
&(&k_1 * (C_44_45 * dt) - &k_2 * (C_56_15 * dt) + &k_3 * (C_32_9 * dt) + &y),
);
k_5 = function(
&(t + C_8_9 * dt),
&(&k_1 * (C_19372_6561 * dt) - &k_2 * (C_25360_2187 * dt)
+ &k_3 * (C_64448_6561 * dt)
- &k_4 * (C_212_729 * dt)
+ &y),
);
k_6 = function(
&(t + dt),
&(&k_1 * (C_9017_3168 * dt) - &k_2 * (C_355_33 * dt)
+ &k_3 * (C_46732_5247 * dt)
+ &k_4 * (C_49_176 * dt)
- &k_5 * (C_5103_18656 * dt)
+ &y),
);
y_trial = (&k_1 * C_35_384 + &k_3 * C_500_1113 + &k_4 * C_125_192 - &k_5 * C_2187_6784
+ &k_6 * C_11_84)
* dt
+ &y;
k_7 = function(&(t + dt), &y_trial);
e = ((&k_1 * C_71_57600 - k_3 * C_71_16695 + k_4 * C_71_1920 - k_5 * C_17253_339200
+ k_6 * C_22_525
- &k_7 * 0.025)
* dt)
.norm();
if e < self.abs_tol || e / y_trial.norm() < self.rel_tol {
k_1 = k_7;
t += dt;
y = y_trial;
t_sol.push(t);
y_sol.push(y.clone());
}
dt *= self.dt_beta * (self.abs_tol / e).powf(1.0 / self.dt_expn);
}
if time.len() > 2 {
let t_int = Vector::new(time);
let y_int = self.interpolate(&t_int, &t_sol, &y_sol, function);
Ok((t_int, y_int))
} else {
Ok((t_sol, y_sol))
}
}
}
impl<Y, U> InterpolateSolution<Y, U> for DormandPrince
where
Y: Tensor + TensorArray,
for<'a> &'a Y: Mul<TensorRank0, Output = Y> + Sub<&'a Y, Output = Y>,
U: TensorVec<Item = Y>,
{
fn interpolate(
&self,
time: &Vector,
tp: &Vector,
yp: &U,
function: impl Fn(&TensorRank0, &Y) -> Y,
) -> U {
let mut dt = 0.0;
let mut i = 0;
let mut k_1 = Y::zero();
let mut k_2 = Y::zero();
let mut k_3 = Y::zero();
let mut k_4 = Y::zero();
let mut k_5 = Y::zero();
let mut k_6 = Y::zero();
let mut t = 0.0;
let mut y = Y::zero();
time.iter()
.map(|time_k| {
i = tp.iter().position(|tp_i| tp_i > time_k).unwrap();
t = tp[i - 1];
y = yp[i - 1].clone();
dt = time_k - t;
k_1 = function(&t, &y);
k_2 = function(&(t + 0.2 * dt), &(&k_1 * (0.2 * dt) + &y));
k_3 = function(
&(t + 0.3 * dt),
&(&k_1 * (0.075 * dt) + &k_2 * (0.225 * dt) + &y),
);
k_4 = function(
&(t + 0.8 * dt),
&(&k_1 * (C_44_45 * dt) - &k_2 * (C_56_15 * dt) + &k_3 * (C_32_9 * dt) + &y),
);
k_5 = function(
&(t + C_8_9 * dt),
&(&k_1 * (C_19372_6561 * dt) - &k_2 * (C_25360_2187 * dt)
+ &k_3 * (C_64448_6561 * dt)
- &k_4 * (C_212_729 * dt)
+ &y),
);
k_6 = function(
&(t + dt),
&(&k_1 * (C_9017_3168 * dt) - &k_2 * (C_355_33 * dt)
+ &k_3 * (C_46732_5247 * dt)
+ &k_4 * (C_49_176 * dt)
- &k_5 * (C_5103_18656 * dt)
+ &y),
);
(&k_1 * C_35_384 + &k_3 * C_500_1113 + &k_4 * C_125_192 - &k_5 * C_2187_6784
+ &k_6 * C_11_84)
* dt
+ &y
})
.collect()
}
}