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

248 lines
6.8 KiB
Rust

// TDD: GREEN phase - Implement error types to pass tests
use thiserror::Error;
// use std::fmt;
/// Result type for CFD operations
pub type CfdResult<T> = Result<T, CfdError>;
/// 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<S: Into<String>>(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<S: Into<String>>(msg: S) -> Self {
Self::MeshError(msg.into())
}
/// Create a solver error
pub fn solver<S: Into<String>>(msg: S) -> Self {
Self::SolverError(msg.into())
}
/// Create a boundary condition error
pub fn boundary_condition<S: Into<String>>(msg: S) -> Self {
Self::BoundaryConditionError(msg.into())
}
/// Create an invalid parameter error
pub fn invalid_parameter<S: Into<String>>(msg: S) -> Self {
Self::InvalidParameter(msg.into())
}
/// Create a tensor error
pub fn tensor<S: Into<String>>(msg: S) -> Self {
Self::TensorError(msg.into())
}
/// Create a kernel error
pub fn kernel<S: Into<String>>(msg: S) -> Self {
Self::KernelError(msg.into())
}
/// Create a physics error
pub fn physics<S: Into<String>>(msg: S) -> Self {
Self::PhysicsError(msg.into())
}
/// Create a CUDA error
pub fn cuda<S: Into<String>>(msg: S) -> Self {
Self::CudaError(msg.into())
}
/// Create a GPU error (alias for `cuda_error`)
pub fn gpu_error<S: Into<String>>(msg: S) -> Self {
Self::CudaError(msg.into())
}
/// Create a solver error
pub fn solver_error<S: Into<String>>(msg: S) -> Self {
Self::SolverError(msg.into())
}
/// Create a not implemented error
pub fn not_implemented<S: Into<String>>(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<anyhow::Error> for CfdError {
fn from(err: anyhow::Error) -> Self {
Self::SolverError(err.to_string())
}
}
impl From<std::io::Error> for CfdError {
fn from(err: std::io::Error) -> Self {
Self::IoError(err.to_string())
}
}
impl From<serde_json::Error> for CfdError {
fn from(err: serde_json::Error) -> Self {
Self::SerializationError(err.to_string())
}
}
#[cfg(feature = "cuda")]
impl From<cudarc::driver::DriverError> for CfdError {
fn from(err: cudarc::driver::DriverError) -> Self {
Self::CudaError(format!("CUDA driver error: {:?}", err))
}
}
// #[cfg(feature = "cuda")]
// impl From<cudarc::driver::CudaError> 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());
}
}