1#[cfg(feature = "mpi")]
3use crate::ParallelGridImpl;
4#[cfg(feature = "mpi")]
5use crate::{
6 MixedGridBuilder,
7 traits::{Builder, DistributableGrid, ParallelBuilder},
8 types::GraphPartitioner,
9};
10#[cfg(feature = "serde")]
11use crate::{
12 geometry::mixed::SerializableGeometry, topology::mixed::SerializableTopology,
13 traits::ConvertToSerializable,
14};
15use crate::{
16 geometry::{GeometryMap, MixedEntityGeometry, MixedGeometry},
17 topology::mixed::{MixedEntityTopology, MixedTopology},
18 traits::{Entity, Grid},
19 types::{Ownership, Scalar},
20};
21use itertools::izip;
22#[cfg(feature = "mpi")]
23use mpi::traits::{Communicator, Equivalence};
24use ndelement::{
25 ciarlet::{CiarletElement, LagrangeElementFamily},
26 map::IdentityMap,
27 reference_cell,
28 traits::{ElementFamily, FiniteElement, MappedFiniteElement},
29 types::{Continuity, ReferenceCellType},
30};
31use rlst::dense::{base_array::BaseArray, data_container::VectorContainer};
32use rlst::{SliceArray, rlst_dynamic_array};
33use std::collections::HashMap;
34
35#[derive(Debug)]
37pub struct MixedGridEntity<
38 'a,
39 T: Scalar,
40 E: MappedFiniteElement<CellType = ReferenceCellType, T = T>,
41> {
42 grid: &'a MixedGrid<T, E>,
43 cell_type: ReferenceCellType,
44 cell_index: usize,
45 entity_type: ReferenceCellType,
46 entity_index: usize,
47 geometry_element_index: usize,
48 geometry_cell_index: usize,
49}
50
51impl<'e, T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>>
52 MixedGridEntity<'e, T, E>
53{
54 pub fn new(
56 grid: &'e MixedGrid<T, E>,
57 cell_type: ReferenceCellType,
58 cell_index: usize,
59 entity_type: ReferenceCellType,
60 entity_index: usize,
61 ) -> Self {
62 Self {
63 grid,
64 cell_type,
65 cell_index,
66 entity_type,
67 entity_index,
68 geometry_element_index: grid.geometry.insertion_indices_to_element_indices
69 [grid.topology.insertion_indices[&cell_type][cell_index]],
70 geometry_cell_index: grid.geometry.insertion_indices_to_cell_indices
71 [grid.topology.insertion_indices[&cell_type][cell_index]],
72 }
73 }
74}
75impl<T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>> Entity
76 for MixedGridEntity<'_, T, E>
77{
78 type T = T;
79 type EntityDescriptor = ReferenceCellType;
80 type Topology<'a>
81 = MixedEntityTopology<'a>
82 where
83 Self: 'a;
84 type Geometry<'a>
85 = MixedEntityGeometry<'a, T, E>
86 where
87 Self: 'a;
88 fn entity_type(&self) -> ReferenceCellType {
89 self.entity_type
90 }
91 fn local_index(&self) -> usize {
92 self.grid.topology.cell_entity_index(
93 self.cell_type,
94 self.cell_index,
95 self.entity_type,
96 self.entity_index,
97 )
98 }
99 fn global_index(&self) -> usize {
100 self.local_index()
101 }
102 fn geometry(&self) -> Self::Geometry<'_> {
103 MixedEntityGeometry::new(
104 &self.grid.geometry,
105 self.geometry_element_index,
106 self.geometry_cell_index,
107 reference_cell::dim(self.entity_type),
108 self.entity_index,
109 )
110 }
111 fn topology(&self) -> Self::Topology<'_> {
112 MixedEntityTopology::new(&self.grid.topology, self.entity_type(), self.local_index())
113 }
114 fn ownership(&self) -> Ownership {
115 Ownership::Owned
116 }
117 fn id(&self) -> Option<usize> {
118 self.grid
119 .topology
120 .entity_id(self.entity_type, self.local_index())
121 }
122}
123
124#[derive(Debug)]
126pub struct MixedGridEntityIter<
127 'a,
128 T: Scalar,
129 E: MappedFiniteElement<CellType = ReferenceCellType, T = T>,
130> {
131 grid: &'a MixedGrid<T, E>,
132 entity_type: ReferenceCellType,
133 index: usize,
134}
135
136impl<'a, T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>>
137 MixedGridEntityIter<'a, T, E>
138{
139 pub fn new(grid: &'a MixedGrid<T, E>, entity_type: ReferenceCellType) -> Self {
141 Self {
142 grid,
143 entity_type,
144 index: 0,
145 }
146 }
147}
148impl<'a, T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>> Iterator
149 for MixedGridEntityIter<'a, T, E>
150{
151 type Item = MixedGridEntity<'a, T, E>;
152
153 fn next(&mut self) -> Option<MixedGridEntity<'a, T, E>> {
154 self.index += 1;
155 self.grid.entity(self.entity_type, self.index - 1)
156 }
157}
158
159#[derive(Debug)]
161pub struct MixedGrid<T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>> {
162 topology: MixedTopology,
163 geometry: MixedGeometry<T, E>,
164}
165
166#[cfg(feature = "serde")]
167#[derive(serde::Serialize, Debug, serde::Deserialize)]
168#[serde(bound = "for<'de2> T: serde::Deserialize<'de2>")]
169pub struct SerializableGrid<T: Scalar + serde::Serialize>
170where
171 for<'de2> T: serde::Deserialize<'de2>,
172{
173 topology: SerializableTopology,
174 geometry: SerializableGeometry<T>,
175}
176
177#[cfg(feature = "serde")]
178impl<T: Scalar + serde::Serialize> ConvertToSerializable
179 for MixedGrid<T, CiarletElement<T, IdentityMap, T>>
180{
181 type SerializableType = SerializableGrid<T>;
182 fn to_serializable(&self) -> SerializableGrid<T> {
183 SerializableGrid {
184 topology: self.topology.to_serializable(),
185 geometry: self.geometry.to_serializable(),
186 }
187 }
188 fn from_serializable(s: SerializableGrid<T>) -> Self {
189 Self {
190 topology: MixedTopology::from_serializable(s.topology),
191 geometry: MixedGeometry::from_serializable(s.geometry),
192 }
193 }
194}
195
196impl<T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>> MixedGrid<T, E> {
197 pub fn new(topology: MixedTopology, geometry: MixedGeometry<T, E>) -> Self {
199 Self { topology, geometry }
200 }
201}
202
203impl<T: Scalar> MixedGrid<T, CiarletElement<T, IdentityMap, T>> {
204 pub fn new_from_raw_data(
206 coordinates: &[T],
207 gdim: usize,
208 cells: &[usize],
209 cell_types: &[ReferenceCellType],
210 cell_degrees: &[usize],
211 ) -> Self {
212 let npts = coordinates.len() / gdim;
213 let mut points = rlst_dynamic_array!(T, [gdim, npts]);
214 points.data_mut().unwrap().copy_from_slice(coordinates);
215
216 let mut element_families = vec![];
217 let mut element_family_indices = HashMap::new();
218
219 let cell_families = cell_degrees
220 .iter()
221 .map(|d| {
222 *element_family_indices.entry(*d).or_insert_with(|| {
223 let index = element_families.len();
224 element_families
225 .push(LagrangeElementFamily::<T, T>::new(*d, Continuity::Standard));
226 index
227 })
228 })
229 .collect::<Vec<_>>();
230
231 let geometry = MixedGeometry::<T, CiarletElement<T, IdentityMap, T>>::new(
232 cell_types,
233 points,
234 cells,
235 &element_families,
236 &cell_families,
237 );
238
239 let mut start = 0;
240 let mut tcells = vec![];
241 for (t, f) in izip!(cell_types, &cell_families) {
242 let tpoints_per_cell = reference_cell::entity_counts(*t)[0];
243 for i in 0..tpoints_per_cell {
244 tcells.push(cells[start + i]);
245 }
246 start += element_families[*f].element(*t).dim();
247 }
248
249 let topology = MixedTopology::new(&tcells, cell_types, None, None);
250
251 Self { topology, geometry }
252 }
253}
254
255impl<T: Scalar, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>> Grid
256 for MixedGrid<T, E>
257{
258 type T = T;
259 type Entity<'a>
260 = MixedGridEntity<'a, T, E>
261 where
262 Self: 'a;
263 type GeometryMap<'a>
264 = GeometryMap<'a, T, BaseArray<VectorContainer<T>, 2>, BaseArray<VectorContainer<usize>, 2>>
265 where
266 Self: 'a;
267 type EntityDescriptor = ReferenceCellType;
268 type EntityIter<'a>
269 = MixedGridEntityIter<'a, T, E>
270 where
271 Self: 'a;
272
273 fn geometry_dim(&self) -> usize {
274 self.geometry.dim()
275 }
276 fn topology_dim(&self) -> usize {
277 self.topology.dim()
278 }
279
280 fn entity(
281 &self,
282 entity_type: ReferenceCellType,
283 local_index: usize,
284 ) -> Option<Self::Entity<'_>> {
285 let dim = reference_cell::dim(entity_type);
286 if local_index < self.topology.entity_count(entity_type) {
287 if dim == self.topology_dim() {
288 Some(MixedGridEntity::new(
289 self,
290 entity_type,
291 local_index,
292 entity_type,
293 0,
294 ))
295 } else {
296 for t in &self.topology.entity_types()[self.topology_dim()] {
297 if let Some(cell) =
298 self.topology.upward_connectivity[&entity_type][t][local_index].first()
299 {
300 let dc = &self.topology.downward_connectivity[t][&entity_type];
301 if let Some(index) =
302 (0..dc.shape()[0]).position(|i| dc[[i, *cell]] == local_index)
303 {
304 return Some(MixedGridEntity::new(self, *t, *cell, entity_type, index));
305 }
306 }
307 }
308 None
309 }
310 } else {
311 None
312 }
313 }
314
315 fn entity_types(&self, dim: usize) -> &[ReferenceCellType] {
316 &self.topology.entity_types()[dim]
317 }
318
319 fn entity_count(&self, entity_type: ReferenceCellType) -> usize {
320 self.topology.entity_count(entity_type)
321 }
322
323 fn entity_iter(&self, entity_type: ReferenceCellType) -> Self::EntityIter<'_> {
324 MixedGridEntityIter::new(self, entity_type)
325 }
326
327 fn entity_from_id(
328 &self,
329 entity_type: ReferenceCellType,
330 id: usize,
331 ) -> Option<Self::Entity<'_>> {
332 self.topology.ids_to_indices[&entity_type]
333 .get(&id)
334 .map(|i| self.entity(entity_type, *i))?
335 }
336
337 fn geometry_map(
338 &self,
339 entity_type: ReferenceCellType,
340 geometry_degree: usize,
341 points: &[T],
342 ) -> GeometryMap<'_, T, BaseArray<VectorContainer<T>, 2>, BaseArray<VectorContainer<usize>, 2>>
343 {
344 let entity_dim = reference_cell::dim(entity_type);
345 let npoints = points.len() / entity_dim;
346 let rlst_points = SliceArray::<T, 2>::from_shape(points, [entity_dim, npoints]);
347
348 for i in 0..self.geometry.element_count() {
349 let e = self.geometry.element(i);
350 if e.cell_type() == entity_type && e.lagrange_superdegree() == geometry_degree {
351 return GeometryMap::new(
352 e,
353 &rlst_points,
354 self.geometry.points(),
355 self.geometry.cells(i),
356 );
357 }
358 }
359 unimplemented!();
360 }
361}
362
363#[cfg(feature = "mpi")]
364impl<T: Scalar + Equivalence, E: MappedFiniteElement<CellType = ReferenceCellType, T = T>>
365 DistributableGrid for MixedGrid<T, E>
366{
367 type ParallelGrid<'a, C: Communicator + 'a> =
368 ParallelGridImpl<'a, C, MixedGrid<T, CiarletElement<T, IdentityMap, T>>>;
369
370 fn distribute<'a, C: Communicator>(
371 &self,
372 comm: &'a C,
373 partitioner: GraphPartitioner,
374 ) -> Self::ParallelGrid<'a, C> {
375 let mut b = MixedGridBuilder::<T>::new(self.geometry.dim());
376 let pts = self.geometry.points();
377 for p in 0..pts.shape()[1] {
378 b.add_point(
379 p,
380 &pts.data().unwrap()[p * pts.shape()[0]..(p + 1) * pts.shape()[0]],
381 );
382 }
383
384 for (c, (element_i, cell_i)) in izip!(
385 &self.geometry.insertion_indices_to_element_indices,
386 &self.geometry.insertion_indices_to_cell_indices
387 )
388 .enumerate()
389 {
390 let e = self.geometry.element(*element_i);
391 let cells = self.geometry.cells(*element_i);
392 b.add_cell(
393 c,
394 (
395 e.cell_type(),
396 e.lagrange_superdegree(),
397 &cells.data().unwrap()
398 [cell_i * cells.shape()[0]..(cell_i + 1) * cells.shape()[0]],
399 ),
400 );
401 }
402 b.create_parallel_grid_root(comm, partitioner)
403 }
404}
405
406#[cfg(test)]
407mod test {
408 use super::*;
409 use crate::traits::{GeometryMap, Topology};
410 use approx::*;
411 use itertools::izip;
412 use ndelement::{
413 ciarlet::{CiarletElement, LagrangeElementFamily},
414 reference_cell,
415 types::Continuity,
416 };
417 use rlst::rlst_dynamic_array;
418
419 fn example_grid_triangle() -> MixedGrid<f64, CiarletElement<f64, IdentityMap>> {
420 let mut points = rlst_dynamic_array!(f64, [3, 4]);
421 *points.get_mut([0, 0]).unwrap() = 0.0;
422 *points.get_mut([1, 0]).unwrap() = 0.0;
423 *points.get_mut([2, 0]).unwrap() = 1.0;
424 *points.get_mut([0, 1]).unwrap() = 1.0;
425 *points.get_mut([1, 1]).unwrap() = 0.0;
426 *points.get_mut([2, 1]).unwrap() = 0.0;
427 *points.get_mut([0, 2]).unwrap() = 0.0;
428 *points.get_mut([1, 2]).unwrap() = 1.0;
429 *points.get_mut([2, 2]).unwrap() = 0.0;
430 *points.get_mut([0, 3]).unwrap() = 2.0;
431 *points.get_mut([1, 3]).unwrap() = 1.0;
432 *points.get_mut([2, 3]).unwrap() = 0.0;
433 let family = LagrangeElementFamily::<f64>::new(1, Continuity::Standard);
434 MixedGrid::new(
435 MixedTopology::new(
436 &[0, 1, 2, 2, 1, 3],
437 &[ReferenceCellType::Triangle, ReferenceCellType::Triangle],
438 None,
439 None,
440 ),
441 MixedGeometry::<f64, CiarletElement<f64, IdentityMap>>::new(
442 &[ReferenceCellType::Triangle, ReferenceCellType::Triangle],
443 points,
444 &[0, 1, 2, 2, 1, 3],
445 &[family],
446 &[0, 0],
447 ),
448 )
449 }
450
451 fn example_grid_mixed() -> MixedGrid<f64, CiarletElement<f64, IdentityMap>> {
452 let mut points = rlst_dynamic_array!(f64, [2, 8]);
453 *points.get_mut([0, 0]).unwrap() = 0.0;
454 *points.get_mut([1, 0]).unwrap() = 0.0;
455 *points.get_mut([0, 1]).unwrap() = 1.0;
456 *points.get_mut([1, 1]).unwrap() = 0.0;
457 *points.get_mut([0, 2]).unwrap() = 2.0;
458 *points.get_mut([1, 2]).unwrap() = 0.0;
459 *points.get_mut([0, 3]).unwrap() = 4.0;
460 *points.get_mut([1, 3]).unwrap() = 0.0;
461 *points.get_mut([0, 4]).unwrap() = 0.0;
462 *points.get_mut([1, 4]).unwrap() = 1.0;
463 *points.get_mut([0, 5]).unwrap() = 1.0;
464 *points.get_mut([1, 5]).unwrap() = 1.0;
465 *points.get_mut([0, 6]).unwrap() = 2.0;
466 *points.get_mut([1, 6]).unwrap() = 1.0;
467 *points.get_mut([0, 7]).unwrap() = 4.0;
468 *points.get_mut([1, 7]).unwrap() = 1.0;
469 let family = LagrangeElementFamily::<f64>::new(1, Continuity::Standard);
470 MixedGrid::new(
471 MixedTopology::new(
472 &[0, 5, 4, 0, 1, 5, 1, 2, 5, 6, 2, 3, 6, 7],
473 &[
474 ReferenceCellType::Triangle,
475 ReferenceCellType::Triangle,
476 ReferenceCellType::Quadrilateral,
477 ReferenceCellType::Quadrilateral,
478 ],
479 None,
480 None,
481 ),
482 MixedGeometry::<f64, CiarletElement<f64, IdentityMap>>::new(
483 &[
484 ReferenceCellType::Triangle,
485 ReferenceCellType::Triangle,
486 ReferenceCellType::Quadrilateral,
487 ReferenceCellType::Quadrilateral,
488 ],
489 points,
490 &[0, 5, 4, 0, 1, 5, 1, 2, 5, 6, 2, 3, 6, 7],
491 &[family],
492 &[0, 0, 0, 0],
493 ),
494 )
495 }
496
497 #[test]
498 fn test_edges_triangle() {
499 let grid = example_grid_triangle();
500 let conn = reference_cell::connectivity(ReferenceCellType::Triangle);
501 for edge in grid.entity_iter(ReferenceCellType::Interval) {
502 let cell = grid
503 .entity(ReferenceCellType::Triangle, edge.cell_index)
504 .unwrap();
505 for (i, v) in izip!(
506 &conn[1][edge.entity_index][0],
507 edge.topology().sub_entity_iter(ReferenceCellType::Point)
508 ) {
509 assert_eq!(v, cell.topology().sub_entity(ReferenceCellType::Point, *i));
510 }
511 }
512 }
513
514 #[test]
515 fn test_geometry_map() {
516 let grid = example_grid_mixed();
517 let mut mapped_pts = vec![0.0; 4];
518
519 let pts = vec![0.0, 0.0, 0.5, 0.5];
520 let map = grid.geometry_map(ReferenceCellType::Triangle, 1, &pts);
521
522 map.physical_points(0, &mut mapped_pts);
523 assert_relative_eq!(mapped_pts[0], 0.0, epsilon = 1e-10);
524 assert_relative_eq!(mapped_pts[1], 0.0, epsilon = 1e-10);
525 assert_relative_eq!(mapped_pts[2], 0.5, epsilon = 1e-10);
526 assert_relative_eq!(mapped_pts[3], 1.0, epsilon = 1e-10);
527
528 map.physical_points(1, &mut mapped_pts);
529 assert_relative_eq!(mapped_pts[0], 0.0, epsilon = 1e-10);
530 assert_relative_eq!(mapped_pts[1], 0.0, epsilon = 1e-10);
531 assert_relative_eq!(mapped_pts[2], 1.0, epsilon = 1e-10);
532 assert_relative_eq!(mapped_pts[3], 0.5, epsilon = 1e-10);
533
534 let pts = vec![0.5, 0.0, 1.0, 1.0];
535 let map = grid.geometry_map(ReferenceCellType::Quadrilateral, 1, &pts);
536
537 map.physical_points(0, &mut mapped_pts);
538 assert_relative_eq!(mapped_pts[0], 1.5, epsilon = 1e-10);
539 assert_relative_eq!(mapped_pts[1], 0.0, epsilon = 1e-10);
540 assert_relative_eq!(mapped_pts[2], 2.0, epsilon = 1e-10);
541 assert_relative_eq!(mapped_pts[3], 1.0, epsilon = 1e-10);
542
543 map.physical_points(1, &mut mapped_pts);
544 assert_relative_eq!(mapped_pts[0], 3.0, epsilon = 1e-10);
545 assert_relative_eq!(mapped_pts[1], 0.0, epsilon = 1e-10);
546 assert_relative_eq!(mapped_pts[2], 4.0, epsilon = 1e-10);
547 assert_relative_eq!(mapped_pts[3], 1.0, epsilon = 1e-10);
548 }
549}