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