conspire/math/integrate/ode/explicit/variable_step/dormand_prince/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::math::Norm;
5use crate::math::{
6 Scalar, Tensor, TensorVec, Vector,
7 integrate::{
8 Explicit, IntegrationError, OdeIntegrator, VariableStep, VariableStepExplicit,
9 VariableStepExplicitFirstSameAsLast,
10 },
11 interpolate::InterpolateSolution,
12};
13use crate::{ABS_TOL, REL_TOL};
14use std::ops::{Mul, Sub};
15
16pub(crate) const C_44_45: Scalar = 44.0 / 45.0;
17pub(crate) const C_56_15: Scalar = 56.0 / 15.0;
18pub(crate) const C_32_9: Scalar = 32.0 / 9.0;
19pub(crate) const C_8_9: Scalar = 8.0 / 9.0;
20pub(crate) const C_19372_6561: Scalar = 19372.0 / 6561.0;
21pub(crate) const C_25360_2187: Scalar = 25360.0 / 2187.0;
22pub(crate) const C_64448_6561: Scalar = 64448.0 / 6561.0;
23pub(crate) const C_212_729: Scalar = 212.0 / 729.0;
24pub(crate) const C_9017_3168: Scalar = 9017.0 / 3168.0;
25pub(crate) const C_355_33: Scalar = 355.0 / 33.0;
26pub(crate) const C_46732_5247: Scalar = 46732.0 / 5247.0;
27pub(crate) const C_49_176: Scalar = 49.0 / 176.0;
28pub(crate) const C_5103_18656: Scalar = 5103.0 / 18656.0;
29pub(crate) const C_35_384: Scalar = 35.0 / 384.0;
30pub(crate) const C_500_1113: Scalar = 500.0 / 1113.0;
31pub(crate) const C_125_192: Scalar = 125.0 / 192.0;
32pub(crate) const C_2187_6784: Scalar = 2187.0 / 6784.0;
33pub(crate) const C_11_84: Scalar = 11.0 / 84.0;
34pub(crate) const C_71_57600: Scalar = 71.0 / 57600.0;
35pub(crate) const C_71_16695: Scalar = 71.0 / 16695.0;
36pub(crate) const C_71_1920: Scalar = 71.0 / 1920.0;
37pub(crate) const C_17253_339200: Scalar = 17253.0 / 339200.0;
38pub(crate) const C_22_525: Scalar = 22.0 / 525.0;
39
40pub(crate) const P_1_0: Scalar = 1.0;
41pub(crate) const P_1_1: Scalar = -8048581381.0 / 2820520608.0;
42pub(crate) const P_1_2: Scalar = 8663915743.0 / 2820520608.0;
43pub(crate) const P_1_3: Scalar = -12715105075.0 / 11282082432.0;
44pub(crate) const P_3_1: Scalar = 131558114200.0 / 32700410799.0;
45pub(crate) const P_3_2: Scalar = -68118460800.0 / 10900136933.0;
46pub(crate) const P_3_3: Scalar = 87487479700.0 / 32700410799.0;
47pub(crate) const P_4_1: Scalar = -1754552775.0 / 470086768.0;
48pub(crate) const P_4_2: Scalar = 14199869525.0 / 1410260304.0;
49pub(crate) const P_4_3: Scalar = -10690763975.0 / 1880347072.0;
50pub(crate) const P_5_1: Scalar = 127303824393.0 / 49829197408.0;
51pub(crate) const P_5_2: Scalar = -318862633887.0 / 49829197408.0;
52pub(crate) const P_5_3: Scalar = 701980252875.0 / 199316789632.0;
53pub(crate) const P_6_1: Scalar = -282668133.0 / 205662961.0;
54pub(crate) const P_6_2: Scalar = 2019193451.0 / 616988883.0;
55pub(crate) const P_6_3: Scalar = -1453857185.0 / 822651844.0;
56pub(crate) const P_7_1: Scalar = 40617522.0 / 29380423.0;
57pub(crate) const P_7_2: Scalar = -110615467.0 / 29380423.0;
58pub(crate) const P_7_3: Scalar = 69997945.0 / 29380423.0;
59
60#[doc = include_str!("doc.md")]
61#[derive(Debug)]
62pub struct DormandPrince {
63 pub abs_tol: Scalar,
65 pub rel_tol: Scalar,
67 pub dt_beta: Scalar,
69 pub dt_expn: Scalar,
71 pub dt_cut: Scalar,
73 pub dt_min: Scalar,
75 pub norm: Norm,
77}
78
79impl Default for DormandPrince {
80 fn default() -> Self {
81 Self {
82 abs_tol: ABS_TOL,
83 rel_tol: REL_TOL,
84 dt_beta: 0.9,
85 dt_expn: 5.0,
86 dt_cut: 0.5,
87 dt_min: ABS_TOL,
88 norm: Norm::Chebyshev,
89 }
90 }
91}
92
93impl<Y, U> OdeIntegrator<Y, U> for DormandPrince
94where
95 Y: Tensor,
96 U: TensorVec<Item = Y>,
97{
98}
99
100impl VariableStep for DormandPrince {
101 fn abs_tol(&self) -> Scalar {
102 self.abs_tol
103 }
104 fn rel_tol(&self) -> Scalar {
105 self.rel_tol
106 }
107 fn dt_beta(&self) -> Scalar {
108 self.dt_beta
109 }
110 fn dt_expn(&self) -> Scalar {
111 self.dt_expn
112 }
113 fn dt_cut(&self) -> Scalar {
114 self.dt_cut
115 }
116 fn dt_min(&self) -> Scalar {
117 self.dt_min
118 }
119 fn norm(&self) -> &Norm {
120 &self.norm
121 }
122}
123
124impl<Y, U> Explicit<Y, U> for DormandPrince
125where
126 Y: Tensor,
127 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
128 U: TensorVec<Item = Y>,
129{
130 const SLOPES: usize = 7;
131 fn integrate(
132 &self,
133 function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
134 time: &[Scalar],
135 initial_condition: Y,
136 ) -> Result<(Vector, U, U), IntegrationError> {
137 self.integrate_variable_step(function, time, initial_condition)
138 }
139}
140
141impl<Y, U> VariableStepExplicit<Y, U> for DormandPrince
142where
143 Self: Explicit<Y, U>,
144 Y: Tensor,
145 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
146 U: TensorVec<Item = Y>,
147{
148 fn error(&self, dt: Scalar, k: &[Y]) -> Result<Scalar, String> {
149 Ok(self.norm.apply(
150 &((&k[0] * C_71_57600 - &k[2] * C_71_16695 + &k[3] * C_71_1920
151 - &k[4] * C_17253_339200
152 + &k[5] * C_22_525
153 - &k[6] * 0.025)
154 * dt),
155 ))
156 }
157 fn slopes(
158 mut function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
159 y: &Y,
160 t: Scalar,
161 dt: Scalar,
162 k: &mut [Y],
163 y_trial: &mut Y,
164 ) -> Result<(), String> {
165 *y_trial = &k[0] * (0.2 * dt) + y;
166 k[1] = function(t + 0.2 * dt, y_trial)?;
167 *y_trial = &k[0] * (0.075 * dt) + &k[1] * (0.225 * dt) + y;
168 k[2] = function(t + 0.3 * dt, y_trial)?;
169 *y_trial = &k[0] * (C_44_45 * dt) - &k[1] * (C_56_15 * dt) + &k[2] * (C_32_9 * dt) + y;
170 k[3] = function(t + 0.8 * dt, y_trial)?;
171 *y_trial = &k[0] * (C_19372_6561 * dt) - &k[1] * (C_25360_2187 * dt)
172 + &k[2] * (C_64448_6561 * dt)
173 - &k[3] * (C_212_729 * dt)
174 + y;
175 k[4] = function(t + C_8_9 * dt, y_trial)?;
176 *y_trial = &k[0] * (C_9017_3168 * dt) - &k[1] * (C_355_33 * dt)
177 + &k[2] * (C_46732_5247 * dt)
178 + &k[3] * (C_49_176 * dt)
179 - &k[4] * (C_5103_18656 * dt)
180 + y;
181 k[5] = function(t + dt, y_trial)?;
182 *y_trial = (&k[0] * C_35_384 + &k[2] * C_500_1113 + &k[3] * C_125_192
183 - &k[4] * C_2187_6784
184 + &k[5] * C_11_84)
185 * dt
186 + y;
187 Ok(())
188 }
189 fn slopes_and_error(
190 &self,
191 function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
192 y: &Y,
193 t: Scalar,
194 dt: Scalar,
195 k: &mut [Y],
196 y_trial: &mut Y,
197 ) -> Result<Scalar, String> {
198 self.slopes_and_error_fsal(function, y, t, dt, k, y_trial)
199 }
200 fn step(
201 &self,
202 _function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
203 y: &mut Y,
204 t: &mut Scalar,
205 y_sol: &mut U,
206 t_sol: &mut Vector,
207 dydt_sol: &mut U,
208 k_sol: &mut Vec<U>,
209 dt: &mut Scalar,
210 k: &mut [Y],
211 y_trial: &Y,
212 e: Scalar,
213 ) -> Result<(), String> {
214 self.step_fsal(y, t, y_sol, t_sol, dydt_sol, k_sol, dt, k, y_trial, e)
215 }
216}
217
218impl<Y, U> VariableStepExplicitFirstSameAsLast<Y, U> for DormandPrince
219where
220 Y: Tensor,
221 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
222 U: TensorVec<Item = Y>,
223{
224}
225
226impl DormandPrince {
227 pub(crate) fn interpolate_free_dense<Y, U>(
228 time: &Vector,
229 tp: &Vector,
230 yp: &U,
231 dydtp: &U,
232 k_sol: &[U],
233 ) -> (U, U)
234 where
235 Y: Tensor,
236 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
237 U: TensorVec<Item = Y>,
238 {
239 let mut y_int = U::new();
240 let mut dydt_int = U::new();
241 for time_k in time.iter() {
242 let i = tp.iter().position(|tp_i| tp_i >= time_k).unwrap();
243 if time_k == &tp[i] {
244 y_int.push(yp[i].clone());
245 dydt_int.push(dydtp[i].clone());
246 } else {
247 let t_0 = tp[i - 1];
248 let h = tp[i] - t_0;
249 let theta = (time_k - t_0) / h;
250 let theta2 = theta * theta;
251 let theta3 = theta2 * theta;
252 let theta4 = theta3 * theta;
253 let k = &k_sol[i - 1];
254 let c_1 = theta * P_1_0 + theta2 * P_1_1 + theta3 * P_1_2 + theta4 * P_1_3;
255 let c_3 = theta2 * P_3_1 + theta3 * P_3_2 + theta4 * P_3_3;
256 let c_4 = theta2 * P_4_1 + theta3 * P_4_2 + theta4 * P_4_3;
257 let c_5 = theta2 * P_5_1 + theta3 * P_5_2 + theta4 * P_5_3;
258 let c_6 = theta2 * P_6_1 + theta3 * P_6_2 + theta4 * P_6_3;
259 let c_7 = theta2 * P_7_1 + theta3 * P_7_2 + theta4 * P_7_3;
260 let dc_1 =
261 P_1_0 + 2.0 * theta * P_1_1 + 3.0 * theta2 * P_1_2 + 4.0 * theta3 * P_1_3;
262 let dc_3 = 2.0 * theta * P_3_1 + 3.0 * theta2 * P_3_2 + 4.0 * theta3 * P_3_3;
263 let dc_4 = 2.0 * theta * P_4_1 + 3.0 * theta2 * P_4_2 + 4.0 * theta3 * P_4_3;
264 let dc_5 = 2.0 * theta * P_5_1 + 3.0 * theta2 * P_5_2 + 4.0 * theta3 * P_5_3;
265 let dc_6 = 2.0 * theta * P_6_1 + 3.0 * theta2 * P_6_2 + 4.0 * theta3 * P_6_3;
266 let dc_7 = 2.0 * theta * P_7_1 + 3.0 * theta2 * P_7_2 + 4.0 * theta3 * P_7_3;
267 let sum = &k[0] * c_1
268 + &k[2] * c_3
269 + &k[3] * c_4
270 + &k[4] * c_5
271 + &k[5] * c_6
272 + &k[6] * c_7;
273 y_int.push(sum * h + &yp[i - 1]);
274 dydt_int.push(
275 &k[0] * dc_1
276 + &k[2] * dc_3
277 + &k[3] * dc_4
278 + &k[4] * dc_5
279 + &k[5] * dc_6
280 + &k[6] * dc_7,
281 );
282 }
283 }
284 (y_int, dydt_int)
285 }
286}
287
288impl<Y, U> InterpolateSolution<Y, U> for DormandPrince
289where
290 Y: Tensor,
291 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
292 U: TensorVec<Item = Y>,
293{
294 fn interpolate(
295 &self,
296 time: &Vector,
297 tp: &Vector,
298 yp: &U,
299 dydtp: &U,
300 k_sol: &[U],
301 _function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
302 ) -> Result<(U, U), IntegrationError> {
303 Ok(Self::interpolate_free_dense(time, tp, yp, dydtp, k_sol))
304 }
305}