Skip to main content

differential_equations/
error.rs

1//! Errors for Differential Equations Crate
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6use std::fmt::{Debug, Display};
7
8use crate::traits::{Real, State};
9
10/// Error for Differential Equations Crate
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[derive(PartialEq, Clone)]
13pub enum Error<T, Y>
14where
15    T: Real,
16    Y: State<T>,
17{
18    /// NumericalMethod input was bad
19    BadInput { msg: String },
20
21    /// Maximum steps reached
22    MaxSteps { t: T, y: Y },
23
24    /// Step size became too small
25    StepSize { t: T, y: Y },
26
27    /// Stiffness detected
28    Stiffness { t: T, y: Y },
29
30    /// Out of bounds error
31    OutOfBounds { t_interp: T, t_prev: T, t_curr: T },
32
33    /// DDE requires at least one lag (L > 0)
34    NoLags,
35
36    /// Not enough history retained to evaluate a delayed state
37    InsufficientHistory { t_delayed: T, t_prev: T, t_curr: T },
38
39    /// General linear algebra error
40    LinearAlgebra { t: T, y: Y, msg: String },
41}
42
43impl<T, Y> Display for Error<T, Y>
44where
45    T: Real + Display,
46    Y: State<T> + Display,
47{
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        match self {
50            Self::BadInput { msg } => write!(
51                f,
52                "Bad input: {}. Check your problem definition, dimensions, and solver options.",
53                msg
54            ),
55            Self::MaxSteps { t, y } => {
56                write!(
57                    f,
58                    "Maximum step count reached at (t, y) = ({}, {}). Try increasing max_steps, relaxing tolerances, or shortening the integration interval.",
59                    t, y
60                )
61            }
62            Self::StepSize { t, y } => write!(
63                f,
64                "Step size became too small at (t, y) = ({}, {}). This often indicates stiffness or overly tight tolerances. Consider using a stiff solver (DIRK/IRK), relaxing rtol/atol, or rescaling the problem.",
65                t, y
66            ),
67            Self::Stiffness { t, y } => write!(
68                f,
69                "Stiffness detected at (t, y) = ({}, {}). Switch to a stiff method (e.g., DIRK or IRK) or relax tolerances to improve stability.",
70                t, y
71            ),
72            Self::OutOfBounds {
73                t_interp,
74                t_prev,
75                t_curr,
76            } => {
77                write!(
78                    f,
79                    "Interpolation error: requested t_interp {} is outside the last step: [t_prev {}, t_curr {}]. Dense output is only valid within a completed step; request t within this interval or use t_eval to sample during integration.",
80                    t_interp, t_prev, t_curr
81                )
82            }
83            Self::NoLags => write!(
84                f,
85                "Invalid DDE configuration: number of lags L must be > 0. If there are no delays, use an ODE solver instead."
86            ),
87            Self::InsufficientHistory {
88                t_delayed,
89                t_prev,
90                t_curr,
91            } => {
92                write!(
93                    f,
94                    "Insufficient history to interpolate at delayed time {} (window: [t_prev {}, t_curr {}]). Possible causes: max_delay is too small or history pruning is too aggressive, or steps advanced before enough history accumulated. Consider increasing max_delay, providing a longer initial history, or reducing maximum step size.",
95                    t_delayed, t_prev, t_curr
96                )
97            }
98            Self::LinearAlgebra { t, y, msg } => write!(
99                f,
100                "Linear algebra error at (t, y) = ({}, {}): {}",
101                t, y, msg
102            ),
103        }
104    }
105}
106
107impl<T, Y> Debug for Error<T, Y>
108where
109    T: Real + Debug,
110    Y: State<T> + Debug,
111{
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        match self {
114            Self::BadInput { msg } => write!(
115                f,
116                "Bad input: {}. Check your problem definition, dimensions, and solver options.",
117                msg
118            ),
119            Self::MaxSteps { t, y } => {
120                write!(
121                    f,
122                    "Maximum step count reached at (t, y) = ({:?}, {:?}). Try increasing max_steps, relaxing tolerances, or shortening the integration interval.",
123                    t, y
124                )
125            }
126            Self::StepSize { t, y } => {
127                write!(
128                    f,
129                    "Step size became too small at (t, y) = ({:?}, {:?}). This often indicates stiffness or overly tight tolerances. Consider using a stiff solver (DIRK/IRK), relaxing rtol/atol, or rescaling the problem.",
130                    t, y
131                )
132            }
133            Self::Stiffness { t, y } => {
134                write!(
135                    f,
136                    "Stiffness detected at (t, y) = ({:?}, {:?}). Switch to a stiff method (e.g., DIRK or IRK) or relax tolerances to improve stability.",
137                    t, y
138                )
139            }
140            Self::OutOfBounds {
141                t_interp,
142                t_prev,
143                t_curr,
144            } => {
145                write!(
146                    f,
147                    "Interpolation error: requested t_interp {:?} is outside the last step: [t_prev {:?}, t_curr {:?}]. Dense output is only valid within a completed step; request t within this interval or use t_eval to sample during integration.",
148                    t_interp, t_prev, t_curr
149                )
150            }
151            Self::NoLags => write!(
152                f,
153                "Invalid DDE configuration: number of lags L must be > 0. If there are no delays, use an ODE solver instead."
154            ),
155            Self::InsufficientHistory {
156                t_delayed,
157                t_prev,
158                t_curr,
159            } => {
160                write!(
161                    f,
162                    "Insufficient history to interpolate at delayed time {:?} (window: [t_prev {:?}, t_curr {:?}]). Possible causes: max_delay is too small or history pruning is too aggressive, or steps advanced before enough history accumulated. Consider increasing max_delay, providing a longer initial history, or reducing maximum step size.",
163                    t_delayed, t_prev, t_curr
164                )
165            }
166            Self::LinearAlgebra { t, y, msg } => write!(
167                f,
168                "Linear algebra error at (t, y) = ({:?}, {:?}): {}",
169                t, y, msg
170            ),
171        }
172    }
173}
174
175impl<T, Y> std::error::Error for Error<T, Y>
176where
177    T: Real + Debug + Display,
178    Y: State<T> + Debug + Display,
179{
180}