Skip to main content

aeon_tk/geometry/tree/
neighbors.rs

1use super::{blocks::BlockId, *};
2
3#[derive(
4    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, serde::Serialize, serde::Deserialize,
5)]
6pub struct NeighborId(pub usize);
7
8/// Stores neighbor of a cell on a tree.
9#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10pub struct TreeCellNeighbor<const N: usize> {
11    /// Primary cell.
12    pub cell: ActiveCellId,
13    /// Neighbor cell.
14    pub neighbor: ActiveCellId,
15    /// Which region is the neighbor cell in?
16    pub region: Region<N>,
17    /// Which periodic region is the neighbor cell in?
18    pub boundary_region: Region<N>,
19}
20
21/// Neighbor of block.
22#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
23pub struct TreeBlockNeighbor<const N: usize> {
24    /// Primary block.
25    pub block: BlockId,
26    /// Neighbor block.
27    pub neighbor: BlockId,
28    /// Leftmost cell neighbor.
29    pub a: TreeCellNeighbor<N>,
30    /// Rightmost cell neighbor.
31    pub b: TreeCellNeighbor<N>,
32}
33
34impl<const N: usize> DataSize for TreeBlockNeighbor<N> {
35    const IS_DYNAMIC: bool = false;
36    const STATIC_HEAP_SIZE: usize = 0;
37
38    fn estimate_heap_size(&self) -> usize {
39        0
40    }
41}
42
43impl<const N: usize> TreeBlockNeighbor<N> {
44    /// If this is a face neighbor, return the corresponding face, otherwise return `None`.
45    pub fn face(&self) -> Option<Face<N>> {
46        regions_to_face(self.a.region, self.b.region)
47    }
48}
49
50fn regions_to_face<const N: usize>(a: Region<N>, b: Region<N>) -> Option<Face<N>> {
51    let mut adjacency = 0;
52    let mut faxis = 0;
53    let mut fside = false;
54
55    for axis in 0..N {
56        let aside = a.side(axis);
57        let bside = b.side(axis);
58
59        if aside == bside && aside != Side::Middle {
60            adjacency += 1;
61            faxis = axis;
62            fside = aside == Side::Right;
63        }
64    }
65
66    if adjacency == 1 {
67        Some(Face {
68            axis: faxis,
69            side: fside,
70        })
71    } else {
72        None
73    }
74}
75
76/// Stores information about neighbors of blocks and cells.
77#[derive(Default, Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
78pub struct TreeNeighbors<const N: usize> {
79    /// Flattened list of lists of neighbors for each block.
80    neighbors: Vec<TreeBlockNeighbor<N>>,
81    /// Offset map for blocks -> neighbors.
82    block_offsets: Vec<usize>,
83    /// A cached list of all fine interfaces.
84    fine: Vec<usize>,
85    /// A cached list of all direct interfaces.
86    direct: Vec<usize>,
87    /// A cached list of all coarse interfaces.
88    coarse: Vec<usize>,
89}
90
91impl<const N: usize> TreeNeighbors<N> {
92    /// Iterates over all fine `BlockInterface`s.
93    pub fn fine(&self) -> impl Iterator<Item = &TreeBlockNeighbor<N>> {
94        self.fine.iter().map(|&i| &self.neighbors[i])
95    }
96
97    /// Iterates over all fine `BlockInterface`s.
98    pub fn direct(&self) -> impl Iterator<Item = &TreeBlockNeighbor<N>> {
99        self.direct.iter().map(|&i| &self.neighbors[i])
100    }
101
102    /// Iterates over all fine `BlockInterface`s.
103    pub fn coarse(&self) -> impl Iterator<Item = &TreeBlockNeighbor<N>> {
104        self.coarse.iter().map(|&i| &self.neighbors[i])
105    }
106
107    /// Iterates over all interfaces in the mesh.
108    pub fn iter(&self) -> slice::Iter<'_, TreeBlockNeighbor<N>> {
109        self.neighbors.iter()
110    }
111
112    pub fn indices(&self) -> impl Iterator<Item = NeighborId> {
113        (0..self.neighbors.len()).map(NeighborId)
114    }
115
116    pub fn fine_indices(&self) -> impl Iterator<Item = NeighborId> + '_ {
117        self.fine.iter().copied().map(NeighborId)
118    }
119
120    pub fn direct_indices(&self) -> impl Iterator<Item = NeighborId> + '_ {
121        self.direct.iter().copied().map(NeighborId)
122    }
123
124    pub fn coarse_indices(&self) -> impl Iterator<Item = NeighborId> + '_ {
125        self.coarse.iter().copied().map(NeighborId)
126    }
127
128    /// Iterates over all neighbors of a block.
129    pub fn block(&self, block: BlockId) -> slice::Iter<'_, TreeBlockNeighbor<N>> {
130        self.neighbors[self.block_offsets[block.0]..self.block_offsets[block.0 + 1]].iter()
131    }
132
133    /// Returns the range of neighbor indices belonging to a given block.
134    pub fn block_range(&self, block: BlockId) -> Range<usize> {
135        self.block_offsets[block.0]..self.block_offsets[block.0 + 1]
136    }
137
138    pub fn neighbor(&self, idx: NeighborId) -> &TreeBlockNeighbor<N> {
139        &self.neighbors[idx.0]
140    }
141
142    /// Rebuilds the block interface data.
143    pub fn build(&mut self, tree: &Tree<N>, blocks: &TreeBlocks<N>) {
144        self.neighbors.clear();
145        self.block_offsets.clear();
146        self.fine.clear();
147        self.coarse.clear();
148        self.direct.clear();
149
150        // Reused memory for neighbors.
151        let mut neighbors = Vec::new();
152
153        for block in blocks.indices() {
154            self.block_offsets.push(self.neighbors.len());
155
156            // Build cell neighbors.
157            neighbors.clear();
158            Self::build_cell_neighbors(tree, blocks, block, &mut neighbors);
159
160            // Sort neighbors (to group cells from the same block together).
161            neighbors.sort_unstable_by(|left, right| {
162                let lblock = blocks.active_cell_block(left.neighbor);
163                let rblock = blocks.active_cell_block(right.neighbor);
164
165                left.boundary_region
166                    .cmp(&right.boundary_region)
167                    .then(lblock.cmp(&rblock))
168                    .then(left.neighbor.cmp(&right.neighbor))
169                    .then(left.cell.cmp(&right.cell))
170                    .then(left.region.cmp(&right.region))
171            });
172
173            Self::taverse_cell_neighbors(blocks, &mut neighbors, |neighbor, a, b| {
174                let acell = tree.cell_from_active_index(a.cell);
175                let aneighbor = tree.cell_from_active_index(a.neighbor);
176
177                // Compute this boundary interface.
178                let kind = InterfaceKind::from_levels(tree.level(acell), tree.level(aneighbor));
179                let interface = TreeBlockNeighbor {
180                    block,
181                    neighbor,
182                    a,
183                    b,
184                };
185
186                let idx = self.neighbors.len();
187                self.neighbors.push(interface);
188
189                match kind {
190                    InterfaceKind::Fine => self.fine.push(idx),
191                    InterfaceKind::Direct => self.direct.push(idx),
192                    InterfaceKind::Coarse => self.coarse.push(idx),
193                }
194            });
195        }
196
197        self.block_offsets.push(self.neighbors.len());
198    }
199
200    /// Iterates the cell neighbors of a block, and pushes them onto the memory stack.
201    fn build_cell_neighbors(
202        tree: &Tree<N>,
203        blocks: &TreeBlocks<N>,
204        block: BlockId,
205        neighbors: &mut Vec<TreeCellNeighbor<N>>,
206    ) {
207        let block_size = blocks.size(block);
208        let block_active_cells = blocks.active_cells(block);
209        let block_space = IndexSpace::new(block_size);
210
211        debug_assert!(block_size.iter().product::<usize>() == block_active_cells.len());
212
213        for region in regions::<N>() {
214            if region == Region::CENTRAL {
215                continue;
216            }
217
218            // Find all cells adjacent to the given region.
219            for index in block_space.region_adjacent_window(region) {
220                let active = block_active_cells[block_space.linear_from_cartesian(index)];
221                let cell = tree.cell_from_active_index(active);
222                let periodic = tree.boundary_region(cell, region);
223
224                for neighbor in tree.active_neighbors_in_region(cell, region) {
225                    neighbors.push(TreeCellNeighbor {
226                        cell: active,
227                        neighbor,
228                        region,
229                        boundary_region: periodic,
230                    })
231                }
232            }
233        }
234    }
235
236    /// Traverses a sorted list of cell neighbors, calling f once for each distinct block.
237    fn taverse_cell_neighbors(
238        blocks: &TreeBlocks<N>,
239        neighbors: &mut [TreeCellNeighbor<N>],
240        mut f: impl FnMut(BlockId, TreeCellNeighbor<N>, TreeCellNeighbor<N>),
241    ) {
242        let mut neighbors = neighbors.iter().cloned().peekable();
243
244        while let Some(a) = neighbors.next() {
245            let neighbor = blocks.active_cell_block(a.neighbor);
246
247            // Next we walk through the iterator until we find the last neighbor that is still in this block.
248            let mut b = a.clone();
249
250            loop {
251                if let Some(next) = neighbors.peek() {
252                    if a.boundary_region == next.boundary_region
253                        && neighbor == blocks.active_cell_block(next.neighbor)
254                    {
255                        b = neighbors.next().unwrap();
256                        continue;
257                    }
258                }
259
260                break;
261            }
262
263            f(neighbor, a, b)
264        }
265    }
266}
267
268impl<const N: usize> DataSize for TreeNeighbors<N> {
269    const IS_DYNAMIC: bool = true;
270    const STATIC_HEAP_SIZE: usize = 0;
271
272    fn estimate_heap_size(&self) -> usize {
273        self.neighbors.estimate_heap_size()
274            + self.block_offsets.estimate_heap_size()
275            + self.fine.estimate_heap_size()
276            + self.direct.estimate_heap_size()
277            + self.coarse.estimate_heap_size()
278    }
279}
280
281#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
282enum InterfaceKind {
283    Coarse,
284    Direct,
285    Fine,
286}
287
288impl InterfaceKind {
289    fn from_levels(level: usize, neighbor: usize) -> Self {
290        match level as isize - neighbor as isize {
291            1 => InterfaceKind::Coarse,
292            0 => InterfaceKind::Direct,
293            -1 => InterfaceKind::Fine,
294            _ => panic!("Unbalanced levels"),
295        }
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302    use crate::geometry::HyperBox;
303
304    #[test]
305    fn regions_and_faces() {
306        assert_eq!(regions_to_face::<2>(Region::CENTRAL, Region::CENTRAL), None);
307        assert_eq!(
308            regions_to_face(
309                Region::new([Side::Left, Side::Middle]),
310                Region::new([Side::Left, Side::Left])
311            ),
312            Some(Face::negative(0))
313        );
314        assert_eq!(
315            regions_to_face(
316                Region::new([Side::Left, Side::Right]),
317                Region::new([Side::Left, Side::Right])
318            ),
319            None
320        );
321        assert_eq!(
322            regions_to_face(
323                Region::new([Side::Left, Side::Right]),
324                Region::new([Side::Middle, Side::Right])
325            ),
326            Some(Face::positive(1))
327        );
328        assert_eq!(
329            regions_to_face(
330                Region::new([Side::Middle, Side::Right]),
331                Region::new([Side::Middle, Side::Right])
332            ),
333            Some(Face::positive(1))
334        );
335    }
336
337    #[test]
338    fn neighbors() {
339        let mut tree = Tree::new(HyperBox::<2>::UNIT);
340        let mut blocks = TreeBlocks::new([4; 2], 2);
341        let mut interfaces = TreeNeighbors::default();
342        tree.refine(&[true]);
343        tree.refine(&[true, false, false, false]);
344        blocks.build(&tree);
345        interfaces.build(&tree, &blocks);
346
347        let mut coarse = interfaces.coarse();
348
349        assert_eq!(
350            coarse.next(),
351            Some(&TreeBlockNeighbor {
352                block: BlockId(0),
353                neighbor: BlockId(1),
354                a: TreeCellNeighbor {
355                    cell: ActiveCellId(1),
356                    neighbor: ActiveCellId(4),
357                    region: Region::new([Side::Right, Side::Middle]),
358                    boundary_region: Region::CENTRAL,
359                },
360                b: TreeCellNeighbor {
361                    cell: ActiveCellId(3),
362                    neighbor: ActiveCellId(6),
363                    region: Region::new([Side::Right, Side::Right]),
364                    boundary_region: Region::CENTRAL,
365                }
366            })
367        );
368
369        assert_eq!(
370            coarse.next(),
371            Some(&TreeBlockNeighbor {
372                block: BlockId(0),
373                neighbor: BlockId(2),
374                a: TreeCellNeighbor {
375                    cell: ActiveCellId(2),
376                    neighbor: ActiveCellId(5),
377                    region: Region::new([Side::Middle, Side::Right]),
378                    boundary_region: Region::CENTRAL,
379                },
380                b: TreeCellNeighbor {
381                    cell: ActiveCellId(3),
382                    neighbor: ActiveCellId(5),
383                    region: Region::new([Side::Middle, Side::Right]),
384                    boundary_region: Region::CENTRAL,
385                }
386            })
387        );
388        assert_eq!(coarse.next(), None);
389    }
390}