1use numra_core::LinalgError;
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
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}