Skip to main content

neural_dynamics/
error.rs

1//! Error types for neural dynamics library.
2
3use thiserror::Error;
4
5/// Result type for neural dynamics operations.
6pub type Result<T> = std::result::Result<T, NeuralDynamicsError>;
7
8/// Errors that can occur in neural dynamics simulations.
9#[derive(Error, Debug, Clone)]
10pub enum NeuralDynamicsError {
11    /// Invalid parameter value
12    #[error("Invalid parameter {parameter}: {reason} (value: {value})")]
13    InvalidParameter {
14        parameter: String,
15        value: f64,
16        reason: String,
17    },
18
19    /// Invalid neuron index
20    #[error("Invalid neuron index {index} (max: {max})")]
21    InvalidNeuronIndex { index: usize, max: usize },
22
23    /// Invalid population index
24    #[error("Invalid population index {index} (max: {max})")]
25    InvalidPopulationIndex { index: usize, max: usize },
26
27    /// Invalid projection index
28    #[error("Invalid projection index {index} (max: {max})")]
29    InvalidProjectionIndex { index: usize, max: usize },
30
31    /// Population size mismatch
32    #[error("Population size mismatch: expected {expected}, got {actual}")]
33    SizeMismatch { expected: usize, actual: usize },
34
35    /// Empty population
36    #[error("Population is empty")]
37    EmptyPopulation,
38
39    /// Empty network
40    #[error("Network is empty (no populations)")]
41    EmptyNetwork,
42
43    /// Connectivity error
44    #[error("Connectivity error: {reason}")]
45    ConnectivityError { reason: String },
46
47    /// Simulation error
48    #[error("Simulation error: {reason}")]
49    SimulationError { reason: String },
50
51    /// Non-finite value encountered
52    #[error("Non-finite value encountered in {location}: {value}")]
53    NonFiniteValue { location: String, value: f64 },
54
55    /// Integration error
56    #[error("Integration error: {reason}")]
57    IntegrationError { reason: String },
58
59    /// Recording error
60    #[error("Recording error: {reason}")]
61    RecordingError { reason: String },
62
63    /// Analysis error
64    #[error("Analysis error: {reason}")]
65    AnalysisError { reason: String },
66
67    /// IO error
68    #[error("IO error: {0}")]
69    IoError(String),
70
71    /// Propagated error from hodgkin-huxley
72    #[error("Hodgkin-Huxley error: {0}")]
73    HodgkinHuxleyError(String),
74
75    /// Propagated error from synapse-models
76    #[error("Synapse error: {0}")]
77    SynapseError(String),
78}
79
80impl From<hodgkin_huxley::error::HHError> for NeuralDynamicsError {
81    fn from(err: hodgkin_huxley::error::HHError) -> Self {
82        NeuralDynamicsError::HodgkinHuxleyError(err.to_string())
83    }
84}
85
86impl From<synapse_models::error::SynapseError> for NeuralDynamicsError {
87    fn from(err: synapse_models::error::SynapseError) -> Self {
88        NeuralDynamicsError::SynapseError(err.to_string())
89    }
90}
91
92impl From<std::io::Error> for NeuralDynamicsError {
93    fn from(err: std::io::Error) -> Self {
94        NeuralDynamicsError::IoError(err.to_string())
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_error_display() {
104        let err = NeuralDynamicsError::InvalidParameter {
105            parameter: "weight".to_string(),
106            value: -1.0,
107            reason: "must be non-negative".to_string(),
108        };
109        assert!(err.to_string().contains("Invalid parameter"));
110        assert!(err.to_string().contains("weight"));
111    }
112
113    #[test]
114    fn test_error_conversions() {
115        let hh_err = hodgkin_huxley::error::HHError::InvalidParameter {
116            parameter: "c_m".to_string(),
117            value: -1.0,
118            reason: "negative".to_string(),
119        };
120        let nd_err: NeuralDynamicsError = hh_err.into();
121        assert!(matches!(nd_err, NeuralDynamicsError::HodgkinHuxleyError(_)));
122    }
123}