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, FreeInterpolant, IntegrationError,
9 OdeIntegrator, Times, VariableStep, VariableStepExplicit,
10 VariableStepExplicitFirstSameAsLast,
11 },
12 interpolate::InterpolateSolution,
13};
14use crate::{ABS_TOL, REL_TOL};
15use std::ops::{Div, Mul, Sub};
16
17#[derive(Debug)]
19pub struct Tableau;
20
21impl ButcherTableau for Tableau {
22 const STAGES: usize = 4;
23 const ORDER: Scalar = 3.0;
24 const A: &'static [&'static [Scalar]] = &[
25 &[],
26 &[0.5],
27 &[0.0, 0.75],
28 &[2.0 / 9.0, 1.0 / 3.0, 4.0 / 9.0],
29 ];
30 const C: &'static [Scalar] = &[0.0, 0.5, 0.75, 1.0];
31 const B: &'static [Scalar] = &[2.0 / 9.0, 1.0 / 3.0, 4.0 / 9.0, 0.0];
32 const FSAL: bool = true;
33}
34
35impl EmbeddedTableau for Tableau {
36 const D: &'static [Scalar] = &[-5.0 / 72.0, 6.0 / 72.0, 8.0 / 72.0, -9.0 / 72.0];
37}
38
39#[doc = include_str!("doc.md")]
40#[derive(Debug)]
41pub struct BogackiShampine {
42 pub abs_tol: Scalar,
44 pub rel_tol: Scalar,
46 pub dt_beta: Scalar,
48 pub dt_expn: Scalar,
50 pub dt_cut: Scalar,
52 pub dt_grow: Scalar,
54 pub dt_min: Scalar,
56 pub error_norm: Norm,
58}
59
60impl Default for BogackiShampine {
61 fn default() -> Self {
62 Self {
63 abs_tol: ABS_TOL,
64 rel_tol: REL_TOL,
65 dt_beta: 0.9,
66 dt_expn: 3.0,
67 dt_cut: 0.5,
68 dt_grow: 5.0,
69 dt_min: ABS_TOL,
70 error_norm: Norm::Chebyshev,
71 }
72 }
73}
74
75impl<Y, U> OdeIntegrator<Y, U> for BogackiShampine
76where
77 Y: Tensor,
78 U: TensorVec<Item = Y>,
79{
80}
81
82impl<T> VariableStep<T> for BogackiShampine {
83 fn abs_tol(&self) -> Scalar {
84 self.abs_tol
85 }
86 fn rel_tol(&self) -> Scalar {
87 self.rel_tol
88 }
89 fn dt_beta(&self) -> Scalar {
90 self.dt_beta
91 }
92 fn dt_expn(&self) -> Scalar {
93 self.dt_expn
94 }
95 fn dt_cut(&self) -> Scalar {
96 self.dt_cut
97 }
98 fn dt_grow(&self) -> Scalar {
99 self.dt_grow
100 }
101 fn dt_min(&self) -> Quantity<T> {
102 Quantity::new(self.dt_min)
103 }
104 fn error_norm(&self) -> &Norm {
105 &self.error_norm
106 }
107}
108
109impl<Y, U, V, T> Explicit<Y, U, V, T> for BogackiShampine
110where
111 Y: Differentiable<T> + Div<Quantity<T>, Output = Derivative<Y, T>> + Tensor,
112 Derivative<Y, T>: Mul<Quantity<T>, Output = Y>,
113 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
114 for<'a> &'a Derivative<Y, T>:
115 Mul<Scalar, Output = Derivative<Y, T>> + Mul<Quantity<T>, Output = Y>,
116 U: TensorVec<Item = Y>,
117 V: TensorVec<Item = Derivative<Y, T>>,
118{
119 const SLOPES: usize = 4;
120 fn integrate(
121 &self,
122 function: impl FnMut(Quantity<T>, &Y) -> Result<Derivative<Y, T>, String>,
123 time: &[Quantity<T>],
124 initial_condition: Y,
125 ) -> Result<(Times<T>, U, V), IntegrationError> {
126 self.integrate_variable_step(function, time, initial_condition)
127 }
128}
129
130impl<Y, U, V, T> VariableStepExplicit<Y, U, V, T> for BogackiShampine
131where
132 Self: Explicit<Y, U, V, T>,
133 Y: Differentiable<T> + Div<Quantity<T>, Output = Derivative<Y, T>> + Tensor,
134 Derivative<Y, T>: Mul<Quantity<T>, Output = Y>,
135 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
136 for<'a> &'a Derivative<Y, T>:
137 Mul<Scalar, Output = Derivative<Y, T>> + Mul<Quantity<T>, Output = Y>,
138 U: TensorVec<Item = Y>,
139 V: TensorVec<Item = Derivative<Y, T>>,
140{
141 type Tableau = Tableau;
142 fn slopes_and_error(
143 &self,
144 function: impl FnMut(Quantity<T>, &Y) -> Result<Derivative<Y, T>, String>,
145 y: &Y,
146 t: Quantity<T>,
147 dt: Quantity<T>,
148 k: &mut [Derivative<Y, T>],
149 y_trial: &mut Y,
150 ) -> Result<Scalar, String> {
151 self.slopes_and_error_fsal(function, y, t, dt, k, y_trial)
152 }
153 fn step(
154 &self,
155 _function: impl FnMut(Quantity<T>, &Y) -> Result<Derivative<Y, T>, String>,
156 y: &mut Y,
157 t: &mut Quantity<T>,
158 y_sol: &mut U,
159 t_sol: &mut Times<T>,
160 dydt_sol: &mut V,
161 k_sol: &mut Vec<V>,
162 dt: &mut Quantity<T>,
163 k: &mut [Derivative<Y, T>],
164 y_trial: &Y,
165 e: Scalar,
166 ) -> Result<(), String> {
167 let dt_0 = *dt;
168 self.step_fsal(y, t, y_sol, t_sol, dydt_sol, k_sol, dt, k, y_trial, e)?;
169 if e > 0.0 {
170 let (beta, tol, expn) = (
171 VariableStep::<T>::dt_beta(self),
172 VariableStep::<T>::abs_tol(self),
173 VariableStep::<T>::dt_expn(self),
174 );
175 *dt = dt_0;
176 *dt *= beta * (tol / e).powf(1.0 / expn)
177 }
178 Ok(()) }
180}
181
182impl<Y, U, V, T> VariableStepExplicitFirstSameAsLast<Y, U, V, T> for BogackiShampine
183where
184 Y: Differentiable<T> + Div<Quantity<T>, Output = Derivative<Y, T>> + Tensor,
185 Derivative<Y, T>: Mul<Quantity<T>, Output = Y>,
186 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
187 for<'a> &'a Derivative<Y, T>:
188 Mul<Scalar, Output = Derivative<Y, T>> + Mul<Quantity<T>, Output = Y>,
189 U: TensorVec<Item = Y>,
190 V: TensorVec<Item = Derivative<Y, T>>,
191{
192}
193
194impl<Y, U, V, T> FreeInterpolant<Y, U, V, T> for BogackiShampine
195where
196 Y: Differentiable<T> + Div<Quantity<T>, Output = Derivative<Y, T>> + Tensor,
197 Derivative<Y, T>: Mul<Quantity<T>, Output = Y>,
198 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
199 for<'a> &'a Derivative<Y, T>:
200 Mul<Scalar, Output = Derivative<Y, T>> + Mul<Quantity<T>, Output = Y>,
201 U: TensorVec<Item = Y>,
202 V: TensorVec<Item = Derivative<Y, T>>,
203{
204}
205
206impl<Y, U, V, T> InterpolateSolution<Y, U, V, T> for BogackiShampine
207where
208 Y: Differentiable<T> + Div<Quantity<T>, Output = Derivative<Y, T>> + Tensor,
209 Derivative<Y, T>: Mul<Quantity<T>, Output = Y>,
210 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
211 for<'a> &'a Derivative<Y, T>:
212 Mul<Scalar, Output = Derivative<Y, T>> + Mul<Quantity<T>, Output = Y>,
213 U: TensorVec<Item = Y>,
214 V: TensorVec<Item = Derivative<Y, T>>,
215{
216 fn interpolate(
217 &self,
218 time: &Times<T>,
219 tp: &Times<T>,
220 yp: &U,
221 dydtp: &V,
222 _k_sol: &[V],
223 _function: impl FnMut(Quantity<T>, &Y) -> Result<Derivative<Y, T>, String>,
224 ) -> Result<(U, V), IntegrationError> {
225 Ok(Self::interpolate_free(time, tp, yp, dydtp))
226 }
227}