Skip to main content

conspire/geometry/mesh/partition/agglomerate/
mod.rs

1#[cfg(test)]
2mod test;
3
4use super::Partition;
5use crate::{
6    geometry::{
7        Coordinates,
8        mesh::{Connectivities, Connectivity, Mesh},
9    },
10    math::{Set, Tensor, TensorVec},
11};
12use std::collections::HashMap;
13
14impl Partition {
15    pub fn agglomerate(&self, mesh: &Mesh<3>) -> Result<Mesh<3>, &'static str> {
16        let elements_faces = outward_faces(mesh)?;
17        let mut faces_nodes: Vec<Vec<usize>> = Vec::new();
18        let mut indices: HashMap<Vec<usize>, usize> = HashMap::new();
19        let mut cells = Vec::new();
20        for part in 0..self.number_of_parts() {
21            let elements = self.part_elements(part);
22            if elements.is_empty() {
23                continue;
24            }
25            let mut roots = (0..elements.len()).collect::<Vec<_>>();
26            let mut tally: HashMap<Vec<usize>, (usize, usize)> = HashMap::new();
27            let mut order: Vec<(&Vec<usize>, Vec<usize>)> = Vec::new();
28            for (position, &element) in elements.iter().enumerate() {
29                for face in &elements_faces[element] {
30                    let mut key = face.clone();
31                    key.sort_unstable();
32                    match tally.get_mut(&key) {
33                        Some((count, first)) => {
34                            *count += 1;
35                            let (a, b) = (find(&mut roots, *first), find(&mut roots, position));
36                            roots[b] = a;
37                        }
38                        None => {
39                            tally.insert(key.clone(), (1, position));
40                            order.push((face, key))
41                        }
42                    }
43                }
44            }
45            let root = find(&mut roots, 0);
46            if (1..elements.len()).any(|position| find(&mut roots, position) != root) {
47                return Err("a part is not connected through shared faces");
48            }
49            cells.push(
50                order
51                    .into_iter()
52                    .filter(|(_, key)| tally[key].0 == 1)
53                    .map(|(face, key)| {
54                        *indices.entry(key).or_insert_with(|| {
55                            faces_nodes.push(face.clone());
56                            faces_nodes.len() - 1
57                        })
58                    })
59                    .collect::<Vec<usize>>(),
60            );
61        }
62        let mut remap = vec![usize::MAX; mesh.number_of_nodes()];
63        faces_nodes
64            .iter()
65            .flatten()
66            .for_each(|&node| remap[node] = 0);
67        let mut coordinates = Coordinates::new();
68        remap.iter_mut().enumerate().for_each(|(node, new)| {
69            if *new == 0 {
70                *new = coordinates.len();
71                coordinates.push(mesh.coordinates()[node].clone())
72            }
73        });
74        faces_nodes
75            .iter_mut()
76            .flatten()
77            .for_each(|node| *node = remap[*node]);
78        Ok((
79            Connectivities::from(vec![Connectivity::Polyhedral((cells, faces_nodes).into())]),
80            Set::from(coordinates),
81        )
82            .into())
83    }
84}
85
86fn find(roots: &mut [usize], mut node: usize) -> usize {
87    while roots[node] != node {
88        roots[node] = roots[roots[node]];
89        node = roots[node]
90    }
91    node
92}
93
94fn outward_faces(mesh: &Mesh<3>) -> Result<Vec<Vec<Vec<usize>>>, &'static str> {
95    let mut elements_faces = Vec::with_capacity(mesh.number_of_elements());
96    for block in mesh.iter() {
97        match block {
98            Connectivity::Polyhedral(connectivity) => {
99                let mut owner = HashMap::new();
100                connectivity
101                    .elements_faces()
102                    .iter()
103                    .enumerate()
104                    .for_each(|(element, faces)| {
105                        faces.iter().for_each(|&face| {
106                            owner.entry(face).or_insert(element);
107                        })
108                    });
109                connectivity
110                    .elements_faces()
111                    .iter()
112                    .enumerate()
113                    .for_each(|(element, faces)| {
114                        elements_faces.push(
115                            faces
116                                .iter()
117                                .map(|&face| {
118                                    let mut nodes = connectivity.faces_nodes()[face].clone();
119                                    if owner[&face] != element {
120                                        nodes.reverse()
121                                    }
122                                    nodes
123                                })
124                                .collect(),
125                        )
126                    })
127            }
128            Connectivity::Polygonal(_)
129            | Connectivity::Quadrilateral(_)
130            | Connectivity::Triangular(_) => {
131                return Err("agglomeration requires three-dimensional elements");
132            }
133            _ => block
134                .iter()
135                .for_each(|element| elements_faces.push(block.element_faces(element))),
136        }
137    }
138    Ok(elements_faces)
139}