//! Error handling for RTX Science //! //! Provides comprehensive error types for scientific computing operations, //! physics simulations, and domain-specific applications. use thiserror::Error; /// Result type alias for RTX Science operations pub type Result = std::result::Result; /// Comprehensive error types for scientific computing operations #[derive(Error, Debug)] pub enum ScienceError { /// Tensor operation errors #[error("Tensor error: {0}")] Tensor(#[from] crate::TensorError), /// Autograd computation errors #[error("Autograd error: {0}")] Autograd(#[from] crate::AutogradError), /// Physics simulation errors #[error("Physics simulation error: {message}")] Physics { /// Error message message: String, /// Physics domain context domain: PhysicsDomain, }, /// Numerical computation errors #[error("Numerical error: {message} (method: {method})")] Numerical { /// Error description message: String, /// Numerical method that failed method: String, /// Convergence information if applicable convergence_info: Option, }, /// Chemistry-specific errors #[cfg(feature = "chemistry")] #[error("Chemistry error: {message}")] Chemistry { /// Error message message: String, /// Molecular context if available molecule_context: Option, }, /// Biology-specific errors #[cfg(feature = "biology")] #[error("Biology error: {message}")] Biology { /// Error message message: String, /// Biological context bio_context: BiologyContext, }, /// Materials science errors #[cfg(feature = "materials")] #[error("Materials science error: {message}")] Materials { /// Error message message: String, /// Material system context material_system: Option, }, /// Scientific data validation errors #[error("Data validation error: {message}")] DataValidation { /// Error message message: String, /// Field that failed validation field: String, /// Expected range or constraint expected: String, /// Actual value received actual: String, }, /// Conservation law violation errors #[error("Conservation law violation: {law} (error: {magnitude:.2e})")] ConservationViolation { /// Conservation law that was violated law: ConservationLaw, /// Magnitude of the violation magnitude: f64, /// Tolerance that was exceeded tolerance: f64, }, /// Boundary condition specification errors #[error("Boundary condition error: {message}")] BoundaryCondition { /// Error message message: String, /// Boundary type boundary_type: BoundaryType, }, /// Convergence failure errors #[error("Convergence failure: {algorithm} failed to converge after {iterations} iterations")] ConvergenceFailure { /// Algorithm that failed to converge algorithm: String, /// Number of iterations attempted iterations: usize, /// Final residual or error measure final_residual: f64, /// Target tolerance tolerance: f64, }, /// Invalid physics model parameters #[error( "Invalid model parameters: {parameter} = {value} is outside valid range [{min}, {max}]" )] InvalidParameters { /// Parameter name parameter: String, /// Invalid value value: f64, /// Minimum valid value min: f64, /// Maximum valid value max: f64, }, /// GPU/CUDA computation errors #[error("GPU computation error: {message}")] GpuComputation { /// Error message message: String, /// CUDA device ID if applicable device_id: Option, }, /// Distributed computing errors #[cfg(feature = "distributed-sci")] #[error("Distributed computing error: {message}")] DistributedComputing { /// Error message message: String, /// Node/rank information node_info: Option, }, /// I/O errors for scientific data #[error("I/O error: {0}")] Io(#[from] std::io::Error), /// Serialization/deserialization errors #[error("Serialization error: {0}")] Serialization(#[from] serde_json::Error), /// Generic anyhow errors for complex cases #[error(transparent)] Other(#[from] anyhow::Error), } /// Physics domain context for error reporting #[derive(Debug, Clone)] pub enum PhysicsDomain { /// Fluid dynamics FluidDynamics, /// Heat transfer HeatTransfer, /// Electromagnetics Electromagnetics, /// Quantum mechanics QuantumMechanics, /// Molecular dynamics MolecularDynamics, /// Continuum mechanics ContinuumMechanics, /// Statistical mechanics StatisticalMechanics, /// Thermodynamics Thermodynamics, } /// Conservation laws that can be violated #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConservationLaw { /// Conservation of mass Mass, /// Conservation of momentum Momentum, /// Conservation of energy Energy, /// Conservation of angular momentum AngularMomentum, /// Conservation of charge Charge, /// Conservation of probability (quantum) Probability, } /// Boundary condition types #[derive(Debug, Clone)] pub enum BoundaryType { /// Dirichlet (fixed value) Dirichlet, /// Neumann (fixed derivative) Neumann, /// Robin (mixed) Robin, /// Periodic Periodic, /// No-slip NoSlip, /// Free-slip FreeSlip, } /// Convergence information for numerical methods #[derive(Debug, Clone)] pub struct ConvergenceInfo { /// Number of iterations completed pub iterations: usize, /// Final residual or error norm pub final_residual: f64, /// Target tolerance pub tolerance: f64, /// Convergence rate if computed pub convergence_rate: Option, /// Additional diagnostic information pub diagnostics: Vec, } /// Biology-specific context for errors #[cfg(feature = "biology")] #[derive(Debug, Clone)] pub enum BiologyContext { /// Protein structure ProteinStructure, /// DNA/RNA sequence NucleicAcid, /// Metabolic pathway MetabolicPathway, /// Gene expression GeneExpression, /// Cell signaling CellSignaling, /// Population dynamics PopulationDynamics, } impl ScienceError { /// Create a physics error with domain context pub fn physics(message: impl Into, domain: PhysicsDomain) -> Self { Self::Physics { message: message.into(), domain, } } /// Create a numerical error with method context pub fn numerical( message: impl Into, method: impl Into, convergence_info: Option, ) -> Self { Self::Numerical { message: message.into(), method: method.into(), convergence_info, } } /// Create a chemistry error with molecular context #[cfg(feature = "chemistry")] pub fn chemistry(message: impl Into, molecule_context: Option) -> Self { Self::Chemistry { message: message.into(), molecule_context, } } /// Create a biology error with biological context #[cfg(feature = "biology")] pub fn biology(message: impl Into, bio_context: BiologyContext) -> Self { Self::Biology { message: message.into(), bio_context, } } /// Create a materials science error #[cfg(feature = "materials")] pub fn materials(message: impl Into, material_system: Option) -> Self { Self::Materials { message: message.into(), material_system, } } /// Create a data validation error pub fn data_validation( message: impl Into, field: impl Into, expected: impl Into, actual: impl Into, ) -> Self { Self::DataValidation { message: message.into(), field: field.into(), expected: expected.into(), actual: actual.into(), } } /// Create a conservation law violation error #[must_use] pub fn conservation_violation(law: ConservationLaw, magnitude: f64, tolerance: f64) -> Self { Self::ConservationViolation { law, magnitude, tolerance, } } /// Create a convergence failure error pub fn convergence_failure( algorithm: impl Into, iterations: usize, final_residual: f64, tolerance: f64, ) -> Self { Self::ConvergenceFailure { algorithm: algorithm.into(), iterations, final_residual, tolerance, } } /// Check if the error is recoverable #[must_use] pub fn is_recoverable(&self) -> bool { match self { Self::ConvergenceFailure { .. } => true, Self::InvalidParameters { .. } => true, Self::DataValidation { .. } => true, Self::Numerical { .. } => true, _ => false, } } /// Create an I/O error with context pub fn io_error(message: impl Into, context: impl Into) -> Self { let msg = format!("{}: {}", message.into(), context.into()); Self::Io(std::io::Error::other(msg)) } /// Get error severity level #[must_use] pub fn severity(&self) -> ErrorSeverity { match self { Self::ConservationViolation { magnitude, tolerance, .. } => { if magnitude / tolerance > 100.0 { ErrorSeverity::Critical } else if magnitude / tolerance > 10.0 { ErrorSeverity::High } else { ErrorSeverity::Medium } } Self::Physics { .. } => ErrorSeverity::High, Self::ConvergenceFailure { .. } => ErrorSeverity::Medium, Self::GpuComputation { .. } => ErrorSeverity::High, Self::Tensor(_) | Self::Autograd(_) => ErrorSeverity::High, _ => ErrorSeverity::Low, } } /// Create a generic computation error pub fn computation(message: impl Into) -> Self { Self::Numerical { message: message.into(), method: "general computation".to_string(), convergence_info: None, } } } /// Error severity levels for logging and handling #[derive(Debug, Clone, PartialEq, Eq)] pub enum ErrorSeverity { /// Low severity - warnings, minor issues Low, /// Medium severity - computational issues, convergence problems Medium, /// High severity - physics violations, computation failures High, /// Critical severity - system failures, severe physics violations Critical, } impl std::fmt::Display for PhysicsDomain { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { Self::FluidDynamics => "Fluid Dynamics", Self::HeatTransfer => "Heat Transfer", Self::Electromagnetics => "Electromagnetics", Self::QuantumMechanics => "Quantum Mechanics", Self::MolecularDynamics => "Molecular Dynamics", Self::ContinuumMechanics => "Continuum Mechanics", Self::StatisticalMechanics => "Statistical Mechanics", Self::Thermodynamics => "Thermodynamics", }; write!(f, "{name}") } } impl std::fmt::Display for ConservationLaw { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { Self::Mass => "Mass", Self::Momentum => "Momentum", Self::Energy => "Energy", Self::AngularMomentum => "Angular Momentum", Self::Charge => "Charge", Self::Probability => "Probability", }; write!(f, "{name}") } } impl std::fmt::Display for BoundaryType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { Self::Dirichlet => "Dirichlet", Self::Neumann => "Neumann", Self::Robin => "Robin", Self::Periodic => "Periodic", Self::NoSlip => "No-slip", Self::FreeSlip => "Free-slip", }; write!(f, "{name}") } } #[cfg(feature = "biology")] impl std::fmt::Display for BiologyContext { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { Self::ProteinStructure => "Protein Structure", Self::NucleicAcid => "Nucleic Acid", Self::MetabolicPathway => "Metabolic Pathway", Self::GeneExpression => "Gene Expression", Self::CellSignaling => "Cell Signaling", Self::PopulationDynamics => "Population Dynamics", }; write!(f, "{name}") } } #[cfg(test)] mod tests { use super::*; #[test] fn test_error_creation() { let err = ScienceError::physics("Test error", PhysicsDomain::FluidDynamics); assert!(matches!(err, ScienceError::Physics { .. })); } #[test] fn test_error_severity() { let err = ScienceError::conservation_violation(ConservationLaw::Energy, 1e-2, 1e-6); assert_eq!(err.severity(), ErrorSeverity::Critical); } #[test] fn test_recoverable_errors() { let err = ScienceError::convergence_failure("Newton", 100, 1e-3, 1e-6); assert!(err.is_recoverable()); } }