conspire/math/integrate/ode/explicit/variable_step/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::math::{
5 Scalar, Tensor, TensorVec, Vector,
6 integrate::{Explicit, IntegrationError, VariableStep},
7 interpolate::InterpolateSolution,
8};
9use std::ops::{Mul, Sub};
10
11pub mod internal_variables;
12
13pub mod bogacki_shampine;
14pub mod dormand_prince;
15pub mod verner_8;
16pub mod verner_9;
17
18pub trait VariableStepExplicit<Y, U>
20where
21 Self: InterpolateSolution<Y, U> + Explicit<Y, U> + VariableStep,
22 Y: Tensor,
23 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
24 U: TensorVec<Item = Y>,
25{
26 fn integrate_variable_step(
27 &self,
28 mut function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
29 time: &[Scalar],
30 initial_condition: Y,
31 ) -> Result<(Vector, U, U), IntegrationError> {
32 let t_0 = time[0];
33 let t_f = time[time.len() - 1];
34 if time.len() < 2 {
35 return Err(IntegrationError::LengthTimeLessThanTwo);
36 } else if t_0 >= t_f {
37 return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
38 }
39 let mut t = t_0;
40 let mut dt = t_f - t_0;
41 let mut k = vec![Y::default(); Self::SLOPES];
42 k[0] = function(t, &initial_condition)?;
43 let mut t_sol = Vector::new();
44 t_sol.push(t_0);
45 let mut y = initial_condition.clone();
46 let mut y_sol = U::new();
47 y_sol.push(initial_condition.clone());
48 let mut dydt_sol = U::new();
49 dydt_sol.push(k[0].clone());
50 let mut y_trial = Y::default();
51 while t < t_f {
52 match self.slopes(&mut function, &y, t, dt, &mut k, &mut y_trial) {
53 Ok(e) => {
54 if let Err(error) = self.step(
55 &mut function,
56 &mut y,
57 &mut t,
58 &mut y_sol,
59 &mut t_sol,
60 &mut dydt_sol,
61 &mut dt,
62 &mut k,
63 &y_trial,
64 e,
65 ) {
66 dt *= self.dt_cut();
67 if dt < self.dt_min() {
68 return Err(IntegrationError::MinimumStepSizeUpstream(
69 self.dt_min(),
70 error,
71 format!("{self:?}"),
72 ));
73 }
74 } else {
75 dt = dt.min(t_f - t);
76 if dt < self.dt_min() && t < t_f {
77 return Err(IntegrationError::MinimumStepSizeReached(
78 self.dt_min(),
79 format!("{self:?}"),
80 ));
81 }
82 }
83 }
84 Err(error) => {
85 dt *= self.dt_cut();
86 if dt < self.dt_min() {
87 return Err(IntegrationError::MinimumStepSizeUpstream(
88 self.dt_min(),
89 error,
90 format!("{self:?}"),
91 ));
92 }
93 }
94 }
95 }
96 if time.len() > 2 {
97 let t_int = Vector::from(time);
98 let (y_int, dydt_int) = self.interpolate(&t_int, &t_sol, &y_sol, function)?;
99 Ok((t_int, y_int, dydt_int))
100 } else {
101 Ok((t_sol, y_sol, dydt_sol))
102 }
103 }
104 fn slopes(
105 &self,
106 function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
107 y: &Y,
108 t: Scalar,
109 dt: Scalar,
110 k: &mut [Y],
111 y_trial: &mut Y,
112 ) -> Result<Scalar, String>;
113 #[allow(clippy::too_many_arguments)]
114 fn step(
115 &self,
116 function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
117 y: &mut Y,
118 t: &mut Scalar,
119 y_sol: &mut U,
120 t_sol: &mut Vector,
121 dydt_sol: &mut U,
122 dt: &mut Scalar,
123 k: &mut [Y],
124 y_trial: &Y,
125 e: Scalar,
126 ) -> Result<(), String>;
127 fn time_step(&self, error: Scalar, dt: &mut Scalar) {
133 if error > 0.0 {
134 *dt *= (self.dt_beta() * (self.abs_tol() / error).powf(1.0 / self.dt_expn()))
135 .max(self.dt_cut())
136 }
137 }
138}