Skip to main content

mesh_sieve/data/
discretization.rs

1//! Discretization metadata for basis and quadrature keyed by regions.
2
3use crate::topology::cell_type::CellType;
4use std::collections::{BTreeMap, HashMap};
5
6/// Region selector for discretization metadata.
7#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8pub enum RegionKey {
9    /// Match points tagged by a label name/value pair.
10    Label { name: String, value: i32 },
11    /// Match points with a specific cell type.
12    CellType(CellType),
13}
14
15impl RegionKey {
16    /// Construct a label-based region selector.
17    pub fn label(name: impl Into<String>, value: i32) -> Self {
18        Self::Label {
19            name: name.into(),
20            value,
21        }
22    }
23
24    /// Construct a cell-type-based region selector.
25    pub fn cell_type(cell_type: CellType) -> Self {
26        Self::CellType(cell_type)
27    }
28}
29
30/// Basis and quadrature metadata for a region.
31#[derive(Clone, Debug, PartialEq)]
32pub struct DiscretizationMetadata {
33    /// Basis function identifier for the region.
34    pub basis: String,
35    /// Optional polynomial order for the basis functions.
36    pub basis_order: Option<usize>,
37    /// Optional labels describing the basis shape functions.
38    pub shape_functions: Vec<String>,
39    /// Quadrature rule identifier for the region.
40    pub quadrature: String,
41    /// Optional quadrature order.
42    pub quadrature_order: Option<usize>,
43    /// Optional quadrature points in reference coordinates.
44    pub quadrature_points: Vec<Vec<f64>>,
45    /// Optional quadrature weights matching `quadrature_points`.
46    pub quadrature_weights: Vec<f64>,
47}
48
49impl DiscretizationMetadata {
50    /// Create a new metadata record with the provided basis and quadrature labels.
51    pub fn new(basis: impl Into<String>, quadrature: impl Into<String>) -> Self {
52        Self {
53            basis: basis.into(),
54            basis_order: None,
55            shape_functions: Vec::new(),
56            quadrature: quadrature.into(),
57            quadrature_order: None,
58            quadrature_points: Vec::new(),
59            quadrature_weights: Vec::new(),
60        }
61    }
62
63    /// Add basis metadata describing order and shape-function labels.
64    pub fn with_basis_metadata(
65        mut self,
66        order: usize,
67        shape_functions: impl IntoIterator<Item = impl Into<String>>,
68    ) -> Self {
69        self.basis_order = Some(order);
70        self.shape_functions = shape_functions.into_iter().map(Into::into).collect();
71        self
72    }
73
74    /// Add quadrature metadata describing order, points, and weights.
75    pub fn with_quadrature_metadata(
76        mut self,
77        order: usize,
78        points: Vec<Vec<f64>>,
79        weights: Vec<f64>,
80    ) -> Self {
81        self.quadrature_order = Some(order);
82        self.quadrature_points = points;
83        self.quadrature_weights = weights;
84        self
85    }
86
87    /// Returns true when explicit quadrature points and weights are available.
88    pub fn has_quadrature_data(&self) -> bool {
89        !self.quadrature_points.is_empty()
90            && self.quadrature_points.len() == self.quadrature_weights.len()
91    }
92}
93
94/// Per-field discretization metadata keyed by region selectors.
95#[derive(Clone, Debug, Default)]
96pub struct FieldDiscretization {
97    metadata: HashMap<RegionKey, DiscretizationMetadata>,
98}
99
100impl FieldDiscretization {
101    /// Create an empty field discretization.
102    pub fn new() -> Self {
103        Self::default()
104    }
105
106    /// Associate discretization metadata with a region selector.
107    pub fn set_metadata(
108        &mut self,
109        region: RegionKey,
110        metadata: DiscretizationMetadata,
111    ) -> Option<DiscretizationMetadata> {
112        self.metadata.insert(region, metadata)
113    }
114
115    /// Convenience wrapper for label-based metadata.
116    pub fn set_label_metadata(
117        &mut self,
118        name: impl Into<String>,
119        value: i32,
120        metadata: DiscretizationMetadata,
121    ) -> Option<DiscretizationMetadata> {
122        self.set_metadata(RegionKey::label(name, value), metadata)
123    }
124
125    /// Convenience wrapper for cell-type-based metadata.
126    pub fn set_cell_type_metadata(
127        &mut self,
128        cell_type: CellType,
129        metadata: DiscretizationMetadata,
130    ) -> Option<DiscretizationMetadata> {
131        self.set_metadata(RegionKey::cell_type(cell_type), metadata)
132    }
133
134    /// Retrieve the metadata for a region selector, if any.
135    pub fn metadata_for(&self, region: &RegionKey) -> Option<&DiscretizationMetadata> {
136        self.metadata.get(region)
137    }
138
139    /// Iterate over region metadata.
140    pub fn iter(&self) -> impl Iterator<Item = (&RegionKey, &DiscretizationMetadata)> {
141        self.metadata.iter()
142    }
143}
144
145/// Discretization metadata for multiple named fields.
146#[derive(Clone, Debug, Default)]
147pub struct Discretization {
148    fields: BTreeMap<String, FieldDiscretization>,
149}
150
151impl Discretization {
152    /// Create an empty discretization metadata container.
153    pub fn new() -> Self {
154        Self::default()
155    }
156
157    /// Insert a field discretization by name.
158    pub fn insert_field(
159        &mut self,
160        name: impl Into<String>,
161        field: FieldDiscretization,
162    ) -> Option<FieldDiscretization> {
163        self.fields.insert(name.into(), field)
164    }
165
166    /// Retrieve a field discretization by name.
167    pub fn field(&self, name: &str) -> Option<&FieldDiscretization> {
168        self.fields.get(name)
169    }
170
171    /// Retrieve or create a field discretization by name.
172    pub fn field_mut(&mut self, name: &str) -> &mut FieldDiscretization {
173        self.fields.entry(name.to_string()).or_default()
174    }
175
176    /// Iterate over all fields.
177    pub fn iter(&self) -> impl Iterator<Item = (&str, &FieldDiscretization)> {
178        self.fields
179            .iter()
180            .map(|(name, field)| (name.as_str(), field))
181    }
182}