use std::array;
use crate::geometry::{ActiveCellId, IndexSpace};
use crate::image::ImageRef;
use crate::{mesh::Mesh, shared::SharedSlice};
impl<const N: usize> Mesh<N> {
pub fn refine_flags(&self) -> &[bool] {
self.refine_flags.as_slice()
}
pub fn coarsen_flags(&self) -> &[bool] {
self.coarsen_flags.as_slice()
}
pub fn regrid(&mut self) {
self.regrid_map.clear();
self.old_blocks.clone_from(&self.blocks);
self.old_cell_splits.clear();
self.old_cell_splits.extend(
self.tree
.active_cell_indices()
.flat_map(|cell| self.tree.most_recent_active_split(cell)),
);
self.regrid_map
.resize(self.tree.num_active_cells(), ActiveCellId(0));
let mut coarsen_map = vec![ActiveCellId(0); self.tree.num_active_cells()];
self.tree
.coarsen_active_index_map(&self.coarsen_flags, &mut coarsen_map);
debug_assert!(self.tree.check_coarsen_flags(&self.coarsen_flags));
self.tree.coarsen(&self.coarsen_flags);
let mut refine_map = vec![ActiveCellId(0); self.tree.num_active_cells()];
let mut flags = vec![false; self.tree.num_active_cells()];
for (old, &new) in coarsen_map.iter().enumerate() {
flags[new.0] = self.refine_flags[old];
}
self.tree.refine_active_index_map(&flags, &mut refine_map);
debug_assert!(self.tree.check_refine_flags(&flags));
self.tree.refine(&flags);
for i in 0..self.regrid_map.len() {
self.regrid_map[i] = refine_map[coarsen_map[i].0];
}
self.build();
}
pub fn refine_global(&mut self) {
self.refine_flags.fill(true);
self.regrid();
}
pub fn refine_innermost(&mut self) {
let mut temp_rflags = vec![false; self.tree().num_active_cells()];
let mut cell_inner_index = 0;
let mut cell_inner_center = f64::MAX;
for cell in self.tree().active_cell_indices() {
let cell_bounds = self.tree().active_bounds(cell);
let cell_center = cell_bounds.center()[0]; if cell_center < cell_inner_center {
cell_inner_center = cell_center;
cell_inner_index = cell.0;
}
}
temp_rflags[cell_inner_index] = true;
self.refine_flags = temp_rflags;
self.balance_flags();
self.regrid();
}
pub fn coarsen_innermost(&mut self) {
let mut temp_cflags = vec![false; self.tree().num_active_cells()];
let mut cell_inner_index = 0;
let mut cell_inner_center = f64::MAX;
for cell in self.tree().active_cell_indices() {
let cell_bounds = self.tree().active_bounds(cell);
let cell_center = cell_bounds.center()[0]; if cell_center < cell_inner_center {
cell_inner_center = cell_center;
cell_inner_index = cell.0;
}
}
temp_cflags[cell_inner_index] = true;
self.coarsen_flags = temp_cflags;
self.balance_flags();
self.regrid();
}
pub fn regrid_in_radius(&mut self, radius: f64, fgl: usize) {
self.refine_flags.fill(false);
self.coarsen_flags.fill(false);
let mut temp_rflags = vec![false; self.tree().num_active_cells()];
let mut temp_cflags = vec![false; self.tree().num_active_cells()];
for cell in self.tree().active_cell_indices() {
let cell_bounds = self.tree().active_bounds(cell);
let cell_center = cell_bounds.center()[0]; let cell_level = self.tree().active_level(cell);
let cell_index = cell.0;
if cell_center < radius {
if cell_level < fgl {
temp_rflags[cell_index] = true;
}
if cell_level > fgl {
temp_cflags[cell_index] = true;
}
}
}
self.refine_flags = temp_rflags;
self.coarsen_flags = temp_cflags;
self.balance_flags();
self.regrid();
}
pub fn flag_wavelets(&mut self, order: usize, lower: f64, upper: f64, data: ImageRef) {
let buffer = 2 * (self.ghost / 2);
let support = (self.width + 2 * buffer) / 2;
assert!(order % 2 == 0);
assert!(order <= support);
assert_eq!(data.num_nodes(), self.num_nodes());
let element = self.request_element(support, order);
let element_coarse = self.request_element(self.width / 2, order / 2);
let support = element.support_refined();
let mut rflags_buf = std::mem::take(&mut self.refine_flags);
let mut cflags_buf = std::mem::take(&mut self.coarsen_flags);
let rflags = SharedSlice::new(&mut rflags_buf);
let cflags = SharedSlice::new(&mut cflags_buf);
self.block_compute(|mesh, store, block| {
let imsrc = store.scratch(support);
let imdest = store.scratch(support);
let nodes = mesh.block_nodes(block);
let space = mesh.block_space(block);
let block_system = data.slice(nodes.clone());
for &cell in mesh.blocks.active_cells(block) {
let is_cell_on_boundary = mesh.cell_needs_coarse_element(cell);
let window = if is_cell_on_boundary {
mesh.element_coarse_window(cell)
} else {
mesh.element_window(cell)
};
let mut should_refine = false;
let mut should_coarsen = true;
for field in data.channels() {
for (i, node) in window.iter().enumerate() {
imsrc[i] = block_system.channel(field)[space.index_from_node(node)];
}
if is_cell_on_boundary {
let src = &imsrc[..element_coarse.support_refined()];
let dst = &mut imdest[..element_coarse.support_refined()];
element_coarse.wavelet(src, dst);
for point in element_coarse.diagonal_points() {
should_refine = should_refine || dst[point].abs() >= upper;
should_coarsen = should_coarsen && dst[point].abs() <= lower;
}
} else {
element.wavelet(imsrc, imdest);
for point in element.diagonal_int_points(buffer) {
should_refine = should_refine || imdest[point].abs() >= upper;
should_coarsen = should_coarsen && imdest[point].abs() <= lower;
}
}
unsafe {
if should_refine {
*rflags.get_mut(cell.0) = true;
}
}
unsafe {
*cflags.get_mut(cell.0) = should_coarsen;
}
}
}
});
let _ = std::mem::replace(&mut self.refine_flags, rflags_buf);
let _ = std::mem::replace(&mut self.coarsen_flags, cflags_buf);
self.replace_element(element);
self.replace_element(element_coarse);
}
pub fn flags_debug(&mut self, debug: &mut [i64]) {
assert!(debug.len() == self.num_nodes());
let debug = SharedSlice::new(debug);
self.block_compute(|mesh, _, block| {
let block_nodes = mesh.block_nodes(block);
let block_space = mesh.block_space(block);
let block_size = mesh.blocks.size(block);
let cells = mesh.blocks.active_cells(block);
for (i, position) in IndexSpace::new(block_size).iter().enumerate() {
let cell = cells[i];
let origin: [_; N] = array::from_fn(|axis| (position[axis] * mesh.width) as isize);
for offset in IndexSpace::new([mesh.width + 1; N]).iter() {
let node = array::from_fn(|axis| origin[axis] + offset[axis] as isize);
let idx = block_nodes.start + block_space.index_from_node(node);
unsafe {
*debug.get_mut(idx) = mesh.refine_flags[cell.0] as i64;
}
}
}
});
}
pub fn set_refine_flag(&mut self, cell: usize) {
self.refine_flags[cell] = true
}
pub fn set_coarsen_flag(&mut self, cell: usize) {
self.coarsen_flags[cell] = true
}
pub fn buffer_refine_flags(&mut self, count: usize) {
for _ in 0..count {
for cell in self.tree.active_cell_indices() {
if !self.refine_flags[cell.0] {
continue;
}
for neighbor in self.tree.active_neighborhood(cell) {
self.refine_flags[neighbor.0] = true;
}
}
}
}
pub fn limit_level_range_flags(&mut self, min_level: usize, max_level: usize) {
assert!(self.refine_flags.len() == self.num_active_cells());
assert!(self.coarsen_flags.len() == self.num_active_cells());
for cell in self.tree.active_cell_indices() {
let level = self.tree.active_level(cell);
if level >= max_level {
self.refine_flags[cell.0] = false;
}
if level <= min_level {
self.coarsen_flags[cell.0] = false;
}
}
}
pub fn balance_flags(&mut self) {
self.tree.balance_refine_flags(&mut self.refine_flags);
for cell in self.tree.active_cell_indices() {
if self.refine_flags[cell.0] {
let level = self.tree.active_level(cell);
for neighbor in self.tree.active_neighborhood(cell) {
let nlevel = self.tree.active_level(neighbor);
if nlevel <= level {
self.coarsen_flags[neighbor.0] = false;
}
}
}
}
self.tree.balance_coarsen_flags(&mut self.coarsen_flags);
}
pub fn requires_regridding(&self) -> bool {
self.refine_flags.iter().any(|&b| b) || self.coarsen_flags.iter().any(|&b| b)
}
pub fn num_refine_cells(&self) -> usize {
self.refine_flags.iter().filter(|&&b| b).count()
}
pub fn num_coarsen_cells(&self) -> usize {
self.coarsen_flags.iter().filter(|&&b| b).count()
}
}
#[cfg(test)]
mod tests {
use crate::geometry::{ActiveCellId, FaceArray, HyperBox};
use crate::kernel::BoundaryClass;
use crate::mesh::Mesh;
#[test]
fn element_windows() {
let mut mesh = Mesh::new(
HyperBox::UNIT,
4,
2,
FaceArray::from_sides([BoundaryClass::Ghost; 2], [BoundaryClass::OneSided; 2]),
);
mesh.refine_global();
mesh.set_refine_flag(0);
mesh.regrid();
assert!(!mesh.cell_needs_coarse_element(ActiveCellId(0)));
assert!(!mesh.cell_needs_coarse_element(ActiveCellId(1)));
assert!(!mesh.cell_needs_coarse_element(ActiveCellId(2)));
assert!(!mesh.cell_needs_coarse_element(ActiveCellId(3)));
assert!(mesh.cell_needs_coarse_element(ActiveCellId(4)));
assert!(mesh.cell_needs_coarse_element(ActiveCellId(5)));
assert!(mesh.cell_needs_coarse_element(ActiveCellId(6)));
}
}