ndgrid/topology/
mixed.rs

1//! Topology for grids where entities of each tdim may be a mixture of types
2
3#[cfg(feature = "serde")]
4use crate::traits::ConvertToSerializable;
5use crate::traits::Topology;
6use itertools::izip;
7use ndelement::{orientation::compute_orientation, reference_cell, types::ReferenceCellType};
8use rlst::DynArray;
9use std::collections::HashMap;
10use std::iter::Copied;
11
12/// Topology of a single element grid
13#[derive(Debug)]
14pub struct MixedTopology {
15    dim: usize,
16    pub(crate) ids: HashMap<ReferenceCellType, Vec<usize>>,
17    pub(crate) ids_to_indices: HashMap<ReferenceCellType, HashMap<usize, usize>>,
18    pub(crate) insertion_indices: HashMap<ReferenceCellType, Vec<usize>>,
19    entity_types: Vec<Vec<ReferenceCellType>>,
20    entity_counts: HashMap<ReferenceCellType, usize>,
21    pub(crate) downward_connectivity:
22        HashMap<ReferenceCellType, HashMap<ReferenceCellType, DynArray<usize, 2>>>,
23    pub(crate) upward_connectivity:
24        HashMap<ReferenceCellType, HashMap<ReferenceCellType, Vec<Vec<usize>>>>,
25    pub(crate) orientation: HashMap<ReferenceCellType, Vec<i32>>,
26}
27
28#[cfg(feature = "serde")]
29#[derive(serde::Serialize, Debug, serde::Deserialize)]
30/// Serde serializable topology
31pub struct SerializableTopology {
32    dim: usize,
33    ids: HashMap<ReferenceCellType, Vec<usize>>,
34    ids_to_indices: HashMap<ReferenceCellType, HashMap<usize, usize>>,
35    insertion_indices: HashMap<ReferenceCellType, Vec<usize>>,
36    entity_types: Vec<Vec<ReferenceCellType>>,
37    entity_counts: HashMap<ReferenceCellType, usize>,
38    #[allow(clippy::type_complexity)]
39    downward_connectivity:
40        HashMap<ReferenceCellType, HashMap<ReferenceCellType, (Vec<usize>, [usize; 2])>>,
41    upward_connectivity: HashMap<ReferenceCellType, HashMap<ReferenceCellType, Vec<Vec<usize>>>>,
42    orientation: HashMap<ReferenceCellType, Vec<i32>>,
43}
44
45#[cfg(feature = "serde")]
46impl ConvertToSerializable for MixedTopology {
47    type SerializableType = SerializableTopology;
48    fn to_serializable(&self) -> SerializableTopology {
49        SerializableTopology {
50            dim: self.dim,
51            ids: self.ids.clone(),
52            ids_to_indices: self.ids_to_indices.clone(),
53            insertion_indices: self.insertion_indices.clone(),
54            entity_types: self.entity_types.clone(),
55            entity_counts: self.entity_counts.clone(),
56            downward_connectivity: self
57                .downward_connectivity
58                .iter()
59                .map(|(a, b)| {
60                    (
61                        *a,
62                        b.iter()
63                            .map(|(c, d)| (*c, (d.data().unwrap().to_vec(), d.shape())))
64                            .collect::<HashMap<_, _>>(),
65                    )
66                })
67                .collect::<HashMap<_, _>>(),
68            upward_connectivity: self.upward_connectivity.clone(),
69            orientation: self.orientation.clone(),
70        }
71    }
72    fn from_serializable(s: SerializableTopology) -> Self {
73        Self {
74            dim: s.dim,
75            ids: s.ids,
76            ids_to_indices: s.ids_to_indices,
77            insertion_indices: s.insertion_indices,
78            entity_types: s.entity_types,
79            entity_counts: s.entity_counts,
80            downward_connectivity: s
81                .downward_connectivity
82                .iter()
83                .map(|(a, b)| {
84                    (
85                        *a,
86                        b.iter()
87                            .map(|(c, (data, shape))| {
88                                (*c, {
89                                    let mut d = DynArray::<usize, 2>::from_shape(*shape);
90                                    d.data_mut().unwrap().copy_from_slice(data);
91                                    d
92                                })
93                            })
94                            .collect::<HashMap<_, _>>(),
95                    )
96                })
97                .collect::<HashMap<_, _>>(),
98            upward_connectivity: s.upward_connectivity,
99            orientation: s.orientation,
100        }
101    }
102}
103
104impl MixedTopology {
105    /// Create a topology
106    pub fn new(
107        cells: &[usize],
108        cell_types: &[ReferenceCellType],
109        vertex_ids: Option<Vec<usize>>,
110        cell_ids: Option<Vec<usize>>,
111    ) -> Self {
112        let mut start = 0;
113
114        let dim = reference_cell::dim(cell_types[0]);
115        // Check that all cells have the same topological dim
116        for ct in cell_types {
117            if reference_cell::dim(*ct) != dim {
118                panic!(
119                    "MixedTopology does not support cells of a mixture of topological dimensions"
120                );
121            }
122        }
123
124        let mut entities = HashMap::new();
125        let mut entity_counts = HashMap::new();
126        entity_counts.insert(ReferenceCellType::Point, cells.iter().max().unwrap() + 1);
127
128        let mut ids = HashMap::new();
129        let mut ids_to_indices = HashMap::new();
130        if let Some(i) = vertex_ids {
131            ids_to_indices.insert(ReferenceCellType::Point, {
132                let mut vids = HashMap::new();
133                for (j, k) in i.iter().enumerate() {
134                    vids.insert(*k, j);
135                }
136                vids
137            });
138            ids.insert(ReferenceCellType::Point, i);
139        }
140
141        let mut insertion_indices = HashMap::new();
142        for (cell_index, cell_type) in cell_types.iter().enumerate() {
143            let size = reference_cell::entity_counts(*cell_type)[0];
144            insertion_indices
145                .entry(*cell_type)
146                .or_insert(vec![])
147                .push(cell_index);
148
149            // Get vertices of cell
150            let cell = &cells[start..start + size];
151            if let Some(i) = &cell_ids {
152                ids.entry(*cell_type).or_insert(vec![]).push(i[cell_index]);
153                ids_to_indices
154                    .entry(*cell_type)
155                    .or_insert(HashMap::new())
156                    .insert(
157                        i[cell_index],
158                        if let Some(j) = entity_counts.get(cell_type) {
159                            *j
160                        } else {
161                            0
162                        },
163                    );
164            }
165
166            // Add each subentity of cell that's not already included in entities
167            for (etypes, rc_i) in izip!(
168                &reference_cell::entity_types(*cell_type),
169                &reference_cell::connectivity(*cell_type)
170            ) {
171                for (etype, c_ij) in izip!(etypes, rc_i) {
172                    let mut entity = c_ij[0].iter().map(|i| cell[*i]).collect::<Vec<_>>();
173                    entity.sort();
174                    entities
175                        .entry(*etype)
176                        .or_insert(HashMap::new())
177                        .entry(entity)
178                        .or_insert_with(|| {
179                            let old = *entity_counts.entry(*etype).or_insert(0);
180                            *entity_counts.get_mut(etype).unwrap() += 1;
181                            old
182                        });
183                }
184            }
185            start += size;
186        }
187
188        let mut entity_types = vec![vec![]; dim + 1];
189        for e in entity_counts.keys() {
190            entity_types[reference_cell::dim(*e)].push(*e);
191        }
192
193        // Downward connectivity: The entities of type t1 that are subentities of
194        // entities of type t0 (with dim(t0)>=dim(t1))
195        // downward_connectivity[t0][t1][[.., t0_entity_index]] = dim1_entity_index
196        let mut downward_connectivity = HashMap::new();
197        // Assign memory for downward connectivity
198        for (etype, ecount) in &entity_counts {
199            downward_connectivity.insert(*etype, {
200                let mut dc = HashMap::new();
201                for sub_etypes in &reference_cell::entity_types(*etype) {
202                    for e in sub_etypes {
203                        dc.entry(*e).or_insert(DynArray::<usize, 2>::from_shape([
204                            sub_etypes.iter().filter(|&i| *i == *e).count(),
205                            *ecount,
206                        ]));
207                    }
208                }
209                dc
210            });
211        }
212
213        // Upward connectivity: The entities of type t1 that are superentities of
214        // entities of type t0 (with dim(t0)<dim(t1))
215        // upward_connectivity[t0][t1][t0_entity_index][..] = t1_entity_index
216        let mut upward_connectivity = HashMap::new();
217        // Add correct nu ber of items to upward connectivity
218        for etype in entity_counts.keys() {
219            for sub_etypes in reference_cell::entity_types(*etype)
220                .iter()
221                .take(reference_cell::dim(*etype))
222            {
223                for e in sub_etypes {
224                    upward_connectivity
225                        .entry(*e)
226                        .or_insert(HashMap::new())
227                        .entry(*etype)
228                        .or_insert(vec![vec![]; entity_counts[e]]);
229                }
230            }
231        }
232
233        // downward_connectivity[t][t][i] = [i] (ie each entity is a sub-entity of itself)
234        for (d, dc) in downward_connectivity.iter_mut() {
235            for (i, mut j) in dc.get_mut(d).unwrap().col_iter_mut().enumerate() {
236                j[[0]] = i;
237            }
238        }
239
240        // downward_connectivity[t][Point][i] = vertices of entity i of type t
241        for (etype, entities_vertices) in &entities {
242            for (vs, entity_index) in entities_vertices {
243                for (i, vertex_index) in vs.iter().enumerate() {
244                    downward_connectivity
245                        .get_mut(etype)
246                        .unwrap()
247                        .get_mut(&ReferenceCellType::Point)
248                        .unwrap()[[i, *entity_index]] = *vertex_index;
249                    // We can also fill out the upward connectivity if dim > 0.
250                    if reference_cell::dim(*etype) > 0 {
251                        let uc = upward_connectivity
252                            .get_mut(&ReferenceCellType::Point)
253                            .unwrap()
254                            .get_mut(etype)
255                            .unwrap();
256                        if !uc[*vertex_index].contains(entity_index) {
257                            uc[*vertex_index].push(*entity_index);
258                        }
259                    }
260                }
261            }
262        }
263
264        // Fill remaining connectivity
265        if dim > 0 {
266            for etype in &entity_types[dim] {
267                let entity_types = reference_cell::entity_types(*etype);
268                let ref_conn = reference_cell::connectivity(*etype);
269                // Cell entities, skipping vertices
270                let mut cell_entities = ref_conn
271                    .iter()
272                    .skip(1)
273                    .map(|i| vec![0; i.len()])
274                    .collect::<Vec<_>>();
275                for (cell, cell_index) in &entities[etype] {
276                    // dim - 1 denotes the dim dimensional subentity as we skipped vertices
277                    cell_entities[dim - 1][0] = *cell_index;
278
279                    // Fill in subentity indices
280                    for (ce_i, rc_i, et_i) in izip!(
281                        cell_entities.iter_mut(),
282                        ref_conn.iter().skip(1),
283                        entity_types.iter().skip(1),
284                    ) {
285                        for (ce_ij, rc_ij, et_ij) in izip!(ce_i.iter_mut(), rc_i, et_i) {
286                            let mut entity = rc_ij[0].iter().map(|i| cell[*i]).collect::<Vec<_>>();
287                            entity.sort();
288                            *ce_ij = *entities[et_ij].get(&entity).unwrap();
289                        }
290                    }
291
292                    for (i, (rc_i, ce_i, et_i)) in izip!(
293                        ref_conn.iter().skip(2),
294                        cell_entities.iter().skip(1),
295                        entity_types.iter().skip(2),
296                    )
297                    .enumerate()
298                    {
299                        for (ce_ij, rc_ij, et_ij) in izip!(ce_i, rc_i, et_i) {
300                            for (k, (rc_ijk, ce_k)) in
301                                izip!(rc_ij.iter().take(i + 2).skip(1), &cell_entities).enumerate()
302                            {
303                                let mut sub_entity_indices = HashMap::new();
304                                for (sub_entity_type, rc_ijkl) in
305                                    izip!(&entity_types[k + 1], rc_ijk)
306                                {
307                                    let sub_entity_index = sub_entity_indices
308                                        .entry(sub_entity_type)
309                                        .and_modify(|e| *e += 1)
310                                        .or_insert(0);
311                                    downward_connectivity
312                                        .get_mut(et_ij)
313                                        .unwrap()
314                                        .get_mut(sub_entity_type)
315                                        .unwrap()[[*sub_entity_index, *ce_ij]] = ce_k[*rc_ijkl];
316                                    let uc = upward_connectivity
317                                        .get_mut(sub_entity_type)
318                                        .unwrap()
319                                        .get_mut(et_ij)
320                                        .unwrap();
321                                    if !uc[ce_k[*rc_ijkl]].contains(ce_ij) {
322                                        uc[ce_k[*rc_ijkl]].push(*ce_ij);
323                                    }
324                                }
325                            }
326                        }
327                    }
328                }
329            }
330        }
331
332        let mut orientation = HashMap::new();
333        for types in entity_types.iter().skip(1) {
334            for t in types {
335                let dc = &downward_connectivity[t][&ReferenceCellType::Point];
336                orientation.insert(
337                    *t,
338                    (0..dc.shape()[1])
339                        .map(|i| {
340                            compute_orientation(
341                                *t,
342                                &dc.data().unwrap()[i * dc.shape()[0]..(i + 1) * dc.shape()[0]],
343                            )
344                        })
345                        .collect::<Vec<_>>(),
346                );
347            }
348        }
349
350        Self {
351            dim,
352            ids,
353            ids_to_indices,
354            insertion_indices,
355            entity_types,
356            entity_counts,
357            downward_connectivity,
358            upward_connectivity,
359            orientation,
360        }
361    }
362    /// Topological dimension
363    pub fn dim(&self) -> usize {
364        self.dim
365    }
366    /// Entity types
367    pub fn entity_types(&self) -> &[Vec<ReferenceCellType>] {
368        &self.entity_types
369    }
370    /// Entity counts
371    pub fn entity_counts(&self) -> &HashMap<ReferenceCellType, usize> {
372        &self.entity_counts
373    }
374    /// Entity counts
375    pub fn entity_count(&self, entity_type: ReferenceCellType) -> usize {
376        if let Some(n) = self.entity_counts.get(&entity_type) {
377            *n
378        } else {
379            0
380        }
381    }
382    /// Cell sub-entity index
383    pub fn cell_entity_index(
384        &self,
385        cell_type: ReferenceCellType,
386        cell_index: usize,
387        entity_type: ReferenceCellType,
388        entity_index: usize,
389    ) -> usize {
390        self.downward_connectivity[&cell_type][&entity_type][[entity_index, cell_index]]
391    }
392    /// Entity id
393    pub fn entity_id(&self, entity_type: ReferenceCellType, entity_index: usize) -> Option<usize> {
394        self.ids.get(&entity_type).map(|a| a[entity_index])
395    }
396}
397
398/// Topology of a cell
399#[derive(Debug)]
400pub struct MixedEntityTopology<'a> {
401    topology: &'a MixedTopology,
402    entity_type: ReferenceCellType,
403    entity_index: usize,
404}
405
406impl<'t> MixedEntityTopology<'t> {
407    /// Create new
408    pub fn new(
409        topology: &'t MixedTopology,
410        entity_type: ReferenceCellType,
411        entity_index: usize,
412    ) -> Self {
413        Self {
414            topology,
415            entity_type,
416            entity_index,
417        }
418    }
419}
420
421impl Topology for MixedEntityTopology<'_> {
422    type EntityDescriptor = ReferenceCellType;
423    type EntityIndexIter<'a>
424        = Copied<std::slice::Iter<'a, usize>>
425    where
426        Self: 'a;
427
428    type ConnectedEntityIndexIter<'a>
429        = Copied<std::slice::Iter<'a, usize>>
430    where
431        Self: 'a;
432
433    fn connected_entity_iter(
434        &self,
435        entity_type: ReferenceCellType,
436    ) -> Copied<std::slice::Iter<'_, usize>> {
437        self.topology.upward_connectivity[&self.entity_type][&entity_type][self.entity_index]
438            .iter()
439            .copied()
440    }
441
442    fn sub_entity_iter(
443        &self,
444        entity_type: ReferenceCellType,
445    ) -> Copied<std::slice::Iter<'_, usize>> {
446        let rows = self.topology.downward_connectivity[&self.entity_type][&entity_type].shape()[0];
447        self.topology.downward_connectivity[&self.entity_type][&entity_type]
448            .data()
449            .unwrap()[rows * self.entity_index..rows * (self.entity_index + 1)]
450            .iter()
451            .copied()
452    }
453
454    fn sub_entity(&self, entity_type: ReferenceCellType, index: usize) -> usize {
455        self.topology.downward_connectivity[&self.entity_type][&entity_type]
456            [[index, self.entity_index]]
457    }
458
459    fn orientation(&self) -> i32 {
460        if reference_cell::dim(self.entity_type) == 0 {
461            0
462        } else {
463            self.topology.orientation[&self.entity_type][self.entity_index]
464        }
465    }
466}
467
468#[cfg(test)]
469mod test {
470    use super::*;
471
472    fn example_topology_triangle_and_quad() -> MixedTopology {
473        //! An example topology
474        MixedTopology::new(
475            &[0, 1, 2, 3, 1, 3, 4],
476            &[
477                ReferenceCellType::Quadrilateral,
478                ReferenceCellType::Triangle,
479            ],
480            None,
481            None,
482        )
483    }
484
485    #[test]
486    fn test_prism() {
487        let _ = MixedTopology::new(&[0, 1, 2, 3, 4, 5], &[ReferenceCellType::Prism], None, None);
488    }
489    #[test]
490    fn test_pyramid() {
491        let _ = MixedTopology::new(&[0, 1, 2, 3, 4], &[ReferenceCellType::Pyramid], None, None);
492    }
493
494    #[test]
495    fn test_sub_entities_triangle_and_quad() {
496        //! Test sub-entities of a triangle
497        let t = example_topology_triangle_and_quad();
498        let cell0 = MixedEntityTopology::new(&t, ReferenceCellType::Quadrilateral, 0);
499        assert_eq!(cell0.sub_entity(ReferenceCellType::Point, 0), 0);
500        assert_eq!(cell0.sub_entity(ReferenceCellType::Point, 1), 1);
501        assert_eq!(cell0.sub_entity(ReferenceCellType::Point, 2), 2);
502        assert_eq!(cell0.sub_entity(ReferenceCellType::Point, 3), 3);
503        assert_eq!(cell0.sub_entity(ReferenceCellType::Interval, 0), 0);
504        assert_eq!(cell0.sub_entity(ReferenceCellType::Interval, 1), 1);
505        assert_eq!(cell0.sub_entity(ReferenceCellType::Interval, 2), 2);
506        assert_eq!(cell0.sub_entity(ReferenceCellType::Interval, 3), 3);
507        assert_eq!(cell0.sub_entity(ReferenceCellType::Quadrilateral, 0), 0);
508        let cell1 = MixedEntityTopology::new(&t, ReferenceCellType::Triangle, 0);
509        assert_eq!(cell1.sub_entity(ReferenceCellType::Point, 0), 1);
510        assert_eq!(cell1.sub_entity(ReferenceCellType::Point, 1), 3);
511        assert_eq!(cell1.sub_entity(ReferenceCellType::Point, 2), 4);
512        assert_eq!(cell1.sub_entity(ReferenceCellType::Interval, 0), 4);
513        assert_eq!(cell1.sub_entity(ReferenceCellType::Interval, 1), 5);
514        assert_eq!(cell1.sub_entity(ReferenceCellType::Interval, 2), 2);
515        assert_eq!(cell1.sub_entity(ReferenceCellType::Triangle, 0), 0);
516
517        let edge0 = MixedEntityTopology::new(&t, ReferenceCellType::Interval, 0);
518        assert_eq!(edge0.sub_entity(ReferenceCellType::Point, 0), 0);
519        assert_eq!(edge0.sub_entity(ReferenceCellType::Point, 1), 1);
520        assert_eq!(edge0.sub_entity(ReferenceCellType::Interval, 0), 0);
521        let edge1 = MixedEntityTopology::new(&t, ReferenceCellType::Interval, 1);
522        assert_eq!(edge1.sub_entity(ReferenceCellType::Point, 0), 0);
523        assert_eq!(edge1.sub_entity(ReferenceCellType::Point, 1), 2);
524        assert_eq!(edge1.sub_entity(ReferenceCellType::Interval, 0), 1);
525        let edge2 = MixedEntityTopology::new(&t, ReferenceCellType::Interval, 2);
526        assert_eq!(edge2.sub_entity(ReferenceCellType::Point, 0), 1);
527        assert_eq!(edge2.sub_entity(ReferenceCellType::Point, 1), 3);
528        assert_eq!(edge2.sub_entity(ReferenceCellType::Interval, 0), 2);
529        let edge3 = MixedEntityTopology::new(&t, ReferenceCellType::Interval, 3);
530        assert_eq!(edge3.sub_entity(ReferenceCellType::Point, 0), 2);
531        assert_eq!(edge3.sub_entity(ReferenceCellType::Point, 1), 3);
532        assert_eq!(edge3.sub_entity(ReferenceCellType::Interval, 0), 3);
533        let edge4 = MixedEntityTopology::new(&t, ReferenceCellType::Interval, 4);
534        assert_eq!(edge4.sub_entity(ReferenceCellType::Point, 0), 3);
535        assert_eq!(edge4.sub_entity(ReferenceCellType::Point, 1), 4);
536        assert_eq!(edge4.sub_entity(ReferenceCellType::Interval, 0), 4);
537        let edge5 = MixedEntityTopology::new(&t, ReferenceCellType::Interval, 5);
538        assert_eq!(edge5.sub_entity(ReferenceCellType::Point, 0), 1);
539        assert_eq!(edge5.sub_entity(ReferenceCellType::Point, 1), 4);
540        assert_eq!(edge5.sub_entity(ReferenceCellType::Interval, 0), 5);
541
542        let vertex0 = MixedEntityTopology::new(&t, ReferenceCellType::Point, 0);
543        assert_eq!(vertex0.sub_entity(ReferenceCellType::Point, 0), 0);
544        let vertex1 = MixedEntityTopology::new(&t, ReferenceCellType::Point, 1);
545        assert_eq!(vertex1.sub_entity(ReferenceCellType::Point, 0), 1);
546        let vertex2 = MixedEntityTopology::new(&t, ReferenceCellType::Point, 2);
547        assert_eq!(vertex2.sub_entity(ReferenceCellType::Point, 0), 2);
548        let vertex3 = MixedEntityTopology::new(&t, ReferenceCellType::Point, 3);
549        assert_eq!(vertex3.sub_entity(ReferenceCellType::Point, 0), 3);
550        let vertex4 = MixedEntityTopology::new(&t, ReferenceCellType::Point, 4);
551        assert_eq!(vertex4.sub_entity(ReferenceCellType::Point, 0), 4);
552    }
553}