scirs2_integrate/pde/mod.rs
1//! Partial Differential Equation (PDE) solvers
2//!
3//! This module provides implementations of various numerical methods for
4//! solving partial differential equations (PDEs).
5//!
6//! ## Supported Methods
7//!
8//! * Method of Lines (MOL): Converts PDEs to systems of ODEs by discretizing spatial derivatives
9//! * Finite Difference Methods: Approximates derivatives using differences between grid points
10//! * Finite Element Methods: Approximates solutions using basis functions on a mesh
11//! * Spectral Methods: Approximates solutions using global basis functions
12//!
13//! ## Supported Equation Types
14//!
15//! * Parabolic PDEs (e.g., heat equation)
16//! * Hyperbolic PDEs (e.g., wave equation)
17//! * Elliptic PDEs (e.g., Poisson equation)
18//! * Systems of coupled PDEs
19
20pub mod error;
21pub use error::{PDEError, PDEResult};
22
23// Submodules for different PDE solution approaches
24pub mod amr;
25pub mod elliptic;
26pub mod finite_difference;
27pub mod finite_element;
28pub mod implicit;
29pub mod mesh_generation;
30pub mod method_of_lines;
31pub mod spectral;
32
33// Hybridizable discontinuous Galerkin
34pub mod hdg;
35// Peridynamics (nonlocal continuum mechanics)
36pub mod peridynamics;
37// Stefan problem (moving boundary)
38pub mod stefan;
39// Virtual element method
40pub mod vem;
41
42// Enhanced PDE solvers (v0.3.0)
43pub mod fd_solvers;
44pub mod fem_1d;
45pub mod mol_enhanced;
46pub mod spectral_enhanced;
47
48// Additional PDE modules
49pub mod bem;
50pub mod finite_volume;
51pub mod time_fem;
52
53// Discontinuous Galerkin system components
54pub mod dg_systems;
55
56use scirs2_core::ndarray::{Array1, Array2};
57use std::ops::Range;
58
59/// Enum representing different types of boundary conditions
60#[derive(Debug, Clone, Copy, PartialEq)]
61pub enum BoundaryConditionType {
62 /// Dirichlet boundary condition (fixed value)
63 Dirichlet,
64
65 /// Neumann boundary condition (fixed derivative)
66 Neumann,
67
68 /// Robin/mixed boundary condition (linear combination of value and derivative)
69 Robin,
70
71 /// Periodic boundary condition
72 Periodic,
73}
74
75/// Struct representing a boundary condition for a PDE
76#[derive(Debug, Clone)]
77pub struct BoundaryCondition<F: 'static + std::fmt::Debug + Copy + PartialOrd> {
78 /// Type of boundary condition
79 pub bc_type: BoundaryConditionType,
80
81 /// Location of the boundary (low or high end of a dimension)
82 pub location: BoundaryLocation,
83
84 /// Dimension to which this boundary condition applies
85 pub dimension: usize,
86
87 /// Value for Dirichlet conditions, or derivative value for Neumann conditions
88 pub value: F,
89
90 /// Coefficients for Robin boundary conditions (a*u + b*du/dn = c)
91 /// For Robin conditions: [a, b, c]
92 pub coefficients: Option<[F; 3]>,
93}
94
95/// Enum representing the location of a boundary
96#[derive(Debug, Clone, Copy, PartialEq)]
97pub enum BoundaryLocation {
98 /// Lower boundary of the domain
99 Lower,
100
101 /// Upper boundary of the domain
102 Upper,
103}
104
105/// Domain for the PDE problem
106#[derive(Debug, Clone)]
107pub struct Domain {
108 /// Ranges defining the spatial domain for each dimension
109 pub ranges: Vec<Range<f64>>,
110
111 /// Number of grid points in each dimension
112 pub grid_points: Vec<usize>,
113}
114
115impl Domain {
116 /// Create a new domain with given ranges and number of grid points
117 pub fn new(ranges: Vec<Range<f64>>, grid_points: Vec<usize>) -> PDEResult<Self> {
118 if ranges.len() != grid_points.len() {
119 return Err(PDEError::DomainError(
120 "Number of ranges must match number of grid point specifications".to_string(),
121 ));
122 }
123
124 for (i, range) in ranges.iter().enumerate() {
125 if range.start >= range.end {
126 return Err(PDEError::DomainError(format!(
127 "Invalid range for dimension {i}: start must be less than end"
128 )));
129 }
130
131 if grid_points[i] < 3 {
132 return Err(PDEError::DomainError(format!(
133 "At least 3 grid points required for dimension {i}"
134 )));
135 }
136 }
137
138 Ok(Domain {
139 ranges,
140 grid_points,
141 })
142 }
143
144 /// Get the number of dimensions in the domain
145 pub fn dimensions(&self) -> usize {
146 self.ranges.len()
147 }
148
149 /// Get the grid spacing for a given dimension
150 pub fn grid_spacing(&self, dimension: usize) -> PDEResult<f64> {
151 if dimension >= self.dimensions() {
152 return Err(PDEError::DomainError(format!(
153 "Invalid dimension: {dimension}"
154 )));
155 }
156
157 let range = &self.ranges[dimension];
158 let n_points = self.grid_points[dimension];
159
160 Ok((range.end - range.start) / (n_points - 1) as f64)
161 }
162
163 /// Generate a grid for the given dimension
164 pub fn grid(&self, dimension: usize) -> PDEResult<Array1<f64>> {
165 if dimension >= self.dimensions() {
166 return Err(PDEError::DomainError(format!(
167 "Invalid dimension: {dimension}"
168 )));
169 }
170
171 let range = &self.ranges[dimension];
172 let n_points = self.grid_points[dimension];
173 let dx = (range.end - range.start) / ((n_points - 1) as f64);
174
175 let mut grid = Array1::zeros(n_points);
176 for i in 0..n_points {
177 grid[i] = range.start + (i as f64) * dx;
178 }
179
180 Ok(grid)
181 }
182
183 /// Get the total number of grid points in the domain
184 pub fn total_grid_points(&self) -> usize {
185 self.grid_points.iter().product()
186 }
187}
188
189/// Trait for PDE problems
190pub trait PDEProblem<F: 'static + std::fmt::Debug + Copy + PartialOrd> {
191 /// Get the domain of the PDE problem
192 fn domain(&self) -> &Domain;
193
194 /// Get the boundary conditions of the PDE problem
195 fn boundary_conditions(&self) -> &[BoundaryCondition<F>];
196
197 /// Get the number of dependent variables in the PDE
198 fn num_variables() -> usize;
199
200 /// Get the PDE terms (implementation depends on the specific PDE type)
201 fn pde_terms() -> PDEResult<()>;
202}
203
204/// Trait for PDE solvers
205pub trait PDESolver<F: 'static + std::fmt::Debug + Copy + PartialOrd> {
206 /// Solve the PDE problem
207 fn solve() -> PDEResult<PDESolution<F>>;
208}
209
210/// Solution to a PDE problem
211#[derive(Debug, Clone)]
212pub struct PDESolution<F: 'static + std::fmt::Debug + Copy + PartialOrd> {
213 /// Grid points in each dimension
214 pub grids: Vec<Array1<f64>>,
215
216 /// Solution values
217 /// For a 1D problem with one variable: u(x)
218 /// For a 2D problem with one variable: u(x,y)
219 /// For a 1D problem with two variables: [u(x), v(x)]
220 /// Shape depends on the problem dimensions and number of variables
221 pub values: Vec<Array2<F>>,
222
223 /// Error estimate (if available)
224 pub error_estimate: Option<Vec<Array2<F>>>,
225
226 /// Additional solver information
227 pub info: PDESolverInfo,
228}
229
230/// Information about the PDE solver run
231#[derive(Debug, Clone)]
232pub struct PDESolverInfo {
233 /// Number of iterations performed
234 pub num_iterations: usize,
235
236 /// Computation time in seconds
237 pub computation_time: f64,
238
239 /// Final residual norm
240 pub residual_norm: Option<f64>,
241
242 /// Convergence history
243 pub convergence_history: Option<Vec<f64>>,
244
245 /// Method used to solve the PDE
246 pub method: String,
247}
248
249/// Enum representing PDE types
250#[derive(Debug, Clone, Copy, PartialEq)]
251pub enum PDEType {
252 /// Parabolic PDE (e.g., heat equation)
253 Parabolic,
254
255 /// Hyperbolic PDE (e.g., wave equation)
256 Hyperbolic,
257
258 /// Elliptic PDE (e.g., Poisson equation)
259 Elliptic,
260
261 /// Mixed type PDE
262 Mixed,
263}