248 lines
6.8 KiB
Rust
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());
|
|
}
|
|
}
|