aeon_tk/geometry/tree/
interfaces.rs1use std::{array, cmp::Ordering, ops::Range};
2
3use super::{
4 NeighborId, Tree, TreeBlockNeighbor, TreeBlocks, TreeCellNeighbor, TreeNeighbors,
5 blocks::BlockId,
6};
7use crate::{
8 geometry::{IndexSpace, Side},
9 kernel::NodeSpace,
10 prelude::{FaceArray, HyperBox},
11};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct TreeInterface<const N: usize> {
15 pub block: BlockId,
17 pub neighbor: BlockId,
19 pub source: [isize; N],
21 pub dest: [isize; N],
23 pub size: [usize; N],
25}
26
27impl<const N: usize> datasize::DataSize for TreeInterface<N> {
28 const IS_DYNAMIC: bool = false;
29 const STATIC_HEAP_SIZE: usize = 0;
30
31 fn estimate_heap_size(&self) -> usize {
32 0
33 }
34}
35
36struct TransferAABB<const N: usize> {
37 source: [isize; N],
39 dest: [isize; N],
41 size: [usize; N],
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, Default)]
46pub struct TreeInterfaces<const N: usize> {
47 interfaces: Vec<TreeInterface<N>>,
49 interface_node_offsets: Vec<usize>,
51 interface_masks: Vec<bool>,
53}
54
55impl<const N: usize> TreeInterfaces<N> {
56 pub fn iter(&self) -> impl Iterator<Item = &TreeInterface<N>> {
57 self.interfaces.iter()
58 }
59
60 pub fn _num_interface_nodes(&self) -> usize {
62 *self.interface_node_offsets.last().unwrap()
63 }
64
65 pub fn interface(&self, neighbor: NeighborId) -> &TreeInterface<N> {
67 &self.interfaces[neighbor.0]
68 }
69
70 pub fn interface_nodes(&self, interface: NeighborId) -> Range<usize> {
72 self.interface_node_offsets[interface.0]..self.interface_node_offsets[interface.0 + 1]
73 }
74
75 pub fn interface_mask(&self, interface: NeighborId) -> &[bool] {
77 &self.interface_masks[self.interface_nodes(interface)]
78 }
79
80 pub fn interface_space(&self, interface: NeighborId) -> IndexSpace<N> {
82 IndexSpace::new(self.interfaces[interface.0].size)
83 }
84
85 pub fn interface_nodes_active(
87 &self,
88 interface: NeighborId,
89 _extent: usize,
90 ) -> impl Iterator<Item = [usize; N]> + '_ {
91 let space = self.interface_space(interface);
92 let mask = self.interface_mask(interface);
93
94 space
95 .iter()
96 .filter(move |&offset| mask[space.linear_from_cartesian(offset)])
97 }
98
99 pub fn build(&mut self, tree: &Tree<N>, blocks: &TreeBlocks<N>, neighbors: &TreeNeighbors<N>) {
100 self.interfaces.clear();
101 self.interface_node_offsets.clear();
102 self.interface_masks.clear();
103
104 for neighbor in neighbors.iter() {
105 let aabb = self.transfer_aabb(tree, blocks, neighbor);
106
107 self.interfaces.push(TreeInterface {
108 block: neighbor.block,
109 neighbor: neighbor.neighbor,
110 source: aabb.source,
111 dest: aabb.dest,
112 size: aabb.size,
113 });
114 }
115
116 let mut cursor = 0;
120
121 for interface in self.interfaces.iter() {
122 self.interface_node_offsets.push(cursor);
123 cursor += IndexSpace::new(interface.size).index_count();
124 }
125
126 self.interface_node_offsets.push(cursor);
127
128 self.interface_masks.resize(cursor, false);
132
133 let mut buffer = Vec::default();
134
135 for block in blocks.indices() {
136 let block_size = blocks.size(block);
137 let block_level = blocks.level(block);
138 let block_space = NodeSpace {
139 size: array::from_fn(|axis| block_size[axis] * blocks.width()[axis]),
140 ghost: blocks.ghost(),
141 bounds: HyperBox::<N>::UNIT,
142 boundary: FaceArray::default(),
143 };
144
145 buffer.resize(block_space.num_nodes(), usize::MAX);
146 buffer.fill(usize::MAX);
147
148 for iidx in neighbors.block_range(block) {
150 let interface = &self.interfaces[iidx];
151 let interface_level = blocks.level(interface.neighbor);
152
153 debug_assert!(interface.block == block);
154
155 for offset in IndexSpace::new(interface.size).iter() {
156 let node = array::from_fn(|axis| interface.dest[axis] + offset[axis] as isize);
157 let index = block_space.index_from_node(node);
158
159 if buffer[index] == usize::MAX {
160 buffer[index] = iidx;
161 continue;
162 }
163
164 let other_interface = &self.interfaces[buffer[index]];
165 let other_neighbor = other_interface.neighbor;
166
167 debug_assert!(other_interface.block == interface.block);
168
169 let other_level = blocks.level(other_neighbor);
170
171 if interface_level < other_level
176 || (interface_level == other_level && interface.neighbor < other_neighbor)
177 {
178 buffer[index] = iidx;
179 }
180 }
181 }
182
183 for iidx in neighbors.block_range(block) {
185 let interface = &self.interfaces[iidx];
186 let interface_level = blocks.level(interface.neighbor);
187
188 debug_assert!(interface.block == block);
189
190 let interface_mask_offset = self.interface_node_offsets[iidx];
191
192 for (dst, offset) in IndexSpace::new(interface.size).iter().enumerate() {
193 let node = array::from_fn(|axis| interface.dest[axis] + offset[axis] as isize);
194 let src = block_space.index_from_node(node);
195
196 let mut mask = buffer[src] == iidx;
198
199 if interface_level == block_level
200 && interface.block <= interface.neighbor
201 && block_space.is_interior(node)
202 {
203 mask = false;
204 }
205
206 self.interface_masks[interface_mask_offset + dst] = mask;
208 }
209 }
210 }
211 }
212
213 fn transfer_aabb(
215 &self,
216 tree: &Tree<N>,
217 blocks: &TreeBlocks<N>,
218 neighbor: &TreeBlockNeighbor<N>,
219 ) -> TransferAABB<N> {
220 let a = neighbor.a.clone();
221 let b = neighbor.b.clone();
222
223 let block_level = tree.active_level(a.cell);
224 let neighbor_level = tree.active_level(a.neighbor);
225
226 let (mut anode, mut bnode) = self.transfer_dest(tree, blocks, neighbor);
230
231 let mut source = self.transfer_source(tree, blocks, &neighbor.a);
235
236 for axis in 0..N {
237 if b.region.side(axis) == Side::Left && block_level < neighbor_level {
238 debug_assert!(a.region.side(axis) == Side::Left);
239 bnode[axis] -= 1;
240 }
241
242 if a.region.side(axis) == Side::Right && block_level < neighbor_level {
243 debug_assert!(b.region.side(axis) == Side::Right);
244
245 anode[axis] += 1;
246 source[axis] += 1;
247 }
248 }
249
250 let size = array::from_fn(|axis| {
251 if bnode[axis] >= anode[axis] {
252 (bnode[axis] - anode[axis] + 1) as usize
253 } else {
254 0
255 }
256 });
257
258 TransferAABB {
259 source,
260 dest: anode,
261 size,
262 }
263 }
264
265 #[inline]
266 fn transfer_dest(
267 &self,
268 tree: &Tree<N>,
269 blocks: &TreeBlocks<N>,
270 interface: &TreeBlockNeighbor<N>,
271 ) -> ([isize; N], [isize; N]) {
272 let a = interface.a.clone();
273 let b = interface.b.clone();
274
275 let aindex = blocks.active_cell_position(a.cell);
277 let bindex = blocks.active_cell_position(b.cell);
278
279 let block_level = tree.active_level(a.cell);
280 let neighbor_level = tree.active_level(a.neighbor);
281
282 let mut anode: [_; N] =
287 array::from_fn(|axis| (aindex[axis] * blocks.width()[axis]) as isize);
288
289 if block_level < neighbor_level {
290 let split = tree.most_recent_active_split(a.neighbor).unwrap();
291 (0..N)
292 .filter(|&axis| a.region.side(axis) == Side::Middle && split.is_set(axis))
293 .for_each(|axis| anode[axis] += (blocks.width()[axis] / 2) as isize);
294 }
295
296 for axis in 0..N {
298 match a.region.side(axis) {
299 Side::Left => {
300 anode[axis] -= blocks.ghost() as isize;
301 }
302 Side::Right => {
303 anode[axis] += blocks.width()[axis] as isize;
304 }
305 Side::Middle => {}
306 }
307 }
308
309 let mut bnode: [_; N] =
314 array::from_fn(|axis| ((bindex[axis] + 1) * blocks.width()[axis]) as isize);
315
316 if block_level < neighbor_level {
317 let split = tree.most_recent_active_split(b.neighbor).unwrap();
318 (0..N)
319 .filter(|&axis| b.region.side(axis) == Side::Middle && !split.is_set(axis))
320 .for_each(|axis| bnode[axis] -= (blocks.width()[axis] / 2) as isize);
321 }
322
323 for axis in 0..N {
325 match b.region.side(axis) {
326 Side::Right => {
327 bnode[axis] += blocks.ghost() as isize;
328 }
329 Side::Left => {
330 bnode[axis] -= blocks.width()[axis] as isize;
331 }
332 Side::Middle => {}
333 }
334 }
335
336 (anode, bnode)
337 }
338
339 #[inline]
341 fn transfer_source(
342 &self,
343 tree: &Tree<N>,
344 blocks: &TreeBlocks<N>,
345 a: &TreeCellNeighbor<N>,
346 ) -> [isize; N] {
347 let block_level = tree.active_level(a.cell);
348 let neighbor_level = tree.active_level(a.neighbor);
349
350 let nindex = blocks.active_cell_position(a.neighbor);
352 let mut source: [isize; N] =
353 array::from_fn(|axis| (nindex[axis] * blocks.width()[axis]) as isize);
354
355 match block_level.cmp(&neighbor_level) {
356 Ordering::Equal => {
357 for axis in 0..N {
358 if a.region.side(axis) == Side::Left {
359 source[axis] += (blocks.width()[axis] - blocks.ghost()) as isize;
360 }
361 }
362 }
363 Ordering::Greater => {
364 for axis in 0..N {
366 source[axis] *= 2;
367 }
368
369 let split = tree.most_recent_active_split(a.cell).unwrap();
370
371 for axis in 0..N {
372 if split.is_set(axis) {
373 match a.region.side(axis) {
374 Side::Left => {
375 source[axis] +=
376 blocks.width()[axis] as isize - blocks.ghost() as isize
377 }
378 Side::Middle => source[axis] += blocks.width()[axis] as isize,
379 Side::Right => {}
380 }
381 } else {
382 match a.region.side(axis) {
383 Side::Left => {
384 source[axis] +=
385 2 * blocks.width()[axis] as isize - blocks.ghost() as isize
386 }
387 Side::Middle => {}
388 Side::Right => source[axis] += blocks.width()[axis] as isize,
389 }
390 }
391 }
392 }
393 Ordering::Less => {
394 for axis in 0..N {
396 source[axis] /= 2;
397 }
398
399 for axis in 0..N {
400 if a.region.side(axis) == Side::Left {
401 source[axis] += blocks.width()[axis] as isize / 2 - blocks.ghost() as isize;
402 }
403 }
404 }
405 }
406
407 source
408 }
409}
410
411impl<const N: usize> datasize::DataSize for TreeInterfaces<N> {
412 const IS_DYNAMIC: bool = true;
413 const STATIC_HEAP_SIZE: usize = 0;
414
415 fn estimate_heap_size(&self) -> usize {
416 self.interfaces.estimate_heap_size()
417 + self.interface_node_offsets.estimate_heap_size()
418 + self.interface_masks.estimate_heap_size()
419 }
420}