Files
rustytorch/crates/specialized/rtx-science/src/error.rs
T
2026-03-04 00:08:42 +00:00

489 lines
14 KiB
Rust

//! 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<T> = std::result::Result<T, ScienceError>;
/// 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<ConvergenceInfo>,
},
/// Chemistry-specific errors
#[cfg(feature = "chemistry")]
#[error("Chemistry error: {message}")]
Chemistry {
/// Error message
message: String,
/// Molecular context if available
molecule_context: Option<String>,
},
/// 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<String>,
},
/// 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<i32>,
},
/// Distributed computing errors
#[cfg(feature = "distributed-sci")]
#[error("Distributed computing error: {message}")]
DistributedComputing {
/// Error message
message: String,
/// Node/rank information
node_info: Option<String>,
},
/// 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<f64>,
/// Additional diagnostic information
pub diagnostics: Vec<String>,
}
/// 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<String>, domain: PhysicsDomain) -> Self {
Self::Physics {
message: message.into(),
domain,
}
}
/// Create a numerical error with method context
pub fn numerical(
message: impl Into<String>,
method: impl Into<String>,
convergence_info: Option<ConvergenceInfo>,
) -> 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<String>, molecule_context: Option<String>) -> Self {
Self::Chemistry {
message: message.into(),
molecule_context,
}
}
/// Create a biology error with biological context
#[cfg(feature = "biology")]
pub fn biology(message: impl Into<String>, 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<String>, material_system: Option<String>) -> Self {
Self::Materials {
message: message.into(),
material_system,
}
}
/// Create a data validation error
pub fn data_validation(
message: impl Into<String>,
field: impl Into<String>,
expected: impl Into<String>,
actual: impl Into<String>,
) -> 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<String>,
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<String>, context: impl Into<String>) -> 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<String>) -> 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());
}
}