// TDD: GREEN phase - Implement error types to pass tests use thiserror::Error; // use std::fmt; /// Result type for CFD operations pub type CfdResult = Result; /// Comprehensive error types for CFD operations #[derive(Error, Debug)] pub enum CfdError { /// GPU memory allocation or transfer errors #[error("GPU memory error: {0}")] GpuMemoryError(String), /// Convergence failure in iterative solvers #[error( "Convergence failed at iteration {iteration}: residual {residual:.2e} > target {target:.2e}" )] ConvergenceError { /// Iteration number where convergence failed iteration: usize, /// Current residual value residual: f64, /// Target residual for convergence target: f64, }, /// Mesh topology or quality issues #[error("Mesh error: {0}")] MeshError(String), /// Linear solver or numerical issues #[error("Solver error: {0}")] SolverError(String), /// Boundary condition specification errors #[error("Boundary condition error: {0}")] BoundaryConditionError(String), /// CUDA runtime or driver errors #[error("CUDA error: {0}")] CudaError(String), /// CUDA device errors #[error("CUDA device error: {0}")] CudaDeviceError(String), /// Invalid input parameters #[error("Invalid parameter: {0}")] InvalidParameter(String), /// I/O errors for mesh or result files #[error("I/O error: {0}")] IoError(String), /// Serialization/deserialization errors #[error("Serialization error: {0}")] SerializationError(String), /// Tensor operation errors from rtx-tensor #[error("Tensor error: {0}")] TensorError(String), /// Memory allocation errors #[error("Memory allocation error: {0}")] AllocationError(String), /// Kernel execution errors #[error("Kernel execution error: {0}")] KernelError(String), /// Physics validation errors #[error("Physics validation error: {0}")] PhysicsError(String), /// Time stepping errors #[error("Time stepping error: {0}")] TimeStepError(String), } impl CfdError { /// Create a GPU memory error pub fn gpu_memory>(msg: S) -> Self { Self::GpuMemoryError(msg.into()) } /// Create a convergence error #[must_use] pub fn convergence(iteration: usize, residual: f64, target: f64) -> Self { Self::ConvergenceError { iteration, residual, target, } } /// Create a mesh error pub fn mesh>(msg: S) -> Self { Self::MeshError(msg.into()) } /// Create a solver error pub fn solver>(msg: S) -> Self { Self::SolverError(msg.into()) } /// Create a boundary condition error pub fn boundary_condition>(msg: S) -> Self { Self::BoundaryConditionError(msg.into()) } /// Create an invalid parameter error pub fn invalid_parameter>(msg: S) -> Self { Self::InvalidParameter(msg.into()) } /// Create a tensor error pub fn tensor>(msg: S) -> Self { Self::TensorError(msg.into()) } /// Create a kernel error pub fn kernel>(msg: S) -> Self { Self::KernelError(msg.into()) } /// Create a physics error pub fn physics>(msg: S) -> Self { Self::PhysicsError(msg.into()) } /// Create a CUDA error pub fn cuda>(msg: S) -> Self { Self::CudaError(msg.into()) } /// Create a GPU error (alias for `cuda_error`) pub fn gpu_error>(msg: S) -> Self { Self::CudaError(msg.into()) } /// Create a solver error pub fn solver_error>(msg: S) -> Self { Self::SolverError(msg.into()) } /// Create a not implemented error pub fn not_implemented>(msg: S) -> Self { Self::SolverError(format!("Not implemented: {}", msg.into())) } /// Check if this is a recoverable error #[must_use] pub fn is_recoverable(&self) -> bool { match self { Self::ConvergenceError { .. } => true, Self::TimeStepError(_) => true, Self::GpuMemoryError(_) => false, Self::CudaError(_) => false, Self::MeshError(_) => false, Self::SolverError(_) => false, Self::BoundaryConditionError(_) => false, Self::InvalidParameter(_) => false, Self::IoError(_) => false, Self::SerializationError(_) => false, Self::TensorError(_) => false, Self::AllocationError(_) => false, Self::KernelError(_) => false, Self::PhysicsError(_) => true, Self::CudaDeviceError(_) => false, } } /// Check if this is a GPU-related error #[must_use] pub fn is_gpu_error(&self) -> bool { matches!( self, Self::GpuMemoryError(_) | Self::CudaError(_) | Self::CudaDeviceError(_) | Self::KernelError(_) ) } } // Additional conversion implementations for integration with other crates impl From for CfdError { fn from(err: anyhow::Error) -> Self { Self::SolverError(err.to_string()) } } impl From for CfdError { fn from(err: std::io::Error) -> Self { Self::IoError(err.to_string()) } } impl From for CfdError { fn from(err: serde_json::Error) -> Self { Self::SerializationError(err.to_string()) } } #[cfg(feature = "cuda")] impl From for CfdError { fn from(err: cudarc::driver::DriverError) -> Self { Self::CudaError(format!("CUDA driver error: {:?}", err)) } } // #[cfg(feature = "cuda")] // impl From for CfdError { // fn from(err: cudarc::driver::CudaError) -> Self { // Self::CudaError(err.to_string()) // } // } #[cfg(test)] mod tests { use super::*; #[test] fn test_error_constructors() { let gpu_err = CfdError::gpu_memory("Out of memory"); assert!(matches!(gpu_err, CfdError::GpuMemoryError(_))); let conv_err = CfdError::convergence(100, 1e-3, 1e-6); assert!(matches!(conv_err, CfdError::ConvergenceError { .. })); let mesh_err = CfdError::mesh("Invalid topology"); assert!(matches!(mesh_err, CfdError::MeshError(_))); } #[test] fn test_error_properties() { let conv_err = CfdError::convergence(100, 1e-3, 1e-6); assert!(conv_err.is_recoverable()); assert!(!conv_err.is_gpu_error()); let gpu_err = CfdError::gpu_memory("Out of memory"); assert!(!gpu_err.is_recoverable()); assert!(gpu_err.is_gpu_error()); } }