conspire/math/integrate/ode/explicit/variable_step/internal_variables/
mod.rs1use crate::math::{
2 Scalar, Tensor, TensorVec, Vector, assert_eq_within_tols,
3 integrate::{Explicit, IntegrationError, VariableStep},
4 interpolate::InterpolateSolutionInternalVariables,
5};
6use std::ops::{Mul, Sub};
7
8pub trait VariableStepExplicitInternalVariables<Y, Z, U, V>
10where
11 Self: InterpolateSolutionInternalVariables<Y, Z, U, V> + Explicit<Y, U> + VariableStep,
12 Y: Tensor,
13 Z: Tensor,
14 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
15 U: TensorVec<Item = Y>,
16 V: TensorVec<Item = Z>,
17{
18 fn integrate_and_evaluate_variable_step(
19 &self,
20 mut function: impl FnMut(Scalar, &Y, &Z) -> Result<Y, String>,
21 mut evaluate: impl FnMut(Scalar, &Y, &Z) -> Result<Z, String>,
22 time: &[Scalar],
23 initial_condition: Y,
24 initial_evaluation: Z,
25 ) -> Result<(Vector, U, U, V), IntegrationError> {
26 let t_0 = time[0];
27 let t_f = time[time.len() - 1];
28 if time.len() < 2 {
29 return Err(IntegrationError::LengthTimeLessThanTwo);
30 } else if t_0 >= t_f {
31 return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
32 }
33 let mut t = t_0;
34 let mut dt = t_f - t_0;
35 let mut t_sol = Vector::new();
36 t_sol.push(t_0);
37 let mut y = initial_condition;
38 let mut z = initial_evaluation;
39 if assert_eq_within_tols(&evaluate(t, &y, &z)?, &z).is_err() {
40 return Err(IntegrationError::InconsistentInitialConditions);
41 }
42 let mut k = vec![Y::default(); Self::SLOPES];
43 k[0] = function(t, &y, &z)?;
44 let mut y_sol = U::new();
45 y_sol.push(y.clone());
46 let mut z_sol = V::new();
47 z_sol.push(z.clone());
48 let mut dydt_sol = U::new();
49 dydt_sol.push(k[0].clone());
50 let mut y_trial = Y::default();
51 let mut z_trial = Z::default();
52 while t < t_f {
53 match self.slopes(
54 &mut function,
55 &mut evaluate,
56 &y,
57 &z,
58 t,
59 dt,
60 &mut k,
61 &mut y_trial,
62 &mut z_trial,
63 ) {
64 Ok(e) => {
65 if let Some(error) = self
66 .step(
67 &mut function,
68 &mut y,
69 &mut z,
70 &mut t,
71 &mut y_sol,
72 &mut z_sol,
73 &mut t_sol,
74 &mut dydt_sol,
75 &mut dt,
76 &mut k,
77 &y_trial,
78 &z_trial,
79 e,
80 )
81 .err()
82 {
83 dt *= self.dt_cut();
84 if dt < self.dt_min() {
85 return Err(IntegrationError::MinimumStepSizeUpstream(
86 self.dt_min(),
87 error,
88 format!("{self:?}"),
89 ));
90 }
91 } else {
92 dt = dt.min(t_f - t);
93 if dt < self.dt_min() && t < t_f {
94 return Err(IntegrationError::MinimumStepSizeReached(
95 self.dt_min(),
96 format!("{self:?}"),
97 ));
98 }
99 }
100 }
101 Err(error) => {
102 dt *= self.dt_cut();
103 if dt < self.dt_min() {
104 return Err(IntegrationError::MinimumStepSizeUpstream(
105 self.dt_min(),
106 error,
107 format!("{self:?}"),
108 ));
109 }
110 }
111 }
112 }
113 if time.len() > 2 {
114 let t_int = Vector::from(time);
115 let (y_int, dydt_int, z_int) =
116 self.interpolate(&t_int, &t_sol, &y_sol, &z_sol, function, evaluate)?;
117 Ok((t_int, y_int, dydt_int, z_int))
118 } else {
119 Ok((t_sol, y_sol, dydt_sol, z_sol))
120 }
121 }
122 #[allow(clippy::too_many_arguments)]
123 fn slopes(
124 &self,
125 function: impl FnMut(Scalar, &Y, &Z) -> Result<Y, String>,
126 evaluate: impl FnMut(Scalar, &Y, &Z) -> Result<Z, String>,
127 y: &Y,
128 z: &Z,
129 t: Scalar,
130 dt: Scalar,
131 k: &mut [Y],
132 y_trial: &mut Y,
133 z_trial: &mut Z,
134 ) -> Result<Scalar, String>;
135 #[allow(clippy::too_many_arguments)]
136 fn step(
137 &self,
138 function: impl FnMut(Scalar, &Y, &Z) -> Result<Y, String>,
139 y: &mut Y,
140 z: &mut Z,
141 t: &mut Scalar,
142 y_sol: &mut U,
143 z_sol: &mut V,
144 t_sol: &mut Vector,
145 dydt_sol: &mut U,
146 dt: &mut Scalar,
147 k: &mut [Y],
148 y_trial: &Y,
149 z_trial: &Z,
150 e: Scalar,
151 ) -> Result<(), String>;
152}