Skip to main content

aeon_tk/mesh/
regrid.rs

1use std::array;
2
3use crate::geometry::{ActiveCellId, IndexSpace};
4
5use crate::image::ImageRef;
6use crate::{mesh::Mesh, shared::SharedSlice};
7
8impl<const N: usize> Mesh<N> {
9    /// Retrieves a vector representing all regridding flags for the mesh.
10    pub fn refine_flags(&self) -> &[bool] {
11        self.refine_flags.as_slice()
12    }
13    /// Retrievs a vector representing all coarsening flags for the mesh.
14    pub fn coarsen_flags(&self) -> &[bool] {
15        self.coarsen_flags.as_slice()
16    }
17
18    /// Refines the mesh using currently set flags.
19    pub fn regrid(&mut self) {
20        self.regrid_map.clear();
21
22        // Save old information
23        self.old_blocks.clone_from(&self.blocks);
24
25        self.old_cell_splits.clear();
26        self.old_cell_splits.extend(
27            self.tree
28                .active_cell_indices()
29                .flat_map(|cell| self.tree.most_recent_active_split(cell)),
30        );
31
32        // Perform regriding
33        self.regrid_map
34            .resize(self.tree.num_active_cells(), ActiveCellId(0));
35
36        let mut coarsen_map = vec![ActiveCellId(0); self.tree.num_active_cells()];
37        self.tree
38            .coarsen_active_index_map(&self.coarsen_flags, &mut coarsen_map);
39
40        debug_assert!(self.tree.check_coarsen_flags(&self.coarsen_flags));
41        self.tree.coarsen(&self.coarsen_flags);
42
43        let mut refine_map = vec![ActiveCellId(0); self.tree.num_active_cells()];
44        let mut flags = vec![false; self.tree.num_active_cells()];
45
46        for (old, &new) in coarsen_map.iter().enumerate() {
47            flags[new.0] = self.refine_flags[old];
48        }
49
50        self.tree.refine_active_index_map(&flags, &mut refine_map);
51
52        debug_assert!(self.tree.check_refine_flags(&flags));
53        self.tree.refine(&flags);
54
55        for i in 0..self.regrid_map.len() {
56            self.regrid_map[i] = refine_map[coarsen_map[i].0];
57        }
58
59        // Rebuild mesh
60        self.build();
61    }
62
63    /// Flags every cell for refinement, then performs the operation.
64    pub fn refine_global(&mut self) {
65        self.refine_flags.fill(true);
66        self.regrid();
67    }
68
69    /// Refines innermost cell
70    pub fn refine_innermost(&mut self) {
71        let mut temp_rflags = vec![false; self.tree().num_active_cells()];
72        // Find the innermost cell and flag it for refinement
73        let mut cell_inner_index = 0;
74        let mut cell_inner_center = f64::MAX;
75        for cell in self.tree().active_cell_indices() {
76            let cell_bounds = self.tree().active_bounds(cell);
77            let cell_center = cell_bounds.center()[0]; // get 1st element because we only have 1 dimension
78            if cell_center < cell_inner_center {
79                cell_inner_center = cell_center;
80                cell_inner_index = cell.0;
81            }
82        }
83        // Set flag and refine
84        temp_rflags[cell_inner_index] = true;
85        self.refine_flags = temp_rflags;
86        self.balance_flags();
87        self.regrid();
88    }
89
90    /// Coarsens innermost cell
91    pub fn coarsen_innermost(&mut self) {
92        let mut temp_cflags = vec![false; self.tree().num_active_cells()];
93        // Find the innermost cell and flag it for coarsening
94        let mut cell_inner_index = 0;
95        let mut cell_inner_center = f64::MAX;
96        for cell in self.tree().active_cell_indices() {
97            let cell_bounds = self.tree().active_bounds(cell);
98            let cell_center = cell_bounds.center()[0]; // get 1st element because we only have 1 dimension
99            if cell_center < cell_inner_center {
100                cell_inner_center = cell_center;
101                cell_inner_index = cell.0;
102            }
103        }
104        // Set flag and refine
105        temp_cflags[cell_inner_index] = true;
106        self.coarsen_flags = temp_cflags;
107        self.balance_flags();
108        self.regrid();
109    }
110
111    /// Refines or coarsens cells one level (towards target level fgl) within a given radius
112    pub fn regrid_in_radius(&mut self, radius: f64, fgl: usize) {
113        // Loop through the active cells and flag any that need to be refined or coarsened
114        self.refine_flags.fill(false);
115        self.coarsen_flags.fill(false);
116        let mut temp_rflags = vec![false; self.tree().num_active_cells()];
117        let mut temp_cflags = vec![false; self.tree().num_active_cells()];
118        for cell in self.tree().active_cell_indices() {
119            // Get some information about the cell
120            let cell_bounds = self.tree().active_bounds(cell);
121            let cell_center = cell_bounds.center()[0]; // get 1st element because we only have 1 dimension
122            let cell_level = self.tree().active_level(cell);
123            let cell_index = cell.0;
124            // Set flags if necessary
125            if cell_center < radius {
126                if cell_level < fgl {
127                    temp_rflags[cell_index] = true;
128                }
129                if cell_level > fgl {
130                    temp_cflags[cell_index] = true;
131                }
132            }
133        }
134        // Update the mesh's flags
135        self.refine_flags = temp_rflags;
136        self.coarsen_flags = temp_cflags;
137        // Perform the regridding
138        self.balance_flags();
139        self.regrid();
140    }
141
142    /// Flags cells for refinement using a wavelet criterion. The system must have filled
143    /// boundaries. This function tags any cell that is insufficiently refined to approximate
144    /// operators of the given `order` within the range of error.
145    pub fn flag_wavelets(&mut self, order: usize, lower: f64, upper: f64, data: ImageRef) {
146        let buffer = 2 * (self.ghost / 2);
147        let support = (self.width + 2 * buffer) / 2;
148
149        assert!(order % 2 == 0);
150        assert!(order <= support);
151        // Example w = 6, g = 3, o = 6
152        // -> o > (6 + 4) / 2 because the ghost offset is odd
153
154        assert_eq!(data.num_nodes(), self.num_nodes());
155
156        let element = self.request_element(support, order);
157        let element_coarse = self.request_element(self.width / 2, order / 2);
158
159        let support = element.support_refined();
160
161        let mut rflags_buf = std::mem::take(&mut self.refine_flags);
162        let mut cflags_buf = std::mem::take(&mut self.coarsen_flags);
163
164        // Allows interior mutability.
165        let rflags = SharedSlice::new(&mut rflags_buf);
166        let cflags = SharedSlice::new(&mut cflags_buf);
167
168        self.block_compute(|mesh, store, block| {
169            let imsrc = store.scratch(support);
170            let imdest = store.scratch(support);
171
172            let nodes = mesh.block_nodes(block);
173            let space = mesh.block_space(block);
174
175            let block_system = data.slice(nodes.clone());
176
177            for &cell in mesh.blocks.active_cells(block) {
178                let is_cell_on_boundary = mesh.cell_needs_coarse_element(cell);
179
180                // Window of nodes on element.
181                let window = if is_cell_on_boundary {
182                    mesh.element_coarse_window(cell)
183                } else {
184                    mesh.element_window(cell)
185                };
186
187                let mut should_refine = false;
188                let mut should_coarsen = true;
189
190                for field in data.channels() {
191                    // Unpack data to element
192                    for (i, node) in window.iter().enumerate() {
193                        imsrc[i] = block_system.channel(field)[space.index_from_node(node)];
194                    }
195
196                    if is_cell_on_boundary {
197                        let src = &imsrc[..element_coarse.support_refined()];
198                        let dst = &mut imdest[..element_coarse.support_refined()];
199
200                        element_coarse.wavelet(src, dst);
201
202                        for point in element_coarse.diagonal_points() {
203                            should_refine = should_refine || dst[point].abs() >= upper;
204                            should_coarsen = should_coarsen && dst[point].abs() <= lower;
205                        }
206                    } else {
207                        element.wavelet(imsrc, imdest);
208
209                        for point in element.diagonal_int_points(buffer) {
210                            should_refine = should_refine || imdest[point].abs() >= upper;
211                            should_coarsen = should_coarsen && imdest[point].abs() <= lower;
212                        }
213                    }
214
215                    unsafe {
216                        if should_refine {
217                            *rflags.get_mut(cell.0) = true;
218                        }
219                    }
220
221                    unsafe {
222                        *cflags.get_mut(cell.0) = should_coarsen;
223                    }
224                }
225            }
226        });
227
228        let _ = std::mem::replace(&mut self.refine_flags, rflags_buf);
229        let _ = std::mem::replace(&mut self.coarsen_flags, cflags_buf);
230
231        self.replace_element(element);
232        self.replace_element(element_coarse);
233    }
234
235    /// Store flags for each cell in a debug buffer.
236    pub fn flags_debug(&mut self, debug: &mut [i64]) {
237        assert!(debug.len() == self.num_nodes());
238
239        let debug = SharedSlice::new(debug);
240
241        self.block_compute(|mesh, _, block| {
242            let block_nodes = mesh.block_nodes(block);
243            let block_space = mesh.block_space(block);
244            let block_size = mesh.blocks.size(block);
245            let cells = mesh.blocks.active_cells(block);
246
247            for (i, position) in IndexSpace::new(block_size).iter().enumerate() {
248                let cell = cells[i];
249                let origin: [_; N] = array::from_fn(|axis| (position[axis] * mesh.width) as isize);
250
251                for offset in IndexSpace::new([mesh.width + 1; N]).iter() {
252                    let node = array::from_fn(|axis| origin[axis] + offset[axis] as isize);
253
254                    let idx = block_nodes.start + block_space.index_from_node(node);
255
256                    unsafe {
257                        *debug.get_mut(idx) = mesh.refine_flags[cell.0] as i64;
258                    }
259                }
260            }
261        });
262    }
263
264    /// Manually marks a cell for refinement.
265    pub fn set_refine_flag(&mut self, cell: usize) {
266        self.refine_flags[cell] = true
267    }
268
269    /// Manually marks a cell for coarsening.
270    pub fn set_coarsen_flag(&mut self, cell: usize) {
271        self.coarsen_flags[cell] = true
272    }
273
274    // Mark `count` cells around each currently tagged cell for refinement.
275    pub fn buffer_refine_flags(&mut self, count: usize) {
276        for _ in 0..count {
277            for cell in self.tree.active_cell_indices() {
278                if !self.refine_flags[cell.0] {
279                    continue;
280                }
281
282                for neighbor in self.tree.active_neighborhood(cell) {
283                    self.refine_flags[neighbor.0] = true;
284                }
285            }
286        }
287    }
288
289    /// Limits coarsening to cells with a `level > min_level`, and refinement to
290    /// cells with a `level < max_level`.
291    pub fn limit_level_range_flags(&mut self, min_level: usize, max_level: usize) {
292        assert!(self.refine_flags.len() == self.num_active_cells());
293        assert!(self.coarsen_flags.len() == self.num_active_cells());
294
295        for cell in self.tree.active_cell_indices() {
296            let level = self.tree.active_level(cell);
297            if level >= max_level {
298                self.refine_flags[cell.0] = false;
299            }
300
301            if level <= min_level {
302                self.coarsen_flags[cell.0] = false;
303            }
304        }
305    }
306
307    /// After cells have been tagged, the refinement/coarsening flags
308    /// must be balanced to ensure that the 2:1 balance across faces and vertices
309    /// is still maintained.
310    pub fn balance_flags(&mut self) {
311        // Propogate refinement flags outwards.
312        self.tree.balance_refine_flags(&mut self.refine_flags);
313        // Refinement has priority over coarsening. Ensure that there is never a cell marked
314        // for refinement next to a equal or coarser cell marked for coarsening.
315        for cell in self.tree.active_cell_indices() {
316            if self.refine_flags[cell.0] {
317                let level = self.tree.active_level(cell);
318                for neighbor in self.tree.active_neighborhood(cell) {
319                    let nlevel = self.tree.active_level(neighbor);
320                    if nlevel <= level {
321                        self.coarsen_flags[neighbor.0] = false;
322                    }
323                }
324            }
325        }
326        // Unmark coarsening flags as necessary.
327        self.tree.balance_coarsen_flags(&mut self.coarsen_flags);
328    }
329
330    /// Returns true if the mesh requires regridding (i.e. any cells are tagged for either refinement
331    /// or coarsening).
332    pub fn requires_regridding(&self) -> bool {
333        self.refine_flags.iter().any(|&b| b) || self.coarsen_flags.iter().any(|&b| b)
334    }
335
336    /// The number of cell that are marked for refinement.
337    pub fn num_refine_cells(&self) -> usize {
338        self.refine_flags.iter().filter(|&&b| b).count()
339    }
340
341    /// The number of cells that are marked for coarsening.
342    pub fn num_coarsen_cells(&self) -> usize {
343        self.coarsen_flags.iter().filter(|&&b| b).count()
344    }
345}
346
347#[cfg(test)]
348mod tests {
349    use crate::geometry::{ActiveCellId, FaceArray, HyperBox};
350    use crate::kernel::BoundaryClass;
351    use crate::mesh::Mesh;
352
353    #[test]
354    fn element_windows() {
355        let mut mesh = Mesh::new(
356            HyperBox::UNIT,
357            4,
358            2,
359            FaceArray::from_sides([BoundaryClass::Ghost; 2], [BoundaryClass::OneSided; 2]),
360        );
361        mesh.refine_global();
362
363        mesh.set_refine_flag(0);
364        mesh.regrid();
365
366        assert!(!mesh.cell_needs_coarse_element(ActiveCellId(0)));
367        assert!(!mesh.cell_needs_coarse_element(ActiveCellId(1)));
368        assert!(!mesh.cell_needs_coarse_element(ActiveCellId(2)));
369        assert!(!mesh.cell_needs_coarse_element(ActiveCellId(3)));
370        assert!(mesh.cell_needs_coarse_element(ActiveCellId(4)));
371        assert!(mesh.cell_needs_coarse_element(ActiveCellId(5)));
372        assert!(mesh.cell_needs_coarse_element(ActiveCellId(6)));
373    }
374}