1use numra_core::{LinalgError, NumraError};
8use thiserror::Error;
9
10#[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
61impl From<SolverError> for NumraError {
62 fn from(e: SolverError) -> Self {
63 NumraError::Ode(e.to_string())
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_error_display() {
73 let err = SolverError::DimensionMismatch {
74 expected: 3,
75 actual: 5,
76 };
77 assert!(err.to_string().contains("3"));
78 assert!(err.to_string().contains("5"));
79 }
80
81 #[test]
82 fn test_error_from_string() {
83 let err = SolverError::from("custom error");
84 matches!(err, SolverError::Other(_));
85 }
86}