132 lines
3.7 KiB
Rust
132 lines
3.7 KiB
Rust
// Mesh refinement algorithms
|
|
|
|
use crate::error::{CfdError, CfdResult};
|
|
|
|
/// Refinement strategy
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum RefinementStrategy {
|
|
/// Uniform refinement - refine all cells
|
|
Uniform,
|
|
/// Adaptive refinement based on error indicators
|
|
Adaptive,
|
|
/// Refine specific regions
|
|
Regional,
|
|
}
|
|
|
|
/// Refinement criteria
|
|
#[derive(Debug, Clone)]
|
|
pub struct RefinementCriteria {
|
|
/// Maximum allowed error per cell
|
|
pub max_error: f64,
|
|
/// Minimum cell size
|
|
pub min_cell_size: f64,
|
|
/// Maximum cell size
|
|
pub max_cell_size: f64,
|
|
/// Maximum refinement levels
|
|
pub max_levels: usize,
|
|
}
|
|
|
|
impl Default for RefinementCriteria {
|
|
fn default() -> Self {
|
|
Self {
|
|
max_error: 1e-3,
|
|
min_cell_size: 1e-6,
|
|
max_cell_size: 1e6,
|
|
max_levels: 10,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Adaptive mesh refinement implementation
|
|
pub struct AdaptiveRefinement {
|
|
criteria: RefinementCriteria,
|
|
current_level: usize,
|
|
}
|
|
|
|
impl AdaptiveRefinement {
|
|
/// Create new adaptive refinement
|
|
#[must_use]
|
|
pub fn new(criteria: RefinementCriteria) -> Self {
|
|
Self {
|
|
criteria,
|
|
current_level: 0,
|
|
}
|
|
}
|
|
|
|
/// Check if refinement is needed
|
|
#[must_use]
|
|
pub fn needs_refinement(&self, error: f64, cell_size: f64, current_level: usize) -> bool {
|
|
error > self.criteria.max_error
|
|
&& cell_size > self.criteria.min_cell_size
|
|
&& current_level < self.criteria.max_levels
|
|
}
|
|
|
|
/// Mark cells for refinement based on error indicators
|
|
pub fn mark_cells_for_refinement(
|
|
&self,
|
|
errors: &[f64],
|
|
cell_sizes: &[f64],
|
|
cell_levels: &[usize],
|
|
) -> CfdResult<Vec<usize>> {
|
|
if errors.len() != cell_sizes.len() || errors.len() != cell_levels.len() {
|
|
return Err(CfdError::mesh(
|
|
"Error, cell size, and level arrays must have same length",
|
|
));
|
|
}
|
|
|
|
let mut marked_cells = Vec::new();
|
|
|
|
for (i, (&error, (&size, &level))) in errors
|
|
.iter()
|
|
.zip(cell_sizes.iter().zip(cell_levels.iter()))
|
|
.enumerate()
|
|
{
|
|
if self.needs_refinement(error, size, level) {
|
|
marked_cells.push(i);
|
|
}
|
|
}
|
|
|
|
Ok(marked_cells)
|
|
}
|
|
|
|
/// Compute gradient-based error indicator
|
|
pub fn compute_gradient_error_indicator(
|
|
&self,
|
|
velocity_field: &[nalgebra::Vector3<f64>],
|
|
) -> CfdResult<Vec<f64>> {
|
|
let mut errors = Vec::with_capacity(velocity_field.len());
|
|
|
|
for velocity in velocity_field {
|
|
// Use velocity magnitude as a simple gradient indicator
|
|
// In practice, this would be computed from actual velocity gradients
|
|
let error = velocity.magnitude();
|
|
errors.push(error);
|
|
}
|
|
|
|
Ok(errors)
|
|
}
|
|
|
|
/// Compute residual-based error indicator
|
|
pub fn compute_residual_error_indicator(
|
|
&self,
|
|
momentum_residuals: &[f64],
|
|
continuity_residuals: &[f64],
|
|
) -> CfdResult<Vec<f64>> {
|
|
if momentum_residuals.len() != continuity_residuals.len() {
|
|
return Err(CfdError::mesh(
|
|
"Momentum and continuity residual arrays must have same length",
|
|
));
|
|
}
|
|
|
|
let mut errors = Vec::with_capacity(momentum_residuals.len());
|
|
|
|
for (&mom_res, &cont_res) in momentum_residuals.iter().zip(continuity_residuals.iter()) {
|
|
// Combine momentum and continuity residuals using L2 norm
|
|
let combined_error = (mom_res * mom_res + cont_res * cont_res).sqrt();
|
|
errors.push(combined_error);
|
|
}
|
|
|
|
Ok(errors)
|
|
}
|
|
}
|