mod algebraic;
mod initialize;
mod interpolate;
mod ordinary;
use std::marker::PhantomData;
use crate::{
linalg::Matrix,
methods::{ImplicitRungeKutta, Radau},
status::Status,
tolerance::Tolerance,
traits::{Real, State},
utils::constrain_step_size,
};
impl<E, T: Real, Y: State<T>> ImplicitRungeKutta<E, Radau, T, Y, 5, 3, 3> {
pub fn radau5() -> Radau5<E, T, Y> {
Radau5::default()
}
}
pub struct Radau5<E, T: Real, Y: State<T>> {
pub rtol: Tolerance<T>,
pub atol: Tolerance<T>,
pub h0: T,
pub h_min: T,
pub h_max: T,
pub max_steps: usize,
pub max_rejects: usize,
pub newton_tol: T,
pub max_newton_iter: usize,
pub safety_factor: T,
pub min_scale: T,
pub max_scale: T,
pub predictive: bool,
pub filter: fn(T) -> T,
t: T,
y: Y,
dydt: Y,
t_prev: T,
y_prev: Y,
dydt_prev: Y,
h: T,
h_prev: T,
tf: T,
c1: T,
c2: T,
c1m1: T,
c2m1: T,
c1mc2: T,
dd1: T,
dd2: T,
dd3: T,
u1: T,
alph: T,
beta: T,
tmat: Matrix<T>,
tinv: Matrix<T>,
z: [Y; 3],
k: [Y; 3],
f: [Y; 3],
jacobian: Matrix<T>,
jacobian_age: usize,
a: Matrix<T>,
b: Vec<T>,
faccon: T,
dynold: T,
theta: T,
thet: T,
thqold: T,
cfac: T,
facr: T,
facl: T,
uround: T,
scal: Y,
quot1: T,
quot2: T,
hhfac: T,
e1: Matrix<T>,
e2r: Matrix<T>,
e2i: Matrix<T>,
ip1: Vec<usize>,
ip2: Vec<usize>,
mass: Matrix<T>,
index2: Vec<usize>,
index3: Vec<usize>,
singular_count: usize,
steps: usize,
rejects: usize,
n_accepted: usize,
status: Status<T, Y>,
cont: [Y; 4],
first: bool,
reject: bool,
call_jac: bool,
call_decomp: bool,
h_acc: T,
err_acc: T,
equation: PhantomData<E>,
}
impl<E, T: Real, Y: State<T>> Default for Radau5<E, T, Y> {
fn default() -> Self {
let c1_t = T::from_f64(0.155_051_025_721_682_2).unwrap();
let c2_t = T::from_f64(0.644_948_974_278_317_8).unwrap();
let c1m1 = T::from_f64(-0.844_948_974_278_317_8).unwrap();
let c2m1 = T::from_f64(-0.355_051_025_721_682_2).unwrap();
let c1mc2 = T::from_f64(-0.489_897_948_556_635_6).unwrap();
let dd1 = T::from_f64(-10.048_809_399_827_416).unwrap();
let dd2 = T::from_f64(1.382_142_733_160_749).unwrap();
let dd3 = T::from_f64(-0.333_333_333_333_333_3).unwrap();
let u1 = T::from_f64(3.637_834_252_744_496).unwrap();
let alph = T::from_f64(2.681_082_873_627_752_3).unwrap();
let beta = T::from_f64(3.050_430_199_247_410_5).unwrap();
let mut tmat = Matrix::zeros(3, 3);
tmat[(0, 0)] = T::from_f64(9.123_239_487_089_295E-2).unwrap();
tmat[(0, 1)] = T::from_f64(-1.412_552_950_209_542E-1).unwrap();
tmat[(0, 2)] = T::from_f64(-3.002_919_410_514_742_4E-2).unwrap();
tmat[(1, 0)] = T::from_f64(2.417_179_327_071_07E-1).unwrap();
tmat[(1, 1)] = T::from_f64(2.041_293_522_937_999_4E-1).unwrap();
tmat[(1, 2)] = T::from_f64(3.829_421_127_572_619E-1).unwrap();
tmat[(2, 0)] = T::from_f64(9.660_481_826_150_93E-1).unwrap();
let mut tinv = Matrix::zeros(3, 3);
tinv[(0, 0)] = T::from_f64(4.325_579_890_063_155).unwrap();
tinv[(0, 1)] = T::from_f64(3.391_992_518_158_098_4E-1).unwrap();
tinv[(0, 2)] = T::from_f64(5.417_705_399_358_749E-1).unwrap();
tinv[(1, 0)] = T::from_f64(-4.178_718_591_551_905).unwrap();
tinv[(1, 1)] = T::from_f64(-3.276_828_207_610_623_7E-1).unwrap();
tinv[(1, 2)] = T::from_f64(4.766_235_545_005_504_4E-1).unwrap();
tinv[(2, 0)] = T::from_f64(-5.028_726_349_457_868E-1).unwrap();
tinv[(2, 1)] = T::from_f64(2.571_926_949_855_605).unwrap();
tinv[(2, 2)] = T::from_f64(-5.960_392_048_282_249E-1).unwrap();
let safety_factor = T::from_f64(0.9).unwrap();
let max_newton_iter_usize: usize = 7;
let cfac_default = T::from_f64(13.5).unwrap();
let facl_default = T::from_f64(5.0).unwrap();
let facr_default = T::from_f64(0.125).unwrap();
let rtol_default = T::from_f64(0.000001).unwrap();
let atol_default = T::from_f64(0.000001).unwrap();
let uround = T::from_f64(1e-16).unwrap();
let newton_tol_default = T::from_f64(0.003_162_277_660_168_379_4).unwrap();
Self {
rtol: Tolerance::Scalar(rtol_default),
atol: Tolerance::Scalar(atol_default),
h0: T::zero(),
h_min: T::zero(),
h_max: T::infinity(),
max_steps: 100_000,
max_rejects: 20,
newton_tol: newton_tol_default,
max_newton_iter: max_newton_iter_usize,
safety_factor,
cfac: cfac_default,
facl: facl_default,
facr: facr_default,
min_scale: T::from_f64(0.2).unwrap(),
max_scale: T::from_f64(8.0).unwrap(),
predictive: true,
filter: |h| h,
t: T::zero(),
y: Y::zeros(),
dydt: Y::zeros(),
t_prev: T::zero(),
y_prev: Y::zeros(),
dydt_prev: Y::zeros(),
h: T::zero(),
h_prev: T::zero(),
tf: T::zero(),
c1: c1_t,
c2: c2_t,
c1m1,
c2m1,
c1mc2,
dd1,
dd2,
dd3,
u1,
alph,
beta,
tmat,
tinv,
z: core::array::from_fn(|_| Y::zeros()),
k: core::array::from_fn(|_| Y::zeros()),
f: core::array::from_fn(|_| Y::zeros()),
jacobian: Matrix::zeros(0, 0),
jacobian_age: 0,
a: Matrix::zeros(0, 0),
b: Vec::new(),
faccon: T::one(),
dynold: T::from_f64(1e-16).unwrap(),
theta: T::zero(),
thet: T::from_f64(0.001).unwrap(),
thqold: T::one(),
uround,
scal: Y::zeros(),
quot1: T::one(),
quot2: T::from_f64(1.2).unwrap(),
hhfac: T::zero(),
e1: Matrix::zeros(0, 0),
e2r: Matrix::zeros(0, 0),
e2i: Matrix::zeros(0, 0),
ip1: Vec::new(),
ip2: Vec::new(),
mass: Matrix::identity(0),
index2: Vec::new(),
index3: Vec::new(),
cont: core::array::from_fn(|_| Y::zeros()),
singular_count: 0,
steps: 0,
rejects: 0,
n_accepted: 0,
status: Status::Uninitialized,
first: true,
reject: false,
call_jac: true,
call_decomp: true,
h_acc: T::zero(),
err_acc: T::from_f64(1e-2).unwrap(),
equation: PhantomData,
}
}
}
impl<E, T: Real, Y: State<T>> Radau5<E, T, Y> {
pub fn rtol<V: Into<Tolerance<T>>>(mut self, rtol: V) -> Self {
self.rtol = rtol.into();
self
}
pub fn atol<V: Into<Tolerance<T>>>(mut self, atol: V) -> Self {
self.atol = atol.into();
self
}
pub fn h0(mut self, h0: T) -> Self {
self.h0 = h0;
self
}
pub fn h_min(mut self, h_min: T) -> Self {
self.h_min = h_min;
self
}
pub fn h_max(mut self, h_max: T) -> Self {
self.h_max = h_max;
self
}
pub fn min_scale(mut self, min_scale: T) -> Self {
self.min_scale = min_scale;
self.facl = T::one() / min_scale;
self
}
pub fn max_scale(mut self, max_scale: T) -> Self {
self.max_scale = max_scale;
self.facr = T::one() / max_scale;
self
}
pub fn predictive(mut self, enabled: bool) -> Self {
self.predictive = enabled;
self
}
pub fn max_steps(mut self, n: usize) -> Self {
self.max_steps = n;
self
}
pub fn max_rejects(mut self, n: usize) -> Self {
self.max_rejects = n;
self
}
pub fn newton_tol(mut self, tol: T) -> Self {
self.newton_tol = tol;
self
}
pub fn safety_factor(mut self, sf: T) -> Self {
self.safety_factor = sf;
self
}
pub fn max_newton_iter(mut self, n: usize) -> Self {
self.max_newton_iter = n;
self
}
pub fn index2_equations<Idxs>(mut self, idxs: Idxs) -> Self
where
Idxs: Into<Vec<usize>>,
{
self.index2 = idxs.into();
self
}
pub fn filter(mut self, filter: fn(T) -> T) -> Self {
self.filter = filter;
self
}
pub fn index3_equations<Idxs>(mut self, idxs: Idxs) -> Self
where
Idxs: Into<Vec<usize>>,
{
self.index3 = idxs.into();
self
}
fn unexpected_step_rejection(&mut self) {
self.hhfac = T::from_f64(0.5).unwrap();
self.h = constrain_step_size(self.h * self.hhfac, self.h_min, self.h_max);
self.h = (self.filter)(self.h);
self.reject = true;
self.status = Status::RejectedStep;
}
}