conspire/math/integrate/verner_8/
mod.rs

1#[cfg(test)]
2mod test;
3
4use super::{
5    super::{Tensor, TensorRank0, TensorVec, Vector, interpolate::InterpolateSolution},
6    Explicit, IntegrationError,
7};
8use crate::{ABS_TOL, REL_TOL};
9use std::ops::{Mul, Sub};
10
11const C_2: TensorRank0 = 0.05;
12const C_3: TensorRank0 = 0.1065625;
13const C_4: TensorRank0 = 0.15984375;
14const C_5: TensorRank0 = 0.39;
15const C_6: TensorRank0 = 0.465;
16const C_7: TensorRank0 = 0.155;
17const C_8: TensorRank0 = 0.943;
18const C_9: TensorRank0 = 0.901802041735857;
19const C_10: TensorRank0 = 0.909;
20const C_11: TensorRank0 = 0.94;
21
22const A_2_1: TensorRank0 = 0.05;
23const A_3_1: TensorRank0 = -0.0069931640625;
24const A_3_2: TensorRank0 = 0.1135556640625;
25const A_4_1: TensorRank0 = 0.0399609375;
26const A_4_3: TensorRank0 = 0.1198828125;
27const A_5_1: TensorRank0 = 0.36139756280045754;
28const A_5_3: TensorRank0 = -1.3415240667004928;
29const A_5_4: TensorRank0 = 1.3701265039000352;
30const A_6_1: TensorRank0 = 0.049047202797202795;
31const A_6_4: TensorRank0 = 0.23509720422144048;
32const A_6_5: TensorRank0 = 0.18085559298135673;
33const A_7_1: TensorRank0 = 0.06169289044289044;
34const A_7_4: TensorRank0 = 0.11236568314640277;
35const A_7_5: TensorRank0 = -0.03885046071451367;
36const A_7_6: TensorRank0 = 0.01979188712522046;
37const A_8_1: TensorRank0 = -1.767630240222327;
38const A_8_4: TensorRank0 = -62.5;
39const A_8_5: TensorRank0 = -6.061889377376669;
40const A_8_6: TensorRank0 = 5.6508231982227635;
41const A_8_7: TensorRank0 = 65.62169641937624;
42const A_9_1: TensorRank0 = -1.1809450665549708;
43const A_9_4: TensorRank0 = -41.50473441114321;
44const A_9_5: TensorRank0 = -4.434438319103725;
45const A_9_6: TensorRank0 = 4.260408188586133;
46const A_9_7: TensorRank0 = 43.75364022446172;
47const A_9_8: TensorRank0 = 0.00787142548991231;
48const A_10_1: TensorRank0 = -1.2814059994414884;
49const A_10_4: TensorRank0 = -45.047139960139866;
50const A_10_5: TensorRank0 = -4.731362069449576;
51const A_10_6: TensorRank0 = 4.514967016593808;
52const A_10_7: TensorRank0 = 47.44909557172985;
53const A_10_8: TensorRank0 = 0.01059228297111661;
54const A_10_9: TensorRank0 = -0.0057468422638446166;
55const A_11_1: TensorRank0 = -1.7244701342624853;
56const A_11_4: TensorRank0 = -60.92349008483054;
57const A_11_5: TensorRank0 = -5.951518376222392;
58const A_11_6: TensorRank0 = 5.556523730698456;
59const A_11_7: TensorRank0 = 63.98301198033305;
60const A_11_8: TensorRank0 = 0.014642028250414961;
61const A_11_9: TensorRank0 = 0.06460408772358203;
62const A_11_10: TensorRank0 = -0.0793032316900888;
63const A_12_1: TensorRank0 = -3.301622667747079;
64const A_12_4: TensorRank0 = -118.01127235975251;
65const A_12_5: TensorRank0 = -10.141422388456112;
66const A_12_6: TensorRank0 = 9.139311332232058;
67const A_12_7: TensorRank0 = 123.37594282840426;
68const A_12_8: TensorRank0 = 4.62324437887458;
69const A_12_9: TensorRank0 = -3.3832777380682018;
70const A_12_10: TensorRank0 = 4.527592100324618;
71const A_12_11: TensorRank0 = -5.828495485811623;
72const A_13_1: TensorRank0 = -3.039515033766309;
73const A_13_4: TensorRank0 = -109.26086808941763;
74const A_13_5: TensorRank0 = -9.290642497400293;
75const A_13_6: TensorRank0 = 8.43050498176491;
76const A_13_7: TensorRank0 = 114.20100103783314;
77const A_13_8: TensorRank0 = -0.9637271342145479;
78const A_13_9: TensorRank0 = -5.0348840888021895;
79const A_13_10: TensorRank0 = 5.958130824002923;
80
81const B_1: TensorRank0 = 0.04427989419007951;
82const B_6: TensorRank0 = 0.3541049391724449;
83const B_7: TensorRank0 = 0.24796921549564377;
84const B_8: TensorRank0 = -15.694202038838085;
85const B_9: TensorRank0 = 25.084064965558564;
86const B_10: TensorRank0 = -31.738367786260277;
87const B_11: TensorRank0 = 22.938283273988784;
88const B_12: TensorRank0 = -0.2361324633071542;
89
90const D_1: TensorRank0 = -0.00003272103901028138;
91const D_6: TensorRank0 = -0.0005046250618777704;
92const D_7: TensorRank0 = 0.0001211723589784759;
93const D_8: TensorRank0 = -20.142336771313868;
94const D_9: TensorRank0 = 5.2371785994398286;
95const D_10: TensorRank0 = -8.156744408794658;
96const D_11: TensorRank0 = 22.938283273988784;
97const D_12: TensorRank0 = -0.2361324633071542;
98const D_13: TensorRank0 = 0.36016794372897754;
99
100/// Explicit, thirteen-stage, eighth-order, variable-step, Runge-Kutta method.[^cite]
101///
102/// [^cite]: J.H. Verner, [Numer. Algor. **53**, 383 (2010)](https://doi.org/10.1007/s11075-009-9290-3).
103///
104/// ```math
105/// \frac{dy}{dt} = f(t, y)
106/// ```
107/// ```math
108/// t_{n+1} = t_n + h
109/// ```
110/// ```math
111/// k_1 = f(t_n, y_n)
112/// ```
113/// ```math
114/// \cdots
115/// ```
116/// ```math
117/// h_{n+1} = \beta h \left(\frac{e_\mathrm{tol}}{e_{n+1}}\right)^{1/p}
118/// ```
119#[derive(Debug)]
120pub struct Verner8 {
121    /// Absolute error tolerance.
122    pub abs_tol: TensorRank0,
123    /// Relative error tolerance.
124    pub rel_tol: TensorRank0,
125    /// Multiplier for adaptive time steps.
126    pub dt_beta: TensorRank0,
127    /// Exponent for adaptive time steps.
128    pub dt_expn: TensorRank0,
129}
130
131impl Default for Verner8 {
132    fn default() -> Self {
133        Self {
134            abs_tol: ABS_TOL,
135            rel_tol: REL_TOL,
136            dt_beta: 0.9,
137            dt_expn: 8.0,
138        }
139    }
140}
141
142impl<Y, U> Explicit<Y, U> for Verner8
143where
144    Self: InterpolateSolution<Y, U>,
145    Y: Tensor,
146    for<'a> &'a Y: Mul<TensorRank0, Output = Y> + Sub<&'a Y, Output = Y>,
147    U: TensorVec<Item = Y>,
148{
149    fn integrate(
150        &self,
151        mut function: impl FnMut(TensorRank0, &Y) -> Result<Y, IntegrationError>,
152        time: &[TensorRank0],
153        initial_condition: Y,
154    ) -> Result<(Vector, U, U), IntegrationError> {
155        let t_0 = time[0];
156        let t_f = time[time.len() - 1];
157        if time.len() < 2 {
158            return Err(IntegrationError::LengthTimeLessThanTwo);
159        } else if t_0 >= t_f {
160            return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
161        }
162        let mut t = t_0;
163        let mut dt = t_f;
164        let mut e;
165        let mut k_1 = function(t, &initial_condition)?;
166        let mut k_2;
167        let mut k_3;
168        let mut k_4;
169        let mut k_5;
170        let mut k_6;
171        let mut k_7;
172        let mut k_8;
173        let mut k_9;
174        let mut k_10;
175        let mut k_11;
176        let mut k_12;
177        let mut k_13;
178        let mut t_sol = Vector::zero(0);
179        t_sol.push(t_0);
180        let mut y = initial_condition.clone();
181        let mut y_sol = U::zero(0);
182        y_sol.push(initial_condition.clone());
183        let mut dydt_sol = U::zero(0);
184        dydt_sol.push(k_1.clone());
185        let mut y_trial;
186        while t < t_f {
187            k_1 = function(t, &y)?;
188            k_2 = function(t + C_2 * dt, &(&k_1 * (A_2_1 * dt) + &y))?;
189            k_3 = function(
190                t + C_3 * dt,
191                &(&k_1 * (A_3_1 * dt) + &k_2 * (A_3_2 * dt) + &y),
192            )?;
193            k_4 = function(
194                t + C_4 * dt,
195                &(&k_1 * (A_4_1 * dt) + &k_3 * (A_4_3 * dt) + &y),
196            )?;
197            k_5 = function(
198                t + C_5 * dt,
199                &(&k_1 * (A_5_1 * dt) + &k_3 * (A_5_3 * dt) + &k_4 * (A_5_4 * dt) + &y),
200            )?;
201            k_6 = function(
202                t + C_6 * dt,
203                &(&k_1 * (A_6_1 * dt) + &k_4 * (A_6_4 * dt) + &k_5 * (A_6_5 * dt) + &y),
204            )?;
205            k_7 = function(
206                t + C_7 * dt,
207                &(&k_1 * (A_7_1 * dt)
208                    + &k_4 * (A_7_4 * dt)
209                    + &k_5 * (A_7_5 * dt)
210                    + &k_6 * (A_7_6 * dt)
211                    + &y),
212            )?;
213            k_8 = function(
214                t + C_8 * dt,
215                &(&k_1 * (A_8_1 * dt)
216                    + &k_4 * (A_8_4 * dt)
217                    + &k_5 * (A_8_5 * dt)
218                    + &k_6 * (A_8_6 * dt)
219                    + &k_7 * (A_8_7 * dt)
220                    + &y),
221            )?;
222            k_9 = function(
223                t + C_9 * dt,
224                &(&k_1 * (A_9_1 * dt)
225                    + &k_4 * (A_9_4 * dt)
226                    + &k_5 * (A_9_5 * dt)
227                    + &k_6 * (A_9_6 * dt)
228                    + &k_7 * (A_9_7 * dt)
229                    + &k_8 * (A_9_8 * dt)
230                    + &y),
231            )?;
232            k_10 = function(
233                t + C_10 * dt,
234                &(&k_1 * (A_10_1 * dt)
235                    + &k_4 * (A_10_4 * dt)
236                    + &k_5 * (A_10_5 * dt)
237                    + &k_6 * (A_10_6 * dt)
238                    + &k_7 * (A_10_7 * dt)
239                    + &k_8 * (A_10_8 * dt)
240                    + &k_9 * (A_10_9 * dt)
241                    + &y),
242            )?;
243            k_11 = function(
244                t + C_11 * dt,
245                &(&k_1 * (A_11_1 * dt)
246                    + &k_4 * (A_11_4 * dt)
247                    + &k_5 * (A_11_5 * dt)
248                    + &k_6 * (A_11_6 * dt)
249                    + &k_7 * (A_11_7 * dt)
250                    + &k_8 * (A_11_8 * dt)
251                    + &k_9 * (A_11_9 * dt)
252                    + &k_10 * (A_11_10 * dt)
253                    + &y),
254            )?;
255            k_12 = function(
256                t + dt,
257                &(&k_1 * (A_12_1 * dt)
258                    + &k_4 * (A_12_4 * dt)
259                    + &k_5 * (A_12_5 * dt)
260                    + &k_6 * (A_12_6 * dt)
261                    + &k_7 * (A_12_7 * dt)
262                    + &k_8 * (A_12_8 * dt)
263                    + &k_9 * (A_12_9 * dt)
264                    + &k_10 * (A_12_10 * dt)
265                    + &k_11 * (A_12_11 * dt)
266                    + &y),
267            )?;
268            y_trial = (&k_1 * B_1
269                + &k_6 * B_6
270                + &k_7 * B_7
271                + &k_8 * B_8
272                + &k_9 * B_9
273                + &k_10 * B_10
274                + &k_11 * B_11
275                + &k_12 * B_12)
276                * dt
277                + &y;
278            k_13 = function(
279                t + dt,
280                &(&k_1 * (A_13_1 * dt)
281                    + &k_4 * (A_13_4 * dt)
282                    + &k_5 * (A_13_5 * dt)
283                    + &k_6 * (A_13_6 * dt)
284                    + &k_7 * (A_13_7 * dt)
285                    + &k_8 * (A_13_8 * dt)
286                    + &k_9 * (A_13_9 * dt)
287                    + &k_10 * (A_13_10 * dt)
288                    + &y),
289            )?;
290            e = ((&k_1 * D_1
291                + &k_6 * D_6
292                + &k_7 * D_7
293                + &k_8 * D_8
294                + &k_9 * D_9
295                + &k_10 * D_10
296                + &k_11 * D_11
297                + &k_12 * D_12
298                + &k_13 * D_13)
299                * dt)
300                .norm_inf();
301            if e < self.abs_tol || e / y_trial.norm_inf() < self.rel_tol {
302                t += dt;
303                y = y_trial;
304                t_sol.push(t);
305                y_sol.push(y.clone());
306                dydt_sol.push(function(t, &y)?);
307            }
308            if e > 0.0 {
309                dt *= self.dt_beta * (self.abs_tol / e).powf(1.0 / self.dt_expn)
310            }
311            dt = dt.min(t_f - t)
312        }
313        if time.len() > 2 {
314            let t_int = Vector::new(time);
315            let (y_int, dydt_int) = self.interpolate(&t_int, &t_sol, &y_sol, function)?;
316            Ok((t_int, y_int, dydt_int))
317        } else {
318            Ok((t_sol, y_sol, dydt_sol))
319        }
320    }
321}
322
323impl<Y, U> InterpolateSolution<Y, U> for Verner8
324where
325    Y: Tensor,
326    for<'a> &'a Y: Mul<TensorRank0, Output = Y> + Sub<&'a Y, Output = Y>,
327    U: TensorVec<Item = Y>,
328{
329    fn interpolate(
330        &self,
331        time: &Vector,
332        tp: &Vector,
333        yp: &U,
334        mut function: impl FnMut(TensorRank0, &Y) -> Result<Y, IntegrationError>,
335    ) -> Result<(U, U), IntegrationError> {
336        let mut dt;
337        let mut i;
338        let mut k_1;
339        let mut k_2;
340        let mut k_3;
341        let mut k_4;
342        let mut k_5;
343        let mut k_6;
344        let mut k_7;
345        let mut k_8;
346        let mut k_9;
347        let mut k_10;
348        let mut k_11;
349        let mut k_12;
350        let mut t;
351        let mut y;
352        let mut y_int = U::zero(0);
353        let mut dydt_int = U::zero(0);
354        let mut y_trial;
355        for time_k in time.iter() {
356            i = tp.iter().position(|tp_i| tp_i >= time_k).unwrap();
357            if time_k == &tp[i] {
358                t = tp[i];
359                y_trial = yp[i].clone();
360                dt = 0.0;
361            } else {
362                t = tp[i - 1];
363                y = yp[i - 1].clone();
364                dt = time_k - t;
365                k_1 = function(t, &y)?;
366                k_2 = function(t + C_2 * dt, &(&k_1 * (A_2_1 * dt) + &y))?;
367                k_3 = function(
368                    t + C_3 * dt,
369                    &(&k_1 * (A_3_1 * dt) + &k_2 * (A_3_2 * dt) + &y),
370                )?;
371                k_4 = function(
372                    t + C_4 * dt,
373                    &(&k_1 * (A_4_1 * dt) + &k_3 * (A_4_3 * dt) + &y),
374                )?;
375                k_5 = function(
376                    t + C_5 * dt,
377                    &(&k_1 * (A_5_1 * dt) + &k_3 * (A_5_3 * dt) + &k_4 * (A_5_4 * dt) + &y),
378                )?;
379                k_6 = function(
380                    t + C_6 * dt,
381                    &(&k_1 * (A_6_1 * dt) + &k_4 * (A_6_4 * dt) + &k_5 * (A_6_5 * dt) + &y),
382                )?;
383                k_7 = function(
384                    t + C_7 * dt,
385                    &(&k_1 * (A_7_1 * dt)
386                        + &k_4 * (A_7_4 * dt)
387                        + &k_5 * (A_7_5 * dt)
388                        + &k_6 * (A_7_6 * dt)
389                        + &y),
390                )?;
391                k_8 = function(
392                    t + C_8 * dt,
393                    &(&k_1 * (A_8_1 * dt)
394                        + &k_4 * (A_8_4 * dt)
395                        + &k_5 * (A_8_5 * dt)
396                        + &k_6 * (A_8_6 * dt)
397                        + &k_7 * (A_8_7 * dt)
398                        + &y),
399                )?;
400                k_9 = function(
401                    t + C_9 * dt,
402                    &(&k_1 * (A_9_1 * dt)
403                        + &k_4 * (A_9_4 * dt)
404                        + &k_5 * (A_9_5 * dt)
405                        + &k_6 * (A_9_6 * dt)
406                        + &k_7 * (A_9_7 * dt)
407                        + &k_8 * (A_9_8 * dt)
408                        + &y),
409                )?;
410                k_10 = function(
411                    t + C_10 * dt,
412                    &(&k_1 * (A_10_1 * dt)
413                        + &k_4 * (A_10_4 * dt)
414                        + &k_5 * (A_10_5 * dt)
415                        + &k_6 * (A_10_6 * dt)
416                        + &k_7 * (A_10_7 * dt)
417                        + &k_8 * (A_10_8 * dt)
418                        + &k_9 * (A_10_9 * dt)
419                        + &y),
420                )?;
421                k_11 = function(
422                    t + C_11 * dt,
423                    &(&k_1 * (A_11_1 * dt)
424                        + &k_4 * (A_11_4 * dt)
425                        + &k_5 * (A_11_5 * dt)
426                        + &k_6 * (A_11_6 * dt)
427                        + &k_7 * (A_11_7 * dt)
428                        + &k_8 * (A_11_8 * dt)
429                        + &k_9 * (A_11_9 * dt)
430                        + &k_10 * (A_11_10 * dt)
431                        + &y),
432                )?;
433                k_12 = function(
434                    t + dt,
435                    &(&k_1 * (A_12_1 * dt)
436                        + &k_4 * (A_12_4 * dt)
437                        + &k_5 * (A_12_5 * dt)
438                        + &k_6 * (A_12_6 * dt)
439                        + &k_7 * (A_12_7 * dt)
440                        + &k_8 * (A_12_8 * dt)
441                        + &k_9 * (A_12_9 * dt)
442                        + &k_10 * (A_12_10 * dt)
443                        + &k_11 * (A_12_11 * dt)
444                        + &y),
445                )?;
446                y_trial = (&k_1 * B_1
447                    + &k_6 * B_6
448                    + &k_7 * B_7
449                    + &k_8 * B_8
450                    + &k_9 * B_9
451                    + &k_10 * B_10
452                    + &k_11 * B_11
453                    + &k_12 * B_12)
454                    * dt
455                    + &y;
456            }
457            dydt_int.push(function(t + dt, &y_trial)?);
458            y_int.push(y_trial);
459        }
460        Ok((y_int, dydt_int))
461    }
462}