Skip to main content

aeon_tk/mesh/
transfer.rs

1use crate::geometry::{ActiveCellId, IndexSpace, NeighborId, Split};
2use crate::image::ImageShared;
3use crate::kernel::Interpolation;
4use rayon::iter::{ParallelBridge, ParallelIterator as _};
5use reborrow::ReborrowMut;
6use std::array;
7
8use crate::{
9    image::{ImageMut, ImageRef},
10    kernel::SystemBoundaryConds,
11    mesh::Mesh,
12    shared::SharedSlice,
13};
14
15impl<const N: usize> Mesh<N> {
16    /// Transfers data from an older version of the mesh to the new refined version, using
17    /// the given order of interpolation.
18    pub fn transfer_system(&mut self, order: usize, source: ImageRef, dest: ImageMut) {
19        assert_eq!(source.num_channels(), dest.num_channels());
20        assert_eq!(dest.num_nodes(), self.num_nodes());
21        assert_eq!(source.num_nodes(), self.num_old_nodes());
22
23        match order {
24            2 => self.transfer_system_impl::<2>(source, dest),
25            4 => self.transfer_system_impl::<4>(source, dest),
26            6 => self.transfer_system_impl::<6>(source, dest),
27            _ => unimplemented!("Order unimplemented"),
28        }
29    }
30
31    /// Const optimized backend to `Mesh::<N>::transfer_system`.
32    fn transfer_system_impl<const ORDER: usize>(&mut self, source: ImageRef, dest: ImageMut) {
33        assert!(self.num_nodes() == dest.num_nodes());
34        assert!(self.num_old_nodes() == source.num_nodes());
35
36        let dest: ImageShared = dest.into();
37
38        self.old_block_compute(|mesh, _store, block| {
39            let size = mesh.old_blocks.size(block);
40            let level = mesh.old_block_level(block);
41            let nodes = mesh.old_block_nodes(block);
42            let space = mesh.old_block_space(block);
43
44            let block_source = source.slice(nodes.clone());
45
46            for (i, offset) in IndexSpace::new(size).iter().enumerate() {
47                let cell = mesh.old_blocks.active_cells(block)[i];
48                let cell_origin: [_; N] = array::from_fn(|axis| offset[axis] * mesh.width);
49
50                let new_cell = mesh.regrid_map[cell.0];
51                let new_level = mesh.tree.active_level(new_cell);
52
53                #[allow(clippy::comparison_chain)]
54                if new_level > level {
55                    // Loop over every child of the recently refined cell.
56                    for child in Split::<N>::enumerate() {
57                        // Retrieves new cell.
58                        let new_cell = ActiveCellId(new_cell.0 + child.to_linear());
59
60                        let new_block = mesh.blocks.active_cell_block(new_cell);
61                        let new_nodes = mesh.block_nodes(new_block);
62                        let new_space = mesh.block_space(new_block);
63
64                        let mut block_dest = unsafe { dest.slice_mut(new_nodes.clone()) };
65
66                        let mut cell_origin: [_; N] = array::from_fn(|axis| 2 * cell_origin[axis]);
67
68                        for axis in 0..N {
69                            if child.is_set(axis) {
70                                cell_origin[axis] += mesh.width;
71                            }
72                        }
73
74                        let node_size = mesh.cell_node_size(new_cell);
75                        let node_origin = mesh.active_node_origin(new_cell);
76
77                        for node_offset in IndexSpace::new(node_size).iter() {
78                            let source_node = array::from_fn(|axis| {
79                                (cell_origin[axis] + node_offset[axis]) as isize
80                            });
81                            let dest_node = array::from_fn(|axis| {
82                                (node_origin[axis] + node_offset[axis]) as isize
83                            });
84
85                            for field in dest.channels() {
86                                let v = space.prolong(
87                                    Interpolation::<ORDER>,
88                                    source_node,
89                                    block_source.channel(field),
90                                );
91                                block_dest.channel_mut(field)
92                                    [new_space.index_from_node(dest_node)] = v;
93                            }
94                        }
95                    }
96                } else if new_level == level {
97                    // Direct copy
98                    let new_block = mesh.blocks.active_cell_block(new_cell);
99                    let new_nodes = mesh.block_nodes(new_block);
100                    let new_space = mesh.block_space(new_block);
101
102                    let mut block_dest = unsafe { dest.slice_mut(new_nodes.clone()) };
103
104                    let node_size = mesh.cell_node_size(new_cell);
105                    let node_origin = mesh.active_node_origin(new_cell);
106
107                    for node_offset in IndexSpace::new(node_size).iter() {
108                        let source_node =
109                            array::from_fn(|axis| (cell_origin[axis] + node_offset[axis]) as isize);
110                        let dest_node =
111                            array::from_fn(|axis| (node_origin[axis] + node_offset[axis]) as isize);
112
113                        for field in dest.channels() {
114                            let v = block_source.channel(field)[space.index_from_node(source_node)];
115                            block_dest.channel_mut(field)[new_space.index_from_node(dest_node)] = v;
116                        }
117                    }
118                } else {
119                    // Coarsening
120                    let split = mesh.old_cell_splits[cell.0];
121
122                    let new_block = mesh.blocks.active_cell_block(new_cell);
123                    let new_offset = mesh.blocks.active_cell_position(new_cell);
124                    let new_size = mesh.blocks.size(new_block);
125                    let new_nodes = mesh.block_nodes(new_block);
126                    let new_space = mesh.block_space(new_block);
127
128                    let mut block_dest = unsafe { dest.slice_mut(new_nodes.clone()) };
129
130                    let cell_origin: [_; N] = array::from_fn(|axis| cell_origin[axis] / 2);
131
132                    let mut node_size = [mesh.width / 2; N];
133
134                    for axis in 0..N {
135                        if new_offset[axis] == new_size[axis] - 1 && split.is_set(axis) {
136                            node_size[axis] += 1;
137                        }
138                    }
139
140                    let mut node_origin: [_; N] =
141                        array::from_fn(|axis| new_offset[axis] * mesh.width);
142
143                    for axis in 0..N {
144                        if split.is_set(axis) {
145                            node_origin[axis] += mesh.width / 2;
146                        }
147                    }
148
149                    for node_offset in IndexSpace::new(node_size).iter() {
150                        let source_node = array::from_fn(|axis| {
151                            2 * (cell_origin[axis] + node_offset[axis]) as isize
152                        });
153                        let dest_node =
154                            array::from_fn(|axis| (node_origin[axis] + node_offset[axis]) as isize);
155
156                        for field in dest.channels() {
157                            let v = block_source.channel(field)[space.index_from_node(source_node)];
158                            block_dest.channel_mut(field)[new_space.index_from_node(dest_node)] = v;
159                        }
160                    }
161                }
162            }
163        });
164    }
165
166    /// Enforces strong boundary conditions. This includes strong physical boundary conditions, as well
167    /// as handling interior boundaries (same level, coarse-fine, or fine-coarse).
168    pub fn fill_boundary<BCs: SystemBoundaryConds<N> + Sync>(
169        &mut self,
170        order: usize,
171        bcs: BCs,
172        system: ImageMut,
173    ) {
174        assert_eq!(system.num_nodes(), self.num_nodes());
175
176        self.fill_boundary_to_extent(order, self.ghost, bcs, system);
177    }
178
179    /// Enforces strong boundary conditions, only filling ghost nodes if those nodes are within `extent`
180    /// of a physical node. This is useful if one is using Kriss-Olgier dissipation, where dissipation
181    /// and derivatives use different order stencils.
182    pub fn fill_boundary_to_extent<C: SystemBoundaryConds<N> + Sync>(
183        &mut self,
184        order: usize,
185        extent: usize,
186        bcs: C,
187        mut system: ImageMut,
188    ) {
189        assert_eq!(system.num_nodes(), self.num_nodes());
190        assert!(extent <= self.ghost);
191
192        self.fill_fine(extent, system.rb_mut());
193        self.fill_direct(extent, system.rb_mut());
194
195        self.fill_physical(extent, &bcs, system.rb_mut());
196        match order {
197            2 => self.fill_prolong::<2>(extent, system.rb_mut()),
198            4 => self.fill_prolong::<4>(extent, system.rb_mut()),
199            6 => self.fill_prolong::<6>(extent, system.rb_mut()),
200            _ => unimplemented!("Fill order not implemented"),
201        }
202        self.fill_physical(extent, &bcs, system.rb_mut());
203    }
204
205    /// Enforces physical boundary conditions near edge of the numerical domain, out to the given extent.
206    fn fill_physical<C: SystemBoundaryConds<N> + Sync>(
207        &mut self,
208        extent: usize,
209        bcs: &C,
210        dest: ImageMut,
211    ) {
212        debug_assert!(dest.num_nodes() == self.num_nodes());
213
214        let shared: ImageShared = dest.into();
215
216        self.blocks.indices().par_bridge().for_each(|block| {
217            // Fill Physical Boundary conditions
218            let nodes = self.block_nodes(block);
219            let space = self.block_space(block);
220            let bcs = self.block_bcs(block, bcs.clone());
221
222            let mut block_system = unsafe { shared.slice_mut(nodes) };
223
224            for field in shared.channels() {
225                space.fill_boundary(extent, bcs.field(field), block_system.channel_mut(field));
226            }
227        });
228    }
229
230    /// Fills ghost nodes via direct injection from neighbors on the same level of refinement.
231    fn fill_direct(&mut self, extent: usize, result: ImageMut) {
232        let shared: ImageShared = result.into();
233
234        // Fill direct neighbors
235        self.neighbors
236            .direct_indices()
237            .par_bridge()
238            .for_each(|interface| {
239                let info = self.interfaces.interface(interface);
240
241                let block_space = self.block_space(info.block);
242                let block_nodes = self.block_nodes(info.block);
243                let neighbor_space = self.block_space(info.neighbor);
244                let neighbor_nodes = self.block_nodes(info.neighbor);
245
246                let dest = info.dest;
247                let source = info.source;
248
249                let mut block_system = unsafe { shared.slice_mut(block_nodes) };
250                let neighbor_system = unsafe { shared.slice(neighbor_nodes) };
251
252                for node in self.interfaces.interface_nodes_active(interface, extent) {
253                    let block_node = array::from_fn(|axis| node[axis] as isize + dest[axis]);
254                    let neighbor_node = array::from_fn(|axis| node[axis] as isize + source[axis]);
255
256                    let block_index = block_space.index_from_node(block_node);
257                    let neighbor_index = neighbor_space.index_from_node(neighbor_node);
258
259                    for field in shared.channels() {
260                        let value = neighbor_system.channel(field)[neighbor_index];
261                        block_system.channel_mut(field)[block_index] = value;
262                    }
263                }
264            });
265    }
266
267    /// Fills ghost nodes via injection from neighbors at a higher level of refinement.
268    fn fill_fine(&mut self, extent: usize, result: ImageMut) {
269        let shared: ImageShared = result.into();
270
271        self.neighbors
272            .fine_indices()
273            .par_bridge()
274            .for_each(|interface| {
275                let info = self.interfaces.interface(interface);
276
277                let block_space = self.block_space(info.block);
278                let block_nodes = self.block_nodes(info.block);
279                let neighbor_space = self.block_space(info.neighbor);
280                let neighbor_nodes = self.block_nodes(info.neighbor);
281
282                let mut block_system = unsafe { shared.slice_mut(block_nodes) };
283                let neighbor_system = unsafe { shared.slice(neighbor_nodes) };
284
285                for node in self.interfaces.interface_nodes_active(interface, extent) {
286                    let block_node = array::from_fn(|axis| node[axis] as isize + info.dest[axis]);
287                    let neighbor_node =
288                        array::from_fn(|axis| 2 * (node[axis] as isize + info.source[axis]));
289
290                    let block_index = block_space.index_from_node(block_node);
291                    let neighbor_index = neighbor_space.index_from_node(neighbor_node);
292
293                    for field in shared.channels() {
294                        let value = neighbor_system.channel(field)[neighbor_index];
295                        block_system.channel_mut(field)[block_index] = value;
296                    }
297                }
298            });
299    }
300
301    /// Fills ghost nodes by interpolating from neighbors at a lower level of refinement.
302    fn fill_prolong<const ORDER: usize>(&mut self, extent: usize, result: ImageMut) {
303        let shared: ImageShared = result.into();
304
305        self.neighbors
306            .coarse_indices()
307            .par_bridge()
308            .for_each(|interface| {
309                let info = self.interfaces.interface(interface);
310
311                let block_nodes = self.block_nodes(info.block);
312                let block_space = self.block_space(info.block);
313                let neighbor_nodes = self.block_nodes(info.neighbor);
314                let neighbor_space = self.block_space(info.neighbor);
315
316                let mut block_system = unsafe { shared.slice_mut(block_nodes) };
317                let neighbor_system = unsafe { shared.slice(neighbor_nodes) };
318
319                for node in self.interfaces.interface_nodes_active(interface, extent) {
320                    let block_node = array::from_fn(|axis| node[axis] as isize + info.dest[axis]);
321
322                    let neighbor_node =
323                        array::from_fn(|axis| node[axis] as isize + info.source[axis]);
324                    let block_index = block_space.index_from_node(block_node);
325
326                    for field in shared.channels() {
327                        let value = neighbor_space.prolong(
328                            Interpolation::<ORDER>,
329                            neighbor_node,
330                            neighbor_system.channel(field),
331                        );
332                        block_system.channel_mut(field)[block_index] = value;
333                    }
334                }
335            });
336    }
337
338    /// Stores the index of the block which owns each individual node in a debug vector.
339    pub fn block_debug(&mut self, debug: &mut [i64]) {
340        assert!(debug.len() == self.num_nodes());
341
342        let debug = SharedSlice::new(debug);
343
344        self.block_compute(|mesh, _, block| {
345            let block_nodes = mesh.block_nodes(block);
346
347            for node in block_nodes {
348                unsafe {
349                    *debug.get_mut(node) = block.0 as i64;
350                }
351            }
352        });
353    }
354
355    /// Stores the index of the cell which owns each individual node in a debug vector.
356    pub fn cell_debug(&mut self, debug: &mut [i64]) {
357        assert!(debug.len() == self.num_nodes());
358
359        let debug = SharedSlice::new(debug);
360
361        self.block_compute(|mesh, _, block| {
362            let block_nodes = mesh.block_nodes(block);
363            let block_space = mesh.block_space(block);
364            let block_size = mesh.blocks.size(block);
365            let cells = mesh.blocks.active_cells(block);
366
367            for (i, position) in IndexSpace::new(block_size).iter().enumerate() {
368                let cell = cells[i];
369                let origin: [_; N] = array::from_fn(|axis| (position[axis] * mesh.width) as isize);
370
371                for offset in IndexSpace::new([mesh.width + 1; N]).iter() {
372                    let node = array::from_fn(|axis| origin[axis] + offset[axis] as isize);
373
374                    let idx = block_nodes.start + block_space.index_from_node(node);
375
376                    unsafe {
377                        *debug.get_mut(idx) = cell.0 as i64;
378                    }
379                }
380            }
381        });
382    }
383
384    /// Stores the index of the neighbor along each interface.
385    pub fn interface_neighbor_debug(&mut self, extent: usize, debug: &mut [i64]) {
386        debug.fill(-1);
387
388        let debug = SharedSlice::new(debug);
389
390        self.interfaces
391            .iter()
392            .enumerate()
393            .for_each(|(iidx, interface)| {
394                let block_nodes = self.block_nodes(interface.block);
395                let block_space = self.block_space(interface.block);
396
397                for offset in self
398                    .interfaces
399                    .interface_nodes_active(NeighborId(iidx), extent)
400                {
401                    let node = array::from_fn(|axis| interface.dest[axis] + offset[axis] as isize);
402                    let index = block_space.index_from_node(node);
403
404                    unsafe {
405                        *debug.get_mut(block_nodes.start + index) = interface.neighbor.0 as i64;
406                    }
407                }
408            });
409    }
410
411    /// Stores the index of each interface for nodes along that interface.
412    pub fn interface_index_debug(&mut self, extent: usize, debug: &mut [i64]) {
413        debug.fill(-1);
414
415        let debug = SharedSlice::new(debug);
416
417        self.interfaces
418            .iter()
419            .enumerate()
420            .for_each(|(iidx, interface)| {
421                let block_nodes = self.block_nodes(interface.block);
422                let block_space = self.block_space(interface.block);
423
424                for offset in self
425                    .interfaces
426                    .interface_nodes_active(NeighborId(iidx), extent)
427                {
428                    let node = array::from_fn(|axis| interface.dest[axis] + offset[axis] as isize);
429                    let index = block_space.index_from_node(node);
430
431                    unsafe {
432                        *debug.get_mut(block_nodes.start + index) = iidx as i64;
433                    }
434                }
435            });
436    }
437}