#[cfg(feature = "doc")]
pub mod doc;
#[cfg(test)]
mod test;
mod dae;
mod ode;
pub use dae::{
ExplicitDaeFirstOrderMinimize, ExplicitDaeFirstOrderRoot, ExplicitDaeSecondOrderMinimize,
ExplicitDaeZerothOrderRoot, ImplicitDaeFirstOrderMinimize, ImplicitDaeFirstOrderRoot,
ImplicitDaeSecondOrderMinimize, ImplicitDaeZerothOrderRoot,
explicit::variable_step::{
explicit::{
ExplicitDaeVariableStepExplicit, ExplicitDaeVariableStepExplicitFirstOrderMinimize,
ExplicitDaeVariableStepExplicitFirstOrderRoot,
ExplicitDaeVariableStepExplicitSecondOrderMinimize,
ExplicitDaeVariableStepExplicitZerothOrderRoot, ExplicitDaeVariableStepFirstSameAsLast,
},
implicit::{
ImplicitDaeVariableStepExplicit, ImplicitDaeVariableStepExplicitFirstOrderMinimize,
ImplicitDaeVariableStepExplicitFirstOrderRoot,
ImplicitDaeVariableStepExplicitSecondOrderMinimize,
ImplicitDaeVariableStepExplicitZerothOrderRoot,
},
},
};
pub use ode::{
FixedStep, OdeIntegrator, VariableStep,
explicit::{
Explicit,
fixed_step::{
FixedStepExplicit, bogacki_shampine::BogackiShampine as BogackiShampineFixedStep,
dormand_prince::DormandPrince as DormandPrinceFixedStep, euler::Euler, heun::Heun,
midpoint::Midpoint, ralston::Ralston, verner_8::Verner8 as Verner8FixedStep,
verner_9::Verner9 as Verner9FixedStep,
},
variable_step::{
VariableStepExplicit,
VariableStepExplicitFirstSameAsLast,
bogacki_shampine::BogackiShampine,
dormand_prince::DormandPrince,
verner_8::Verner8,
verner_9::Verner9,
},
},
implicit::{
ImplicitFirstOrder, ImplicitZerothOrder, backward_euler::BackwardEuler,
midpoint::Midpoint as ImplicitMidpoint, trapezoidal::Trapezoidal,
},
};
pub type Ode1 = Euler;
pub type Ode1be = BackwardEuler;
pub type Ode2 = Heun;
pub type Ode23 = BogackiShampine;
pub type Ode3 = BogackiShampineFixedStep;
pub type Ode45 = DormandPrince;
pub type Ode5 = DormandPrinceFixedStep;
pub type Ode78 = Verner8;
pub type Ode8 = Verner8FixedStep;
pub type Ode89 = Verner9;
pub type Ode9 = Verner9FixedStep;
use crate::{
defeat_message,
math::{Scalar, TestError},
};
use std::fmt::{self, Debug, Display, Formatter};
pub enum IntegrationError {
InconsistentInitialConditions,
InitialTimeNotLessThanFinalTime,
Intermediate(String),
LengthTimeLessThanTwo,
MinimumStepSizeReached(Scalar, String),
MinimumStepSizeUpstream(Scalar, String, String),
TimeStepNotSet(Scalar, Scalar, String),
Upstream(String, String),
}
impl From<String> for IntegrationError {
fn from(error: String) -> Self {
Self::Intermediate(error)
}
}
impl Debug for IntegrationError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error = match self {
Self::InconsistentInitialConditions => {
"\x1b[1;91mThe initial condition z_0 is not consistent with g(t_0, y_0)."
.to_string()
}
Self::InitialTimeNotLessThanFinalTime => {
"\x1b[1;91mThe initial time must precede the final time.".to_string()
}
Self::Intermediate(message) => message.to_string(),
Self::LengthTimeLessThanTwo => {
"\x1b[1;91mThe time must contain at least two entries.".to_string()
}
Self::MinimumStepSizeReached(dt_min, integrator) => {
format!(
"\x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
In integrator: {integrator}."
)
}
Self::MinimumStepSizeUpstream(dt_min, error, integrator) => {
format!(
"{error}\x1b[0;91m\n\
Causing error: \x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
In integrator: {integrator}."
)
}
Self::TimeStepNotSet(t0, tf, integrator) => {
format!(
"\x1b[1;91mA positive time step must be set within [{t0:?}, {tf:?}].\x1b[0;91m\n\
In integrator: {integrator}."
)
}
Self::Upstream(error, integrator) => {
format!(
"{error}\x1b[0;91m\n\
In integrator: {integrator}."
)
}
};
write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
}
}
impl Display for IntegrationError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error = match self {
Self::InconsistentInitialConditions => {
"\x1b[1;91mThe initial condition z_0 is not consistent with g(t_0, y_0)."
.to_string()
}
Self::InitialTimeNotLessThanFinalTime => {
"\x1b[1;91mThe initial time must precede the final time.".to_string()
}
Self::Intermediate(message) => message.to_string(),
Self::LengthTimeLessThanTwo => {
"\x1b[1;91mThe time must contain at least two entries.".to_string()
}
Self::MinimumStepSizeReached(dt_min, integrator) => {
format!(
"\x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
In integrator: {integrator}."
)
}
Self::MinimumStepSizeUpstream(dt_min, error, integrator) => {
format!(
"{error}\x1b[0;91m\n\
Causing error: \x1b[1;91mMinimum time step ({dt_min:?}) reached.\x1b[0;91m\n\
In integrator: {integrator}."
)
}
Self::TimeStepNotSet(t0, tf, integrator) => {
format!(
"\x1b[1;91mA positive time step must be set within [{t0:?}, {tf:?}].\x1b[0;91m\n\
In integrator: {integrator}."
)
}
Self::Upstream(error, integrator) => {
format!(
"{error}\x1b[0;91m\n\
In integrator: {integrator}."
)
}
};
write!(f, "{error}\x1b[0m")
}
}
impl From<IntegrationError> for String {
fn from(error: IntegrationError) -> Self {
format!("{}", error)
}
}
impl From<IntegrationError> for TestError {
fn from(error: IntegrationError) -> Self {
TestError {
message: error.to_string(),
}
}
}