differential_equations/tableau/gauss_legendre.rs
1//! Gauss-Legendre Implicit Runge-Kutta Methods
2
3use crate::{tableau::ButcherTableau, traits::Real};
4
5const SQRT_3: f64 = 1.732050808;
6
7impl<T: Real> ButcherTableau<T, 2> {
8 /// Butcher Tableau for the Gauss-Legendre method of order 4.
9 ///
10 /// # Overview
11 /// This provides a 2-stage, implicit Runge-Kutta method (Gauss-Legendre) with:
12 /// - Primary order: 4
13 /// - Number of stages: 2
14 ///
15 /// # Notes
16 /// - Gauss-Legendre methods are A-stable and symmetric.
17 /// - They are highly accurate for their number of stages.
18 /// - The `c` values are the roots of the Legendre polynomial P_s(2x-1) = 0.
19 /// - This implementation includes two sets of `b` coefficients. The primary `b` coefficients
20 /// are used for the solution, and `bh` can represent alternative coefficients (often related to error estimation or specific properties).
21 ///
22 /// # Butcher Tableau
23 /// ```text
24 /// (1/2 - sqrt(3)/6) | 1/4 1/4 - sqrt(3)/6
25 /// (1/2 + sqrt(3)/6) | 1/4 + sqrt(3)/6 1/4
26 /// -------------------|---------------------------------------
27 /// | 1/2 1/2
28 /// | 1/2 + sqrt(3)/2 1/2 - sqrt(3)/2 (bh coefficients)
29 /// ```
30 ///
31 /// # References
32 /// - Hairer, E., Nørsett, S. P., & Wanner, G. (1993). *Solving Ordinary Differential Equations I: Nonstiff Problems*. Springer. (Page 200, Table 4.5)
33 pub fn gauss_legendre_4() -> Self {
34 let mut c = [0.0; 2];
35 let mut a = [[0.0; 2]; 2];
36 let mut b = [0.0; 2];
37 let mut bh = [0.0; 2];
38
39 let sqrt3_6 = SQRT_3 / 6.0;
40 let sqrt3_2 = SQRT_3 / 2.0;
41
42 c[0] = 0.5 - sqrt3_6;
43 c[1] = 0.5 + sqrt3_6;
44
45 a[0][0] = 0.25;
46 a[0][1] = 0.25 - sqrt3_6;
47 a[1][0] = 0.25 + sqrt3_6;
48 a[1][1] = 0.25;
49
50 b[0] = 0.5;
51 b[1] = 0.5;
52
53 bh[0] = 0.5 + sqrt3_2;
54 bh[1] = 0.5 - sqrt3_2;
55
56 let c = c.map(|x| T::from_f64(x).unwrap());
57 let a = a.map(|row| row.map(|x| T::from_f64(x).unwrap()));
58 let b = b.map(|x| T::from_f64(x).unwrap());
59 let bh = bh.map(|x| T::from_f64(x).unwrap());
60
61 Self {
62 c,
63 a,
64 b,
65 bh: Some(bh),
66 bi: None,
67 er: None,
68 }
69 }
70}
71
72impl<T: Real> ButcherTableau<T, 3> {
73 /// Butcher Tableau for the Gauss-Legendre method of order 6.
74 ///
75 /// # Overview
76 /// This provides a 3-stage, implicit Runge-Kutta method (Gauss-Legendre) with:
77 /// - Primary order: 6
78 /// - Number of stages: 3
79 ///
80 /// # Notes
81 /// - Gauss-Legendre methods are A-stable and symmetric.
82 /// - They are highly accurate for their number of stages.
83 /// - The `c` values are the roots of the Legendre polynomial P_s(2x-1) = 0.
84 /// - This implementation includes two sets of `b` coefficients. The primary `b` coefficients
85 /// are used for the solution, and `bh` can represent alternative coefficients.
86 ///
87 /// # Butcher Tableau
88 /// ```text
89 /// (1/2 - sqrt(15)/10) | 5/36 2/9 - sqrt(15)/15 5/36 - sqrt(15)/30
90 /// 1/2 | 5/36 + sqrt(15)/24 2/9 5/36 - sqrt(15)/24
91 /// (1/2 + sqrt(15)/10) | 5/36 + sqrt(15)/30 2/9 + sqrt(15)/15 5/36
92 /// --------------------|-------------------------------------------------------------
93 /// | 5/18 4/9 5/18
94 /// | -5/6 8/3 -5/6 (bh coefficients)
95 /// ```
96 ///
97 /// # References
98 /// - Hairer, E., Nørsett, S. P., & Wanner, G. (1993). *Solving Ordinary Differential Equations I: Nonstiff Problems*. Springer. (Page 200, Table 4.5)
99 pub fn gauss_legendre_6() -> Self {
100 let mut c = [0.0; 3];
101 let mut a = [[0.0; 3]; 3];
102 let mut b = [0.0; 3];
103 let mut bh = [0.0; 3];
104
105 let sqrt_15: f64 = 3.872983346207417;
106 let sqrt15_10 = sqrt_15 / 10.0;
107 let sqrt15_15 = sqrt_15 / 15.0;
108 let sqrt15_24 = sqrt_15 / 24.0;
109 let sqrt15_30 = sqrt_15 / 30.0;
110
111 c[0] = 0.5 - sqrt15_10;
112 c[1] = 0.5;
113 c[2] = 0.5 + sqrt15_10;
114
115 a[0][0] = 5.0 / 36.0;
116 a[0][1] = 2.0 / 9.0 - sqrt15_15;
117 a[0][2] = 5.0 / 36.0 - sqrt15_30;
118
119 a[1][0] = 5.0 / 36.0 + sqrt15_24;
120 a[1][1] = 2.0 / 9.0;
121 a[1][2] = 5.0 / 36.0 - sqrt15_24;
122
123 a[2][0] = 5.0 / 36.0 + sqrt15_30;
124 a[2][1] = 2.0 / 9.0 + sqrt15_15;
125 a[2][2] = 5.0 / 36.0;
126
127 b[0] = 5.0 / 18.0;
128 b[1] = 4.0 / 9.0;
129 b[2] = 5.0 / 18.0;
130
131 bh[0] = -5.0 / 6.0;
132 bh[1] = 8.0 / 3.0;
133 bh[2] = -5.0 / 6.0;
134
135 let c = c.map(|x| T::from_f64(x).unwrap());
136 let a = a.map(|row| row.map(|x| T::from_f64(x).unwrap()));
137 let b = b.map(|x| T::from_f64(x).unwrap());
138 let bh = bh.map(|x| T::from_f64(x).unwrap());
139
140 Self {
141 c,
142 a,
143 b,
144 bh: Some(bh),
145 bi: None,
146 er: None,
147 }
148 }
149}