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