1use super::MixedGrid;
4use crate::{
5 geometry::MixedGeometry,
6 topology::mixed::MixedTopology,
7 traits::{Builder, GeometryBuilder, GridBuilder, TopologyBuilder},
8 types::Scalar,
9};
10use itertools::izip;
11use ndelement::{
12 ciarlet::{CiarletElement, LagrangeElementFamily, 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 MixedGridBuilder<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> MixedGridBuilder<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 MixedGridBuilder<T> {
69 type Grid = MixedGrid<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 ));
99 self.points_per_cell.push(self.elements[n].dim());
100 n
101 });
102 self.cell_families.push(element_index);
103 self.cell_starts.push(self.cells.len());
104 self.cell_types.push(cell_data.0);
105 if reference_cell::dim(cell_data.0) != reference_cell::dim(self.cell_types[0]) {
106 panic!("Cannot create grid with cells of different topological dimensions");
107 }
108 self.cell_degrees.push(cell_data.1);
109 if self.cell_indices.contains(&id) {
110 panic!("Cannot add cell with duplicate id.");
111 }
112 assert_eq!(cell_data.2.len(), self.points_per_cell[element_index]);
113 self.cell_ids_to_indices
114 .insert(id, self.cell_indices_to_ids.len());
115 self.cell_indices.insert(id);
116 self.cell_indices_to_ids.push(id);
117 for id in cell_data.2 {
118 self.cells.push(self.point_ids_to_indices[id]);
119 }
120 }
121
122 fn add_cell_from_nodes_and_type(
123 &mut self,
124 id: usize,
125 nodes: &[usize],
126 cell_type: ReferenceCellType,
127 cell_degree: usize,
128 ) {
129 self.add_cell(id, (cell_type, cell_degree, nodes));
130 }
131
132 fn create_grid(&self) -> MixedGrid<T, CiarletElement<T, IdentityMap, T>> {
133 let cell_vertices =
134 self.extract_vertices(&self.cells, &self.cell_types, &self.cell_degrees);
135
136 let mut vertex_ids = HashSet::<usize>::new();
141 for v in &cell_vertices {
142 vertex_ids.insert(*v);
143 }
144
145 let vertex_ids = {
146 let mut tmp = Vec::<usize>::with_capacity(vertex_ids.len());
147 tmp.extend(vertex_ids.iter());
148 tmp.sort();
149 tmp
150 };
151
152 let geometry = self.create_geometry(
153 &self.point_indices_to_ids,
154 &self.points,
155 &self.cells,
156 &self.cell_types,
157 &self.cell_degrees,
158 );
159
160 let topology = self.create_topology(
161 vertex_ids,
162 (0..self.cell_count()).collect::<Vec<_>>(),
163 &cell_vertices,
164 &self.cell_types,
165 );
166
167 self.create_grid_from_topology_geometry(topology, geometry)
168 }
169
170 fn point_count(&self) -> usize {
171 self.point_indices_to_ids.len()
172 }
173 fn cell_count(&self) -> usize {
174 self.cell_indices_to_ids.len()
175 }
176 fn point_indices_to_ids(&self) -> &[usize] {
177 &self.point_indices_to_ids
178 }
179 fn cell_indices_to_ids(&self) -> &[usize] {
180 unimplemented!();
181 }
183 fn cell_points(&self, index: usize) -> &[usize] {
184 &self.cells[self.cell_starts[index]
185 ..self.cell_starts[index] + self.points_per_cell[self.cell_families[index]]]
186 }
187 fn cell_vertices(&self, index: usize) -> &[usize] {
188 &self.cells[self.cell_starts[index]
189 ..self.cell_starts[index] + reference_cell::entity_counts(self.cell_types[index])[0]]
190 }
191 fn point(&self, index: usize) -> &[T] {
192 &self.points[self.gdim * index..self.gdim * (index + 1)]
193 }
194 fn points(&self) -> &[T] {
195 &self.points
196 }
197 fn cell_type(&self, index: usize) -> ReferenceCellType {
198 self.cell_types[index]
199 }
200 fn cell_degree(&self, index: usize) -> usize {
201 self.cell_degrees[index]
202 }
203 fn gdim(&self) -> usize {
204 self.gdim
205 }
206 fn tdim(&self) -> usize {
207 reference_cell::dim(self.cell_types[0])
208 }
209 fn npts(&self, cell_type: Self::EntityDescriptor, degree: usize) -> usize {
210 self.points_per_cell[self.element_indices[&(cell_type, degree)]]
211 }
212
213 fn add_point_parametric_coords(&mut self, id: usize, entity_dim: usize, coords: &[T]) {
214 if let Some(&index) = self.point_ids_to_indices.get(&id) {
215 self.parametric_coords
216 .insert(index, (entity_dim, coords.to_vec()));
217 }
218 }
219
220 fn point_parametric_coords(&self, index: usize) -> Option<(usize, &[T])> {
221 self.parametric_coords
222 .get(&index)
223 .map(|(dim, coords)| (*dim, coords.as_slice()))
224 }
225}
226
227impl<T: Scalar> GeometryBuilder for MixedGridBuilder<T> {
228 type GridGeometry = MixedGeometry<T, CiarletElement<T, IdentityMap, T>>;
229 fn create_geometry(
230 &self,
231 point_ids: &[usize],
232 coordinates: &[Self::T],
233 cell_points: &[usize],
234 cell_types: &[ReferenceCellType],
235 cell_degrees: &[usize],
236 ) -> MixedGeometry<T, CiarletElement<T, IdentityMap, T>> {
237 let npts = point_ids.len();
238 let mut points = rlst_dynamic_array!(T, [self.gdim(), npts]);
239 points.data_mut().unwrap().copy_from_slice(coordinates);
240
241 let mut element_families = vec![];
242 let mut ef_indices = HashMap::new();
243 let mut cell_families = vec![];
244 for degree in cell_degrees {
245 cell_families.push(*ef_indices.entry(*degree).or_insert_with(|| {
246 let n = element_families.len();
247 element_families.push(LagrangeElementFamily::<T, T>::new(
248 *degree,
249 Continuity::Standard,
250 ));
251 n
252 }))
253 }
254
255 MixedGeometry::<T, CiarletElement<T, IdentityMap, T>>::new(
256 cell_types,
257 points,
258 cell_points,
259 &element_families,
260 &cell_families,
261 )
262 }
263}
264
265impl<T: Scalar> TopologyBuilder for MixedGridBuilder<T> {
266 type GridTopology = MixedTopology;
267 fn create_topology(
268 &self,
269 vertex_ids: Vec<usize>,
270 cell_ids: Vec<usize>,
271 cells: &[usize],
272 _cell_types: &[ReferenceCellType],
273 ) -> MixedTopology {
274 let vertex_ids_to_pos = {
276 let mut tmp = HashMap::<usize, usize>::new();
277 for (i, id) in vertex_ids.iter().enumerate() {
278 tmp.insert(*id, i);
279 }
280 tmp
281 };
282
283 let cells = {
284 let mut new_cells = Vec::<usize>::with_capacity(cells.len());
285 for id in cells {
286 new_cells.push(vertex_ids_to_pos[id]);
287 }
288 new_cells
289 };
290
291 MixedTopology::new(&cells, &self.cell_types, Some(vertex_ids), Some(cell_ids))
292 }
293
294 fn extract_vertices(
295 &self,
296 cell_points: &[usize],
297 cell_types: &[Self::EntityDescriptor],
298 cell_degrees: &[usize],
299 ) -> Vec<usize> {
300 let mut cell_vertices = vec![];
301 let mut start = 0;
302 for (t, d) in izip!(cell_types, cell_degrees) {
303 let e = &self.elements[self.element_indices[&(*t, *d)]];
304 for v in 0..reference_cell::entity_counts(*t)[0] {
305 for d in e.entity_dofs(0, v).unwrap() {
306 cell_vertices.push(cell_points[start + *d])
307 }
308 }
309 start += e.dim();
310 }
311 cell_vertices
312 }
313}
314
315impl<T: Scalar> GridBuilder for MixedGridBuilder<T> {
316 fn create_grid_from_topology_geometry(
317 &self,
318 topology: <Self as TopologyBuilder>::GridTopology,
319 geometry: <Self as GeometryBuilder>::GridGeometry,
320 ) -> <Self as Builder>::Grid {
321 MixedGrid::new(topology, geometry)
322 }
323}
324
325#[cfg(test)]
326mod test {
327 use super::*;
328
329 #[test]
330 #[should_panic]
331 fn test_duplicate_point_id() {
332 let mut b = MixedGridBuilder::<f64>::new(3);
333
334 b.add_point(2, &[0.0, 0.0, 0.0]);
335 b.add_point(0, &[1.0, 0.0, 0.0]);
336 b.add_point(1, &[0.0, 1.0, 0.0]);
337 b.add_point(2, &[1.0, 1.0, 0.0]);
338 }
339
340 #[test]
341 #[should_panic]
342 fn test_duplicate_cell_id() {
343 let mut b = MixedGridBuilder::<f64>::new(3);
344
345 b.add_point(0, &[0.0, 0.0, 0.0]);
346 b.add_point(1, &[1.0, 0.0, 0.0]);
347 b.add_point(2, &[0.0, 1.0, 0.0]);
348 b.add_point(3, &[1.0, 1.0, 0.0]);
349
350 b.add_cell(0, (ReferenceCellType::Triangle, 1, &[0, 1, 2]));
351 b.add_cell(0, (ReferenceCellType::Triangle, 1, &[1, 2, 3]));
352 }
353
354 #[test]
355 fn test_non_contiguous_ids() {
356 let mut b = MixedGridBuilder::<f64>::new(3);
357
358 b.add_point(0, &[0.0, 0.0, 0.0]);
359 b.add_point(1, &[1.0, 0.0, 0.0]);
360 b.add_point(2, &[0.0, 1.0, 0.0]);
361 b.add_point(4, &[1.0, 1.0, 0.0]);
362
363 b.add_cell(0, (ReferenceCellType::Triangle, 1, &[0, 1, 2]));
364 b.add_cell(2, (ReferenceCellType::Triangle, 1, &[1, 2, 4]));
365
366 b.create_grid();
367 }
368}