Skip to main content

numra_ode/
error.rs

1//! Error types for ODE solvers.
2//!
3//! Author: Moussa Leblouba
4//! Date: 8 February 2026
5//! Modified: 2 May 2026
6
7use numra_core::LinalgError;
8use thiserror::Error;
9
10/// Errors that can occur during ODE solving.
11#[derive(Debug, Error)]
12pub enum SolverError {
13    #[error("dimension mismatch: expected {expected}, got {actual}")]
14    DimensionMismatch { expected: usize, actual: usize },
15
16    #[error("step size too small at t = {t}: h = {h} < h_min = {h_min}")]
17    StepSizeTooSmall { t: f64, h: f64, h_min: f64 },
18
19    #[error("maximum iterations exceeded at t = {t}")]
20    MaxIterationsExceeded { t: f64 },
21
22    #[error("Newton iteration failed to converge at t = {t}")]
23    NewtonConvergenceFailed { t: f64 },
24
25    #[error("singular mass matrix detected")]
26    SingularMassMatrix,
27
28    #[error("inconsistent initial conditions for DAE")]
29    InconsistentInitialConditions,
30
31    #[error("LU factorization failed")]
32    LuFactorizationFailed,
33
34    #[error("{0}")]
35    Other(String),
36}
37
38impl From<String> for SolverError {
39    fn from(s: String) -> Self {
40        SolverError::Other(s)
41    }
42}
43
44impl From<&str> for SolverError {
45    fn from(s: &str) -> Self {
46        SolverError::Other(s.to_string())
47    }
48}
49
50impl From<LinalgError> for SolverError {
51    fn from(e: LinalgError) -> Self {
52        match e {
53            LinalgError::Singular { .. }
54            | LinalgError::NotSquare { .. }
55            | LinalgError::NotPositiveDefinite => SolverError::LuFactorizationFailed,
56            _ => SolverError::Other(e.to_string()),
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_error_display() {
67        let err = SolverError::DimensionMismatch {
68            expected: 3,
69            actual: 5,
70        };
71        assert!(err.to_string().contains("3"));
72        assert!(err.to_string().contains("5"));
73    }
74
75    #[test]
76    fn test_error_from_string() {
77        let err = SolverError::from("custom error");
78        matches!(err, SolverError::Other(_));
79    }
80}