numeric_algs/integration/
rk8.rs

1use super::{Integrator, StepSize};
2use crate::traits::State;
3
4// Source: https://core.ac.uk/download/pdf/42883081.pdf section 6.6
5
6pub struct RK8Integrator {
7    default_step: f64,
8}
9
10impl RK8Integrator {
11    pub fn new(step_size: f64) -> Self {
12        RK8Integrator {
13            default_step: step_size,
14        }
15    }
16
17    pub fn set_default_step(&mut self, step: f64) {
18        self.default_step = step;
19    }
20}
21
22impl<S: State> Integrator<S> for RK8Integrator {
23    fn propagate_in_place<D>(&mut self, start: &mut S, diff_eq: D, step_size: StepSize)
24    where
25        D: Fn(&S) -> S::Derivative,
26    {
27        let h = match step_size {
28            StepSize::UseDefault => self.default_step,
29            StepSize::Step(x) => x,
30        };
31
32        let mut f = vec![diff_eq(start)];
33
34        let a: [(f64, f64); 9] = [
35            (4.0, 27.0),
36            (2.0, 9.0),
37            (1.0, 3.0),
38            (1.0, 2.0),
39            (2.0, 3.0),
40            (1.0, 6.0),
41            (1.0, 1.0),
42            (5.0, 6.0),
43            (1.0, 1.0),
44        ];
45
46        let b: [(f64, Vec<f64>); 9] = [
47            (1.0, vec![1.0]),
48            (4.0, vec![1.0, 3.0]),
49            (4.0, vec![1.0, 0.0, 3.0]),
50            (4.0, vec![1.0, 0.0, 0.0, 3.0]),
51            (36.0, vec![13.0, 0.0, -27.0, 42.0, 8.0]),
52            (720.0, vec![389.0, 0.0, -54.0, 966.0, -824.0, 243.0]),
53            (20.0, vec![-231.0, 0.0, 81.0, -1164.0, 656.0, -122.0, 800.0]),
54            (
55                240.0,
56                vec![-127.0, 0.0, 18.0, -678.0, 456.0, -9.0, 576.0, 4.0],
57            ),
58            (
59                820.0,
60                vec![
61                    1481.0, 0.0, -81.0, 7104.0, -3376.0, 72.0, -5040.0, -60.0, 720.0,
62                ],
63            ),
64        ];
65
66        for i in 0..9 {
67            assert_eq!(f.len(), b[i].1.len());
68            let k = f
69                .iter()
70                .zip(b[i].1.iter())
71                .map(|(f, b)| f.clone() * *b)
72                .reduce(|v1, v2| v1 + v2)
73                .unwrap()
74                / b[i].0;
75            let a = a[i];
76            let new_f = diff_eq(&start.shift(&k, h * a.0 / a.1));
77            f.push(new_f);
78        }
79
80        let c: [f64; 10] = [41.0, 0.0, 0.0, 27.0, 272.0, 27.0, 216.0, 0.0, 216.0, 41.0];
81
82        assert_eq!(f.len(), 10);
83
84        let shift = f
85            .iter()
86            .zip(c.iter())
87            .map(|(f, c)| f.clone() * *c)
88            .reduce(|v1, v2| v1 + v2)
89            .unwrap()
90            / 840.0;
91
92        start.shift_in_place(&shift, h);
93    }
94}