Skip to main content

oxirs_physics/gpu/
mod.rs

1//! GPU-accelerated kernels for physics simulations.
2//!
3//! When compiled with the `gpu` feature, this module exposes dispatchers that
4//! attempt to offload finite-element stress assembly, the Navier-Stokes
5//! pressure-Poisson solve, and heat-diffusion stencil updates onto a GPU
6//! compute backend supplied by `scirs2_core`. When the `gpu` feature is
7//! disabled (the default), every dispatcher returns
8//! [`GpuError::BackendUnavailable`] immediately so callers can fall back to
9//! the existing CPU paths without conditional compilation at the call site.
10//!
11//! This mirrors the SAMM W3-S12 GPU pattern: feature-gated, default off,
12//! pure-Rust default surface, opt-in C/Fortran via the `gpu` feature.
13//!
14//! # Layout
15//!
16//! - [`stress_assembly`] — element stiffness and mass matrix assembly.
17//! - [`navier_stokes_kernel`] — pressure-Poisson and Jacobi pressure solves.
18//! - [`heat_kernel`] — explicit and ADI heat-diffusion stencils.
19//!
20//! # Feature gate
21//!
22//! Enable via `Cargo.toml`:
23//!
24//! ```toml
25//! [dependencies]
26//! oxirs-physics = { version = "*", features = ["gpu"] }
27//! ```
28//!
29//! # Example
30//!
31//! ```rust,no_run
32//! use oxirs_physics::gpu::{GpuElementDescriptor, GpuError, StressAssemblyDispatcher};
33//!
34//! let dispatcher = StressAssemblyDispatcher::new();
35//! let elements = vec![GpuElementDescriptor::default(); 8];
36//! let result = dispatcher.dispatch_stiffness_assembly(&elements);
37//! // Without `gpu` feature: Err(GpuError::BackendUnavailable)
38//! ```
39
40pub mod heat_kernel;
41pub mod navier_stokes_kernel;
42pub mod stress_assembly;
43
44use thiserror::Error;
45
46/// Errors that can arise when using a GPU dispatch path.
47#[derive(Debug, Clone, PartialEq, Eq, Error)]
48pub enum GpuError {
49    /// The GPU backend is not compiled in or is unavailable at runtime.
50    #[error("GPU backend is unavailable; falling back to CPU")]
51    BackendUnavailable,
52
53    /// A kernel produced an unexpected result.
54    #[error("GPU kernel dispatch error: {0}")]
55    DispatchError(String),
56
57    /// Inputs to a GPU kernel were malformed.
58    #[error("GPU kernel input error: {0}")]
59    InvalidInput(String),
60}
61
62/// Result type for GPU dispatch operations.
63pub type GpuResult<T> = Result<T, GpuError>;
64
65/// Whether the underlying compute backend is available at runtime.
66#[inline]
67pub fn backend_available() -> bool {
68    #[cfg(feature = "gpu")]
69    {
70        true
71    }
72    #[cfg(not(feature = "gpu"))]
73    {
74        false
75    }
76}
77
78pub use heat_kernel::HeatKernelDispatcher;
79pub use navier_stokes_kernel::NavierStokesKernelDispatcher;
80pub use stress_assembly::{
81    FemElementKind, GpuElementContribution, GpuElementDescriptor, StressAssemblyDispatcher,
82};
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn backend_available_matches_feature() {
90        #[cfg(feature = "gpu")]
91        assert!(backend_available());
92        #[cfg(not(feature = "gpu"))]
93        assert!(!backend_available());
94    }
95
96    #[test]
97    fn gpu_error_display() {
98        assert!(GpuError::BackendUnavailable
99            .to_string()
100            .contains("unavailable"));
101        assert!(GpuError::DispatchError("foo".to_string())
102            .to_string()
103            .contains("foo"));
104        assert!(GpuError::InvalidInput("bad".to_string())
105            .to_string()
106            .contains("bad"));
107    }
108}