1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Lobatto Implicit Runge-Kutta Methods
use crate::{tableau::ButcherTableau, traits::Real};
impl<T: Real> ButcherTableau<T, 2> {
/// Butcher Tableau for the Lobatto IIIC method of order 2.
///
/// # Overview
/// This provides a 2-stage, implicit Runge-Kutta method (Lobatto IIIC) with:
/// - Primary order: 2
/// - Number of stages: 2
///
/// # Notes
/// - Lobatto IIIC methods are L-stable.
/// - They are algebraically stable and thus B-stable, making them suitable for stiff problems.
/// - This implementation includes two sets of `b` coefficients. The primary `b` coefficients
/// are used for the solution, and `bh` can represent alternative coefficients if needed
/// (though their specific use here as a second row is characteristic of Lobatto IIIC).
///
/// # Butcher Tableau
/// ```text
/// 0 | 1/2 -1/2
/// 1 | 1/2 1/2
/// ----|------------
/// | 1/2 1/2 (b coefficients)
/// | 1 0 (bh coefficients)
/// ```
///
/// # References
/// - Hairer, E., & Wanner, G. (1996). *Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems*. Springer. (Page 80, Table 5.7)
pub fn lobatto_iiic_2() -> Self {
let mut c = [0.0; 2];
let mut a = [[0.0; 2]; 2];
let mut b = [0.0; 2];
let mut bh = [0.0; 2];
c[0] = 0.0;
c[1] = 1.0;
a[0][0] = 1.0 / 2.0;
a[0][1] = -1.0 / 2.0;
a[1][0] = 1.0 / 2.0;
a[1][1] = 1.0 / 2.0;
b[0] = 1.0 / 2.0;
b[1] = 1.0 / 2.0;
bh[0] = 1.0;
bh[1] = 0.0;
let c = c.map(|x| T::from_f64(x).unwrap());
let a = a.map(|row| row.map(|x| T::from_f64(x).unwrap()));
let b = b.map(|x| T::from_f64(x).unwrap());
let bh = bh.map(|x| T::from_f64(x).unwrap());
Self {
c,
a,
b,
bh: Some(bh),
bi: None,
er: None,
}
}
}
impl<T: Real> ButcherTableau<T, 3> {
/// Butcher Tableau for the Lobatto IIIC method of order 4.
///
/// # Overview
/// This provides a 3-stage, implicit Runge-Kutta method (Lobatto IIIC) with:
/// - Primary order: 4
/// - Number of stages: 3
///
/// # Notes
/// - Lobatto IIIC methods are L-stable.
/// - They are algebraically stable and thus B-stable, making them suitable for stiff problems.
/// - This implementation includes two sets of `b` coefficients. The primary `b` coefficients
/// are used for the solution, and `bh` represents the second row of coefficients from the tableau.
///
/// # Butcher Tableau
/// ```text
/// 0 | 1/6 -1/3 1/6
/// 1/2 | 1/6 5/12 -1/12
/// 1 | 1/6 2/3 1/6
/// ----|------------------
/// | 1/6 2/3 1/6 (b coefficients)
/// | -1/2 2 -1/2 (bh coefficients)
/// ```
///
/// # References
/// - Hairer, E., & Wanner, G. (1996). *Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems*. Springer. (Page 80, Table 5.7)
pub fn lobatto_iiic_4() -> Self {
let mut c = [0.0; 3];
let mut a = [[0.0; 3]; 3];
let mut b = [0.0; 3];
let mut bh = [0.0; 3];
c[0] = 0.0;
c[1] = 1.0 / 2.0;
c[2] = 1.0;
a[0][0] = 1.0 / 6.0;
a[0][1] = -1.0 / 3.0;
a[0][2] = 1.0 / 6.0;
a[1][0] = 1.0 / 6.0;
a[1][1] = 5.0 / 12.0;
a[1][2] = -1.0 / 12.0;
a[2][0] = 1.0 / 6.0;
a[2][1] = 2.0 / 3.0;
a[2][2] = 1.0 / 6.0;
b[0] = 1.0 / 6.0;
b[1] = 2.0 / 3.0;
b[2] = 1.0 / 6.0;
bh[0] = -1.0 / 2.0;
bh[1] = 2.0;
bh[2] = -1.0 / 2.0;
let c = c.map(|x| T::from_f64(x).unwrap());
let a = a.map(|row| row.map(|x| T::from_f64(x).unwrap()));
let b = b.map(|x| T::from_f64(x).unwrap());
let bh = bh.map(|x| T::from_f64(x).unwrap());
Self {
c,
a,
b,
bh: Some(bh),
bi: None,
er: None,
}
}
}