// Copyright (c) 2024 RustyTorch++ Team // Licensed under the Apache License, Version 2.0 //! # RTX-FEA: GPU-Accelerated Finite Element Analysis //! //! A production-ready finite element analysis library with comprehensive GPU acceleration //! using CUDA. This crate provides all the essential components for modern FEA simulations. //! //! ## Features //! //! - **GPU-Accelerated**: Leverages cudarc 0.17.3 for CUDA operations //! - **Comprehensive Elements**: Support for Tri3/6, Quad4/8/9, Tet4/10, Hex8/20/27, and more //! - **Advanced Materials**: Linear elastic, hyperelastic, and plasticity models //! - **Efficient Assembly**: Sparse matrix assembly with GPU optimization //! - **Robust Solvers**: Direct and iterative solvers with GPU acceleration //! - **Mesh Management**: Advanced mesh operations including refinement and partitioning //! //! ## Maturity //! //! Validated: element stiffness and mass matrices, shape functions across the //! element library, global assembly, constraint handling, the generalized //! eigensolver, and modal analysis end to end against closed-form bar //! frequencies. See `tests/element_matrices_physical.rs`, //! `tests/shape_function_invariants.rs`, `tests/eigenvalue_closed_form.rs` //! and `tests/modal_closed_form.rs`. //! //! Validated since: manufactured solutions across the element library and //! the nonlinear path — `NonlinearStaticAnalysis` runs full Newton on the //! consistent tangent (orders 1.76/1.95 by MMS) and [`mor`] provides //! POD-Galerkin reduction with ECSW hyper-reduction on top of it. //! //! Not yet: `Pyramid13` and pyramid quadrature are unimplemented and report //! so; plane-stress condensation of nonlinear materials refuses explicitly. //! The only test modules still behind `#[cfg(disabled)]` are the GPU solver //! tests, which need CUDA hardware — everything else is enabled, with //! fixtures corrected where they encoded abandoned designs. //! //! ## Quick Start //! //! Natural frequencies of a fixed-free bar: //! //! ```rust //! use rtx_fea::analysis::{Analysis, AnalysisConfig, AnalysisData, ModalAnalysis}; //! use rtx_fea::assembly::DofComponent; //! use rtx_fea::boundary::{BoundaryCondition, BoundaryConditionSet, DirichletBC}; //! use rtx_fea::materials::{LinearElastic, MaterialDatabase}; //! use rtx_fea::mesh::{Element, ElementType, MaterialId, Mesh, Node}; //! //! // A 4 x 1 grid of quadrilaterals spanning a 1.0 x 0.05 strip. //! let mut mesh = Mesh::new(2)?; //! let mut columns = Vec::new(); //! for i in 0..=4 { //! let x = f64::from(i) * 0.25; //! columns.push([ //! mesh.add_node(Node::new_2d(x, 0.0)), //! mesh.add_node(Node::new_2d(x, 0.05)), //! ]); //! } //! for i in 0..4 { //! let nodes = vec![columns[i][0], columns[i + 1][0], columns[i + 1][1], columns[i][1]]; //! mesh.add_element(Element::new(ElementType::Quad4, nodes, MaterialId(0))?)?; //! } //! //! let mut materials = MaterialDatabase::new(); //! materials.add_material(MaterialId(0), LinearElastic::new(200e9, 0.3).with_density(8000.0), None); //! //! // Clamp the left edge. Without constraints the stiffness matrix is //! // singular and the analysis reports that rather than returning noise. //! let mut boundary_conditions = BoundaryConditionSet::new(); //! boundary_conditions.add_condition(BoundaryCondition::Dirichlet(DirichletBC::fixed( //! columns[0].to_vec(), //! vec![DofComponent::DisplacementX, DofComponent::DisplacementY], //! 0.0, //! ))); //! //! let mut analysis = ModalAnalysis::new(mesh, materials, 3, AnalysisConfig::default()) //! .with_boundary_conditions(boundary_conditions); //! let results = analysis.run()?; //! //! let AnalysisData::Vector(frequencies) = &results.additional_data["frequencies"] else { //! panic!("frequencies should be a vector") //! }; //! assert_eq!(frequencies.len(), 3); //! assert!(frequencies.iter().all(|f| f.is_finite() && *f > 0.0)); //! # Ok::<(), Box>(()) //! ``` //! //! ## Module Organization //! //! - [`mesh`]: Mesh data structures, generation, and operations //! - [`elements`]: Finite element formulations and shape functions //! - [`materials`]: Constitutive models and material behavior //! - [`assembly`]: Global matrix assembly and equation systems //! - [`boundary`]: Boundary conditions and constraints //! - [`solvers`]: Linear and nonlinear equation solvers //! - [`kernels`]: GPU kernels and CUDA operations //! - [`analysis`]: High-level analysis drivers //! //! ## Examples //! //! The crate includes comprehensive examples: //! //! - `linear_elasticity`: Basic linear elastic analysis //! - `cantilever_beam`: Classical beam bending problem //! - Advanced examples with nonlinear materials and contact pub mod analysis; pub mod assembly; pub mod boundary; pub mod elements; pub mod error; pub mod kernels; pub mod materials; pub mod mesh; pub mod mor; pub mod solvers; pub mod utils; // Re-export commonly used types for convenience pub use error::{FeaError, FeaResult}; /// Common prelude for RTX-FEA. /// /// This module re-exports the most commonly used types and traits /// to make it easier to get started with the library. pub mod prelude { pub use crate::analysis::{Analysis, DynamicAnalysis, StaticLinearAnalysis}; pub use crate::assembly::{AssemblyOptions, GlobalAssembler, SparseMatrix}; pub use crate::boundary::{BoundaryCondition, DirichletBC, NeumannBC}; pub use crate::elements::{ ElementFactory, FiniteElement, NaturalCoords, PhysicalCoords, QuadratureRule, ShapeFunctionEval, }; pub use crate::error::{FeaError, FeaResult}; pub use crate::materials::{LinearElastic, Material, MaterialProperties}; pub use crate::mesh::{ Element, ElementId, ElementType, MaterialId, Mesh, Node, NodeId, geometry::{Box3D, Circle, Rectangle, Sphere}, }; pub use crate::solvers::{CholeskyDirect, ConjugateGradient, LinearSolver, SolverOptions}; } /// Library information and version. pub mod info { /// Get the library version. pub fn version() -> &'static str { env!("CARGO_PKG_VERSION") } /// Get the library name. pub fn name() -> &'static str { env!("CARGO_PKG_NAME") } /// Get the library description. pub fn description() -> &'static str { env!("CARGO_PKG_DESCRIPTION") } /// Check if CUDA support is available. pub fn has_cuda_support() -> bool { cfg!(feature = "cuda") } /// Get supported element types. pub fn supported_elements() -> Vec { crate::mesh::ElementType::all() } /// Library build information. pub fn build_info() -> BuildInfo { BuildInfo { version: version().to_string(), cuda_support: has_cuda_support(), element_types: supported_elements(), build_date: std::env::var("VERGEN_BUILD_DATE") .unwrap_or_else(|_| "unknown".to_string()), git_sha: std::env::var("VERGEN_GIT_SHA").unwrap_or_else(|_| "unknown".to_string()), } } /// Detailed build information. #[derive(Debug, Clone)] pub struct BuildInfo { /// Library version pub version: String, /// CUDA support enabled pub cuda_support: bool, /// Supported element types pub element_types: Vec, /// Build date pub build_date: String, /// Git commit SHA pub git_sha: String, } impl std::fmt::Display for BuildInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "RTX-FEA Build Information:")?; writeln!(f, " Version: {}", self.version)?; writeln!( f, " CUDA Support: {}", if self.cuda_support { "Yes" } else { "No" } )?; writeln!(f, " Element Types: {} supported", self.element_types.len())?; writeln!(f, " Build Date: {}", self.build_date)?; writeln!(f, " Git SHA: {}", &self.git_sha[..8])?; Ok(()) } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_library_info() { assert!(!info::version().is_empty()); assert_eq!(info::name(), "rtx-fea"); assert!(!info::description().is_empty()); let build_info = info::build_info(); assert!(!build_info.version.is_empty()); assert!(!build_info.element_types.is_empty()); } #[test] fn test_supported_elements() { let elements = info::supported_elements(); assert!(elements.contains(&mesh::ElementType::Tri3)); assert!(elements.contains(&mesh::ElementType::Quad4)); assert!(elements.contains(&mesh::ElementType::Tet4)); assert!(elements.contains(&mesh::ElementType::Hex8)); } #[test] fn test_prelude_imports() -> FeaResult<()> { use prelude::*; // Test that we can create basic types from prelude let _mesh = Mesh::new(2)?; let _coords = NaturalCoords::new_2d(0.0, 0.0); let _material = LinearElastic::new(200e9, 0.3); // Test error types let _result: FeaResult<()> = Ok(()); Ok(()) } // Fixture correction on re-enable (2026-08-19): the factory deliberately // refuses Point/Line2/Line3, which have no finite element implementation // — requiring every ElementType to construct asserted a capability the // crate does not claim. Implemented types must construct with the right // node count; unimplemented ones must refuse explicitly, not stub. #[test] fn test_element_factory() { use elements::ElementFactory; use mesh::ElementType; for element_type in ElementType::all() { let element = ElementFactory::create(element_type); match element_type { ElementType::Point | ElementType::Line2 | ElementType::Line3 => { assert!(element.is_err(), "{element_type:?} has no implementation"); } _ => { let element = element .unwrap_or_else(|e| panic!("failed to create {element_type:?}: {e}")); assert_eq!(element.num_nodes(), element_type.num_nodes()); } } } } #[test] fn test_mesh_creation() { let mesh = mesh::Mesh::generate_rectangle(1.0, 1.0, 3, 3); assert!(mesh.is_ok()); let mesh = mesh.unwrap(); assert_eq!(mesh.num_nodes(), 9); // 3x3 grid assert_eq!(mesh.num_elements(), 4); // 2x2 quads assert!(mesh.validate().is_ok()); } #[test] fn test_basic_workflow() { use materials::LinearElastic; // Create mesh let mesh = mesh::Mesh::generate_rectangle(1.0, 1.0, 3, 3).unwrap(); // Create material let material = LinearElastic::new(200e9, 0.3); // Validate mesh assert!(mesh.validate().is_ok()); assert_eq!(mesh.spatial_dimension, 2); assert!(mesh.num_elements() > 0); assert!(mesh.num_nodes() > 0); // Check material properties assert!((material.elastic_modulus() - 200e9).abs() < 1e-6); assert!((material.poisson_ratio() - 0.3).abs() < 1e-6); } }