1use super::MixedMesh;
4use crate::{
5 geometry::MixedGeometry,
6 topology::mixed::MixedTopology,
7 traits::{Builder, GeometryBuilder, MeshBuilder, TopologyBuilder},
8 types::Scalar,
9};
10use itertools::izip;
11use ndelement::{
12 ciarlet::{CiarletElement, LagrangeElementFamily, LagrangeVariant, lagrange},
13 map::IdentityMap,
14 reference_cell,
15 traits::FiniteElement,
16 types::{Continuity, ReferenceCellType},
17};
18use rlst::rlst_dynamic_array;
19use std::collections::{HashMap, HashSet};
20
21#[derive(Debug)]
23pub struct MixedMeshBuilder<T: Scalar> {
24 gdim: usize,
25 element_indices: HashMap<(ReferenceCellType, usize), usize>,
26 elements: Vec<CiarletElement<T, IdentityMap, T>>,
27 points_per_cell: Vec<usize>,
28 pub(crate) points: Vec<T>,
29 cells: Vec<usize>,
30 cell_starts: Vec<usize>,
31 cell_families: Vec<usize>,
32 cell_degrees: Vec<usize>,
33 cell_types: Vec<ReferenceCellType>,
34 point_indices_to_ids: Vec<usize>,
35 point_ids_to_indices: HashMap<usize, usize>,
36 cell_indices_to_ids: Vec<usize>,
37 cell_ids_to_indices: HashMap<usize, usize>,
38 point_indices: HashSet<usize>,
39 cell_indices: HashSet<usize>,
40 parametric_coords: HashMap<usize, (usize, Vec<T>)>,
41}
42
43impl<T: Scalar> MixedMeshBuilder<T> {
44 pub fn new(gdim: usize) -> Self {
46 Self {
47 gdim,
48 element_indices: HashMap::new(),
49 elements: vec![],
50 points_per_cell: vec![],
51 points: vec![],
52 cells: vec![],
53 cell_starts: vec![],
54 cell_families: vec![],
55 cell_degrees: vec![],
56 cell_types: vec![],
57 point_indices_to_ids: vec![],
58 point_ids_to_indices: HashMap::new(),
59 cell_indices_to_ids: vec![],
60 cell_ids_to_indices: HashMap::new(),
61 point_indices: HashSet::new(),
62 cell_indices: HashSet::new(),
63 parametric_coords: HashMap::new(),
64 }
65 }
66}
67
68impl<T: Scalar> Builder for MixedMeshBuilder<T> {
69 type Mesh = MixedMesh<T, CiarletElement<T, IdentityMap, T>>;
70 type T = T;
71 type CellData<'a> = (ReferenceCellType, usize, &'a [usize]);
72 type EntityDescriptor = ReferenceCellType;
73
74 fn add_point(&mut self, id: usize, data: &[T]) {
75 if data.len() != self.gdim {
76 panic!("Point has wrong number of coordinates");
77 }
78 if self.point_indices.contains(&id) {
79 panic!("Cannot add point with duplicate id.");
80 }
81 self.point_ids_to_indices
82 .insert(id, self.point_indices_to_ids.len());
83 self.point_indices.insert(id);
84 self.point_indices_to_ids.push(id);
85 self.points.extend_from_slice(data);
86 }
87
88 fn add_cell(&mut self, id: usize, cell_data: (ReferenceCellType, usize, &[usize])) {
89 let element_index = *self
90 .element_indices
91 .entry((cell_data.0, cell_data.1))
92 .or_insert_with(|| {
93 let n = self.cell_indices_to_ids.len();
94 self.elements.push(lagrange::create::<T, T>(
95 cell_data.0,
96 cell_data.1,
97 Continuity::Standard,
98 LagrangeVariant::Equispaced,
99 ));
100 self.points_per_cell.push(self.elements[n].dim());
101 n
102 });
103 self.cell_families.push(element_index);
104 self.cell_starts.push(self.cells.len());
105 self.cell_types.push(cell_data.0);
106 if reference_cell::dim(cell_data.0) != reference_cell::dim(self.cell_types[0]) {
107 panic!("Cannot create mesh with cells of different topological dimensions");
108 }
109 self.cell_degrees.push(cell_data.1);
110 if self.cell_indices.contains(&id) {
111 panic!("Cannot add cell with duplicate id.");
112 }
113 assert_eq!(cell_data.2.len(), self.points_per_cell[element_index]);
114 self.cell_ids_to_indices
115 .insert(id, self.cell_indices_to_ids.len());
116 self.cell_indices.insert(id);
117 self.cell_indices_to_ids.push(id);
118 for id in cell_data.2 {
119 self.cells.push(self.point_ids_to_indices[id]);
120 }
121 }
122
123 fn add_cell_from_nodes_and_type(
124 &mut self,
125 id: usize,
126 nodes: &[usize],
127 cell_type: ReferenceCellType,
128 cell_degree: usize,
129 ) {
130 self.add_cell(id, (cell_type, cell_degree, nodes));
131 }
132
133 fn create_mesh(&self) -> MixedMesh<T, CiarletElement<T, IdentityMap, T>> {
134 let cell_vertices =
135 self.extract_vertices(&self.cells, &self.cell_types, &self.cell_degrees);
136
137 let mut vertex_ids = HashSet::<usize>::new();
142 for v in &cell_vertices {
143 vertex_ids.insert(*v);
144 }
145
146 let vertex_ids = {
147 let mut tmp = Vec::<usize>::with_capacity(vertex_ids.len());
148 tmp.extend(vertex_ids.iter());
149 tmp.sort();
150 tmp
151 };
152
153 let geometry = self.create_geometry(
154 &self.point_indices_to_ids,
155 &self.points,
156 &self.cells,
157 &self.cell_types,
158 &self.cell_degrees,
159 );
160
161 let topology = self.create_topology(
162 vertex_ids,
163 (0..self.cell_count()).collect::<Vec<_>>(),
164 &cell_vertices,
165 &self.cell_types,
166 );
167
168 self.create_mesh_from_topology_geometry(topology, geometry)
169 }
170
171 fn point_count(&self) -> usize {
172 self.point_indices_to_ids.len()
173 }
174 fn cell_count(&self) -> usize {
175 self.cell_indices_to_ids.len()
176 }
177 fn point_indices_to_ids(&self) -> &[usize] {
178 &self.point_indices_to_ids
179 }
180 fn cell_indices_to_ids(&self) -> &[usize] {
181 unimplemented!();
182 }
184 fn cell_points(&self, index: usize) -> &[usize] {
185 &self.cells[self.cell_starts[index]
186 ..self.cell_starts[index] + self.points_per_cell[self.cell_families[index]]]
187 }
188 fn cell_vertices(&self, index: usize) -> &[usize] {
189 &self.cells[self.cell_starts[index]
190 ..self.cell_starts[index] + reference_cell::entity_counts(self.cell_types[index])[0]]
191 }
192 fn point(&self, index: usize) -> &[T] {
193 &self.points[self.gdim * index..self.gdim * (index + 1)]
194 }
195 fn points(&self) -> &[T] {
196 &self.points
197 }
198 fn cell_type(&self, index: usize) -> ReferenceCellType {
199 self.cell_types[index]
200 }
201 fn cell_degree(&self, index: usize) -> usize {
202 self.cell_degrees[index]
203 }
204 fn gdim(&self) -> usize {
205 self.gdim
206 }
207 fn tdim(&self) -> usize {
208 reference_cell::dim(self.cell_types[0])
209 }
210 fn npts(&self, cell_type: Self::EntityDescriptor, degree: usize) -> usize {
211 self.points_per_cell[self.element_indices[&(cell_type, degree)]]
212 }
213
214 fn add_point_parametric_coords(&mut self, id: usize, entity_dim: usize, coords: &[T]) {
215 if let Some(&index) = self.point_ids_to_indices.get(&id) {
216 self.parametric_coords
217 .insert(index, (entity_dim, coords.to_vec()));
218 }
219 }
220
221 fn point_parametric_coords(&self, index: usize) -> Option<(usize, &[T])> {
222 self.parametric_coords
223 .get(&index)
224 .map(|(dim, coords)| (*dim, coords.as_slice()))
225 }
226}
227
228impl<T: Scalar> GeometryBuilder for MixedMeshBuilder<T> {
229 type MeshGeometry = MixedGeometry<T, CiarletElement<T, IdentityMap, T>>;
230 fn create_geometry(
231 &self,
232 point_ids: &[usize],
233 coordinates: &[Self::T],
234 cell_points: &[usize],
235 cell_types: &[ReferenceCellType],
236 cell_degrees: &[usize],
237 ) -> MixedGeometry<T, CiarletElement<T, IdentityMap, T>> {
238 let npts = point_ids.len();
239 let mut points = rlst_dynamic_array!(T, [self.gdim(), npts]);
240 points.data_mut().unwrap().copy_from_slice(coordinates);
241
242 let mut element_families = vec![];
243 let mut ef_indices = HashMap::new();
244 let mut cell_families = vec![];
245 for degree in cell_degrees {
246 cell_families.push(*ef_indices.entry(*degree).or_insert_with(|| {
247 let n = element_families.len();
248 element_families.push(LagrangeElementFamily::<T, T>::new(
249 *degree,
250 Continuity::Standard,
251 LagrangeVariant::Equispaced,
252 ));
253 n
254 }))
255 }
256
257 MixedGeometry::<T, CiarletElement<T, IdentityMap, T>>::new(
258 cell_types,
259 points,
260 cell_points,
261 &element_families,
262 &cell_families,
263 )
264 }
265}
266
267impl<T: Scalar> TopologyBuilder for MixedMeshBuilder<T> {
268 type MeshTopology = MixedTopology;
269 fn create_topology(
270 &self,
271 vertex_ids: Vec<usize>,
272 cell_ids: Vec<usize>,
273 cells: &[usize],
274 _cell_types: &[ReferenceCellType],
275 ) -> MixedTopology {
276 let vertex_ids_to_pos = {
278 let mut tmp = HashMap::<usize, usize>::new();
279 for (i, id) in vertex_ids.iter().enumerate() {
280 tmp.insert(*id, i);
281 }
282 tmp
283 };
284
285 let cells = {
286 let mut new_cells = Vec::<usize>::with_capacity(cells.len());
287 for id in cells {
288 new_cells.push(vertex_ids_to_pos[id]);
289 }
290 new_cells
291 };
292
293 MixedTopology::new(&cells, &self.cell_types, Some(vertex_ids), Some(cell_ids))
294 }
295
296 fn extract_vertices(
297 &self,
298 cell_points: &[usize],
299 cell_types: &[Self::EntityDescriptor],
300 cell_degrees: &[usize],
301 ) -> Vec<usize> {
302 let mut cell_vertices = vec![];
303 let mut start = 0;
304 for (t, d) in izip!(cell_types, cell_degrees) {
305 let e = &self.elements[self.element_indices[&(*t, *d)]];
306 for v in 0..reference_cell::entity_counts(*t)[0] {
307 for d in e.entity_dofs(0, v).unwrap() {
308 cell_vertices.push(cell_points[start + *d])
309 }
310 }
311 start += e.dim();
312 }
313 cell_vertices
314 }
315}
316
317impl<T: Scalar> MeshBuilder for MixedMeshBuilder<T> {
318 fn create_mesh_from_topology_geometry(
319 &self,
320 topology: <Self as TopologyBuilder>::MeshTopology,
321 geometry: <Self as GeometryBuilder>::MeshGeometry,
322 ) -> <Self as Builder>::Mesh {
323 MixedMesh::new(topology, geometry)
324 }
325}
326
327#[cfg(test)]
328mod test {
329 use super::*;
330
331 #[test]
332 #[should_panic]
333 fn test_duplicate_point_id() {
334 let mut b = MixedMeshBuilder::<f64>::new(3);
335
336 b.add_point(2, &[0.0, 0.0, 0.0]);
337 b.add_point(0, &[1.0, 0.0, 0.0]);
338 b.add_point(1, &[0.0, 1.0, 0.0]);
339 b.add_point(2, &[1.0, 1.0, 0.0]);
340 }
341
342 #[test]
343 #[should_panic]
344 fn test_duplicate_cell_id() {
345 let mut b = MixedMeshBuilder::<f64>::new(3);
346
347 b.add_point(0, &[0.0, 0.0, 0.0]);
348 b.add_point(1, &[1.0, 0.0, 0.0]);
349 b.add_point(2, &[0.0, 1.0, 0.0]);
350 b.add_point(3, &[1.0, 1.0, 0.0]);
351
352 b.add_cell(0, (ReferenceCellType::Triangle, 1, &[0, 1, 2]));
353 b.add_cell(0, (ReferenceCellType::Triangle, 1, &[1, 2, 3]));
354 }
355
356 #[test]
357 fn test_non_contiguous_ids() {
358 let mut b = MixedMeshBuilder::<f64>::new(3);
359
360 b.add_point(0, &[0.0, 0.0, 0.0]);
361 b.add_point(1, &[1.0, 0.0, 0.0]);
362 b.add_point(2, &[0.0, 1.0, 0.0]);
363 b.add_point(4, &[1.0, 1.0, 0.0]);
364
365 b.add_cell(0, (ReferenceCellType::Triangle, 1, &[0, 1, 2]));
366 b.add_cell(2, (ReferenceCellType::Triangle, 1, &[1, 2, 4]));
367
368 b.create_mesh();
369 }
370}