conspire/math/integrate/
mod.rs

1#[cfg(feature = "doc")]
2pub mod doc;
3
4#[cfg(test)]
5mod test;
6
7mod dae;
8mod ode;
9
10pub use dae::{
11    ExplicitDaeFirstOrderMinimize, ExplicitDaeFirstOrderRoot, ExplicitDaeSecondOrderMinimize,
12    ExplicitDaeZerothOrderRoot, ImplicitDaeFirstOrderMinimize, ImplicitDaeFirstOrderRoot,
13    ImplicitDaeSecondOrderMinimize, ImplicitDaeZerothOrderRoot,
14    explicit::variable_step::{
15        explicit::{
16            ExplicitDaeVariableStepExplicit, ExplicitDaeVariableStepExplicitFirstOrderMinimize,
17            ExplicitDaeVariableStepExplicitFirstOrderRoot,
18            ExplicitDaeVariableStepExplicitSecondOrderMinimize,
19            ExplicitDaeVariableStepExplicitZerothOrderRoot, ExplicitDaeVariableStepFirstSameAsLast,
20        },
21        implicit::{
22            ImplicitDaeVariableStepExplicit, ImplicitDaeVariableStepExplicitFirstOrderMinimize,
23            ImplicitDaeVariableStepExplicitFirstOrderRoot,
24            ImplicitDaeVariableStepExplicitSecondOrderMinimize,
25            ImplicitDaeVariableStepExplicitZerothOrderRoot,
26        },
27    },
28};
29pub use ode::{
30    FixedStep, OdeIntegrator, VariableStep,
31    explicit::{
32        Explicit,
33        fixed_step::{
34            FixedStepExplicit, bogacki_shampine::BogackiShampine as BogackiShampineFixedStep,
35            dormand_prince::DormandPrince as DormandPrinceFixedStep, euler::Euler, heun::Heun,
36            midpoint::Midpoint, ralston::Ralston, verner_8::Verner8 as Verner8FixedStep,
37            verner_9::Verner9 as Verner9FixedStep,
38        },
39        variable_step::{
40            VariableStepExplicit,
41            VariableStepExplicitFirstSameAsLast,
42            bogacki_shampine::BogackiShampine,
43            dormand_prince::DormandPrince,
44            // heun_euler::HeunEuler,
45            // midpoint_euler::MidpointEuler,
46            // ralston_euler::RalstonEuler,
47            verner_8::Verner8,
48            verner_9::Verner9,
49        },
50    },
51    implicit::{
52        ImplicitFirstOrder, ImplicitZerothOrder, backward_euler::BackwardEuler,
53        midpoint::Midpoint as ImplicitMidpoint, trapezoidal::Trapezoidal,
54    },
55};
56
57/// Alias for [`Euler`].
58pub type Ode1 = Euler;
59
60/// Alias for [`BackwardEuler`].
61pub type Ode1be = BackwardEuler;
62
63// /// Alias for [`HeunEuler`].
64// pub type Ode12 = HeunEuler;
65
66/// Alias for [`Heun`].
67pub type Ode2 = Heun;
68
69/// Alias for [`BogackiShampine`].
70pub type Ode23 = BogackiShampine;
71
72/// Alias for [`BogackiShampineFixedStep`].
73pub type Ode3 = BogackiShampineFixedStep;
74
75/// Alias for [`DormandPrince`].
76pub type Ode45 = DormandPrince;
77
78/// Alias for [`DormandPrinceFixedStep`].
79pub type Ode5 = DormandPrinceFixedStep;
80
81/// Alias for [`Verner8`].
82pub type Ode78 = Verner8;
83
84/// Alias for [`Verner8FixedStep`].
85pub type Ode8 = Verner8FixedStep;
86
87/// Alias for [`Verner9`].
88pub type Ode89 = Verner9;
89
90/// Alias for [`Verner9FixedStep`].
91pub type Ode9 = Verner9FixedStep;
92
93use crate::{
94    defeat_message,
95    math::{Scalar, TestError},
96};
97use std::fmt::{self, Debug, Display, Formatter};
98
99/// Possible errors encountered when integrating.
100pub enum IntegrationError {
101    InconsistentInitialConditions,
102    InitialTimeNotLessThanFinalTime,
103    Intermediate(String),
104    LengthTimeLessThanTwo,
105    MinimumStepSizeReached(Scalar, String),
106    MinimumStepSizeUpstream(Scalar, String, String),
107    TimeStepNotSet(Scalar, Scalar, String),
108    Upstream(String, String),
109}
110
111impl From<String> for IntegrationError {
112    fn from(error: String) -> Self {
113        Self::Intermediate(error)
114    }
115}
116
117impl Debug for IntegrationError {
118    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
119        let error = match self {
120            Self::InconsistentInitialConditions => {
121                "\x1b[1;91mThe initial condition z_0 is not consistent with g(t_0, y_0)."
122                    .to_string()
123            }
124            Self::InitialTimeNotLessThanFinalTime => {
125                "\x1b[1;91mThe initial time must precede the final time.".to_string()
126            }
127            Self::Intermediate(message) => message.to_string(),
128            Self::LengthTimeLessThanTwo => {
129                "\x1b[1;91mThe time must contain at least two entries.".to_string()
130            }
131            Self::MinimumStepSizeReached(dt_min, integrator) => {
132                format!(
133                    "\x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
134                    In integrator: {integrator}."
135                )
136            }
137            Self::MinimumStepSizeUpstream(dt_min, error, integrator) => {
138                format!(
139                    "{error}\x1b[0;91m\n\
140                    Causing error: \x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
141                    In integrator: {integrator}."
142                )
143            }
144            Self::TimeStepNotSet(t0, tf, integrator) => {
145                format!(
146                    "\x1b[1;91mA positive time step must be set within [{t0:?}, {tf:?}].\x1b[0;91m\n\
147                    In integrator: {integrator}."
148                )
149            }
150            Self::Upstream(error, integrator) => {
151                format!(
152                    "{error}\x1b[0;91m\n\
153                    In integrator: {integrator}."
154                )
155            }
156        };
157        write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
158    }
159}
160
161impl Display for IntegrationError {
162    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
163        let error = match self {
164            Self::InconsistentInitialConditions => {
165                "\x1b[1;91mThe initial condition z_0 is not consistent with g(t_0, y_0)."
166                    .to_string()
167            }
168            Self::InitialTimeNotLessThanFinalTime => {
169                "\x1b[1;91mThe initial time must precede the final time.".to_string()
170            }
171            Self::Intermediate(message) => message.to_string(),
172            Self::LengthTimeLessThanTwo => {
173                "\x1b[1;91mThe time must contain at least two entries.".to_string()
174            }
175            Self::MinimumStepSizeReached(dt_min, integrator) => {
176                format!(
177                    "\x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
178                    In integrator: {integrator}."
179                )
180            }
181            Self::MinimumStepSizeUpstream(dt_min, error, integrator) => {
182                format!(
183                    "{error}\x1b[0;91m\n\
184                    Causing error: \x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
185                    In integrator: {integrator}."
186                )
187            }
188            Self::TimeStepNotSet(t0, tf, integrator) => {
189                format!(
190                    "\x1b[1;91mA positive time step must be set within [{t0:?}, {tf:?}].\x1b[0;91m\n\
191                    In integrator: {integrator}."
192                )
193            }
194            Self::Upstream(error, integrator) => {
195                format!(
196                    "{error}\x1b[0;91m\n\
197                    In integrator: {integrator}."
198                )
199            }
200        };
201        write!(f, "{error}\x1b[0m")
202    }
203}
204
205impl From<IntegrationError> for String {
206    fn from(error: IntegrationError) -> Self {
207        format!("{}", error)
208    }
209}
210
211impl From<IntegrationError> for TestError {
212    fn from(error: IntegrationError) -> Self {
213        TestError {
214            message: error.to_string(),
215        }
216    }
217}