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