conspire/math/integrate/backward_euler/
mod.rs1#[cfg(test)]
2mod test;
3
4use super::{
5 super::{
6 Hessian, Jacobian, Scalar, Solution, TensorArray, TensorVec, Vector,
7 interpolate::InterpolateSolution,
8 optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
9 },
10 ImplicitFirstOrder, ImplicitZerothOrder, IntegrationError,
11};
12use std::{
13 fmt::Debug,
14 ops::{Div, Mul, Sub},
15};
16
17#[derive(Debug, Default)]
21pub struct BackwardEuler {}
22
23impl<Y, U> ImplicitZerothOrder<Y, U> for BackwardEuler
24where
25 Self: InterpolateSolution<Y, U>,
26 Y: Solution,
27 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
28 U: TensorVec<Item = Y>,
29 Vector: From<Y>,
30{
31 fn integrate(
32 &self,
33 function: impl Fn(Scalar, &Y) -> Result<Y, IntegrationError>,
34 time: &[Scalar],
35 initial_condition: Y,
36 solver: impl ZerothOrderRootFinding<Y>,
37 ) -> Result<(Vector, U, U), IntegrationError> {
38 let t_0 = time[0];
39 let t_f = time[time.len() - 1];
40 if time.len() < 2 {
41 return Err(IntegrationError::LengthTimeLessThanTwo);
42 } else if t_0 >= t_f {
43 return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
44 }
45 let mut index = 0;
46 let mut t = t_0;
47 let mut dt;
48 let mut t_sol = Vector::zero(0);
49 t_sol.push(t_0);
50 let mut t_trial;
51 let mut y = initial_condition.clone();
52 let mut y_sol = U::zero(0);
53 y_sol.push(initial_condition.clone());
54 let mut dydt_sol = U::zero(0);
55 dydt_sol.push(function(t, &y.clone())?);
56 let mut y_trial;
57 while t < t_f {
58 t_trial = time[index + 1];
59 dt = t_trial - t;
60 y_trial = match solver.root(
61 |y_trial: &Y| Ok(y_trial - &y - &(&function(t_trial, y_trial)? * dt)),
62 y.clone(),
63 EqualityConstraint::None,
64 ) {
65 Ok(solution) => solution,
66 Err(error) => {
67 return Err(IntegrationError::Upstream(
68 format!("{error:?}"),
69 format!("{self:?}"),
70 ));
71 }
72 };
73 t = t_trial;
74 y = y_trial;
75 t_sol.push(t);
76 y_sol.push(y.clone());
77 dydt_sol.push(function(t, &y)?);
78 index += 1;
79 }
80 Ok((t_sol, y_sol, dydt_sol))
81 }
82}
83
84impl<Y, J, U> ImplicitFirstOrder<Y, J, U> for BackwardEuler
85where
86 Self: InterpolateSolution<Y, U>,
87 Y: Jacobian + Solution + Div<J, Output = Y>,
88 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
89 J: Hessian + TensorArray,
90 U: TensorVec<Item = Y>,
91 Vector: From<Y>,
92{
93 fn integrate(
94 &self,
95 function: impl Fn(Scalar, &Y) -> Result<Y, IntegrationError>,
96 jacobian: impl Fn(Scalar, &Y) -> Result<J, IntegrationError>,
97 time: &[Scalar],
98 initial_condition: Y,
99 solver: impl FirstOrderRootFinding<Y, J, Y>,
100 ) -> Result<(Vector, U, U), IntegrationError> {
101 let t_0 = time[0];
102 let t_f = time[time.len() - 1];
103 if time.len() < 2 {
104 return Err(IntegrationError::LengthTimeLessThanTwo);
105 } else if t_0 >= t_f {
106 return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
107 }
108 let mut index = 0;
109 let mut t = t_0;
110 let mut dt;
111 let identity = J::identity();
112 let mut t_sol = Vector::zero(0);
113 t_sol.push(t_0);
114 let mut t_trial;
115 let mut y = initial_condition.clone();
116 let mut y_sol = U::zero(0);
117 y_sol.push(initial_condition.clone());
118 let mut dydt_sol = U::zero(0);
119 dydt_sol.push(function(t, &y.clone())?);
120 let mut y_trial;
121 while t < t_f {
122 t_trial = time[index + 1];
123 dt = t_trial - t;
124 y_trial = match solver.root(
125 |y_trial: &Y| Ok(y_trial - &y - &(&function(t_trial, y_trial)? * dt)),
126 |y_trial: &Y| Ok(jacobian(t_trial, y_trial)? * -dt + &identity),
127 y.clone(),
128 EqualityConstraint::None,
129 ) {
130 Ok(solution) => solution,
131 Err(error) => {
132 return Err(IntegrationError::Upstream(
133 format!("{error:?}"),
134 format!("{self:?}"),
135 ));
136 }
137 };
138 t = t_trial;
139 y = y_trial;
140 t_sol.push(t);
141 y_sol.push(y.clone());
142 dydt_sol.push(function(t, &y)?);
143 index += 1;
144 }
145 Ok((t_sol, y_sol, dydt_sol))
146 }
147}
148
149impl<Y, U> InterpolateSolution<Y, U> for BackwardEuler
150where
151 Y: Jacobian + Solution + TensorArray,
152 for<'a> &'a Y: Mul<Scalar, Output = Y> + Sub<&'a Y, Output = Y>,
153 U: TensorVec<Item = Y>,
154 Vector: From<Y>,
155{
156 fn interpolate(
157 &self,
158 _time: &Vector,
159 _tp: &Vector,
160 _yp: &U,
161 mut _function: impl FnMut(Scalar, &Y) -> Result<Y, String>,
162 ) -> Result<(U, U), IntegrationError> {
163 unimplemented!()
164 }
165}