1use crate::geometry::{
9 ActiveCellId, BlockId, Face, FaceArray, FaceMask, HyperBox, Split, Tree, TreeBlocks,
10 TreeInterfaces, TreeNeighbors, TreeSer,
11};
12use crate::kernel::{BoundaryClass, DirichletParams, Element, node_from_vertex};
13use crate::kernel::{BoundaryKind, NodeSpace, NodeWindow, SystemBoundaryConds};
14use crate::prelude::IndexSpace;
15use datasize::DataSize;
16
17#[cfg(feature = "parallel")]
18use rayon::iter::{IntoParallelIterator, ParallelBridge, ParallelIterator};
19
20use std::collections::HashMap;
21use std::{array, fmt::Write, ops::Range};
22
23mod checkpoint;
24mod evaluate;
25mod function;
26mod regrid;
27mod store;
28mod transfer;
29
30pub use checkpoint::{Checkpoint, ExportStride, ExportVtuConfig};
31pub use function::{Engine, Function, FunctionBorrowMut, Gaussian, Projection, TanH};
32pub use store::{MeshStore, UnsafeThreadCache};
33
34use crate::image::ImageRef;
35
36#[derive(Debug, serde::Serialize, serde::Deserialize)]
44#[serde(from = "MeshSer<N>", into = "MeshSer<N>")]
45pub struct Mesh<const N: usize> {
46 tree: Tree<N>,
48 width: usize,
50 ghost: usize,
52 boundary: FaceArray<N, BoundaryClass>,
55
56 blocks: TreeBlocks<N>,
58 neighbors: TreeNeighbors<N>,
60 interfaces: TreeInterfaces<N>,
62
63 refine_flags: Vec<bool>,
65 coarsen_flags: Vec<bool>,
67
68 regrid_map: Vec<ActiveCellId>,
70
71 old_blocks: TreeBlocks<N>,
73 old_cell_splits: Vec<Split<N>>,
77
78 stores: UnsafeThreadCache<MeshStore>,
82 elements: HashMap<(usize, usize), Element<N>>,
84}
85
86impl<const N: usize> Mesh<N> {
87 pub fn new(
90 bounds: HyperBox<N>,
91 width: usize,
92 ghost: usize,
93 boundary: FaceArray<N, BoundaryClass>,
94 ) -> Self {
95 assert!(width % 2 == 0);
96 assert!(ghost >= width / 2);
97
98 let mut tree = Tree::new(bounds);
99
100 for axis in 0..N {
101 let negative_periodic =
102 matches!(boundary[Face::negative(axis)], BoundaryClass::Periodic);
103 let positive_periodic =
104 matches!(boundary[Face::positive(axis)], BoundaryClass::Periodic);
105
106 assert_eq!(
107 negative_periodic, positive_periodic,
108 "Periodicity on a given axis must match"
109 );
110
111 tree.set_periodic(axis, negative_periodic && positive_periodic);
112 }
113
114 let mut result = Self {
115 tree,
116 width,
117 ghost,
118 boundary,
119
120 blocks: TreeBlocks::new([width; N], ghost),
121 neighbors: TreeNeighbors::default(),
122 interfaces: TreeInterfaces::default(),
123
124 refine_flags: Vec::new(),
125 coarsen_flags: Vec::new(),
126
127 regrid_map: Vec::default(),
128 old_blocks: TreeBlocks::new([width; N], ghost),
129 old_cell_splits: Vec::default(),
130
131 stores: UnsafeThreadCache::new(),
132 elements: HashMap::default(),
133 };
134
135 result.build();
136
137 result
138 }
139
140 pub fn width(&self) -> usize {
142 self.width
143 }
144
145 pub fn ghost(&self) -> usize {
147 self.ghost
148 }
149
150 fn build(&mut self) {
152 debug_assert_eq!(self.blocks.width(), [self.width; N]);
153 debug_assert_eq!(self.blocks.ghost(), self.ghost());
154 debug_assert_eq!(self.old_blocks.width(), [self.width; N]);
155 debug_assert_eq!(self.old_blocks.ghost(), self.ghost());
156
157 self.tree.build();
159 self.blocks.build(&self.tree);
161
162 self.neighbors.build(&self.tree, &self.blocks);
164 self.interfaces
166 .build(&self.tree, &self.blocks, &self.neighbors);
167 self.build_flags();
169 }
170
171 fn build_flags(&mut self) {
173 self.refine_flags.clear();
174 self.coarsen_flags.clear();
175
176 self.refine_flags
177 .resize(self.tree.num_active_cells(), false);
178 self.coarsen_flags
179 .resize(self.tree.num_active_cells(), false);
180 }
181
182 pub fn tree(&self) -> &Tree<N> {
187 &self.tree
188 }
189
190 pub fn num_blocks(&self) -> usize {
192 self.blocks.len()
193 }
194
195 pub(crate) fn num_old_blocks(&self) -> usize {
197 self.old_blocks.len()
198 }
199
200 pub fn num_active_cells(&self) -> usize {
202 self.tree.num_active_cells()
203 }
204
205 pub fn num_nodes(&self) -> usize {
207 self.blocks.num_nodes()
208 }
209
210 pub fn num_dofs(&self) -> usize {
211 let mut result = 0;
212
213 for block in 0..self.num_blocks() {
214 let mut size = self.blocks.size(BlockId(block));
215
216 for axis in 0..N {
217 size[axis] *= self.width;
218
219 if self
220 .blocks
221 .boundary_flags(BlockId(block))
222 .is_set(Face::positive(axis))
223 {
224 size[axis] += 1;
225 }
226 }
227
228 result += size.iter().product::<usize>();
229 }
230
231 result
232 }
233
234 pub(crate) fn num_old_nodes(&self) -> usize {
236 self.old_blocks.num_nodes()
237 }
238
239 pub fn boundary_classes(&self) -> FaceArray<N, BoundaryClass> {
241 self.boundary.clone()
242 }
243
244 pub fn blocks(&self) -> &TreeBlocks<N> {
249 &self.blocks
250 }
251
252 pub fn block_nodes(&self, block: BlockId) -> Range<usize> {
254 self.blocks.nodes(block)
255 }
256
257 pub(crate) fn old_block_nodes(&self, block: BlockId) -> Range<usize> {
259 self.old_blocks.nodes(block)
260 }
261
262 pub fn block_space(&self, block: BlockId) -> NodeSpace<N> {
264 let size = self.blocks.size(block);
265 let cell_size = array::from_fn(|axis| size[axis] * self.width);
266
267 NodeSpace {
268 size: cell_size,
269 ghost: self.ghost,
270 boundary: self.block_boundary_classes(block),
271 bounds: self.block_bounds(block),
272 }
273 }
274
275 pub(crate) fn old_block_space(&self, block: BlockId) -> NodeSpace<N> {
277 let size = self.old_blocks.size(block);
278 let cell_size = array::from_fn(|axis| size[axis] * self.width);
279
280 NodeSpace {
281 size: cell_size,
282 ghost: self.ghost,
283 bounds: HyperBox::UNIT,
284 boundary: self.old_block_boundary_classes(block),
285 }
286 }
287
288 pub fn block_bounds(&self, block: BlockId) -> HyperBox<N> {
290 self.blocks.bounds(block)
291 }
292
293 pub fn block_physical_boundary_flags(&self, block: BlockId) -> FaceMask<N> {
296 self.blocks.boundary_flags(block)
297 }
298
299 pub fn block_boundary_classes(&self, block: BlockId) -> FaceArray<N, BoundaryClass> {
301 let flag = self.block_physical_boundary_flags(block);
302
303 FaceArray::from_fn(|face| {
304 if flag.is_set(face) {
305 self.boundary[face]
306 } else {
307 BoundaryClass::Ghost
308 }
309 })
310 }
311
312 pub fn block_bcs<B: SystemBoundaryConds<N>>(
315 &self,
316 block: BlockId,
317 bcs: B,
318 ) -> BlockBoundaryConds<N, B> {
319 BlockBoundaryConds {
320 inner: bcs,
321 physical_boundary_flags: self.block_physical_boundary_flags(block),
322 }
323 }
324
325 pub(crate) fn old_block_boundary_classes(&self, block: BlockId) -> FaceArray<N, BoundaryClass> {
327 let flag = self.old_blocks.boundary_flags(block);
328
329 FaceArray::from_fn(|face| {
330 if flag.is_set(face) {
331 self.boundary[face]
332 } else {
333 BoundaryClass::Ghost
334 }
335 })
336 }
337
338 pub fn block_level(&self, block: BlockId) -> usize {
340 self.blocks.level(block)
341 }
342
343 pub(crate) fn old_block_level(&self, block: BlockId) -> usize {
345 self.old_blocks.level(block)
346 }
347
348 pub fn window_bounds(&self, block: BlockId, window: NodeWindow<N>) -> HyperBox<N> {
353 debug_assert!(self.block_space(block).contains_window(window));
354 let block_size = self.blocks.node_size(block);
355 let bounds = self.blocks.bounds(block);
356
357 HyperBox {
358 size: array::from_fn(|axis| {
359 bounds.size[axis] * window.size[axis] as f64 / block_size[axis] as f64
360 }),
361 origin: array::from_fn(|axis| {
362 bounds.size[axis] * window.origin[axis] as f64 / block_size[axis] as f64
363 }),
364 }
365 }
366
367 pub fn active_window(&self, cell: ActiveCellId) -> NodeWindow<N> {
369 NodeWindow {
370 origin: node_from_vertex(self.active_node_origin(cell)),
371 size: [self.width + 1; N],
372 }
373 }
374
375 pub fn interpolate_window(&self, cell: ActiveCellId, position: [f64; N]) -> NodeWindow<N> {
378 let cell_offset = self.blocks.active_cell_position(cell);
379 let cell_bounds = self.tree().active_bounds(cell);
380 let cell_origin: [_; N] = array::from_fn(|axis| (self.width * cell_offset[axis]) as isize);
381
382 debug_assert!(cell_bounds.contains(position));
383
384 let local = cell_bounds.global_to_local(position);
385 let local_node: [_; N] =
386 array::from_fn(|axis| (local[axis] * self.width as f64).round() as isize);
387 let local_origin: [_; N] =
388 array::from_fn(|axis| local_node[axis] - self.width as isize / 2);
389
390 NodeWindow {
391 origin: array::from_fn(|axis| cell_origin[axis] + local_origin[axis]),
392 size: [self.width + 1; N],
393 }
394 }
395
396 pub fn element_window(&self, cell: ActiveCellId) -> NodeWindow<N> {
398 let position = self.blocks.active_cell_position(cell);
399 let buffer = 2 * (self.ghost / 2);
402 debug_assert!(buffer <= self.ghost);
403
404 let size = [self.width + 2 * buffer + 1; N];
405 let mut origin = [-(buffer as isize); N];
406
407 for axis in 0..N {
408 origin[axis] += (self.width * position[axis]) as isize
409 }
410
411 NodeWindow { origin, size }
412 }
413
414 pub fn element_coarse_window(&self, cell: ActiveCellId) -> NodeWindow<N> {
417 let position = self.blocks.active_cell_position(cell);
418
419 let size = [self.width + 1; N];
420 let mut origin = [0; N];
421
422 for axis in 0..N {
423 origin[axis] += (self.width * position[axis]) as isize
424 }
425
426 NodeWindow { origin, size }
427 }
428
429 pub fn request_element(&mut self, width: usize, order: usize) -> Element<N> {
431 self.elements
432 .remove(&(width, order))
433 .unwrap_or_else(|| Element::uniform(width, order))
434 }
435
436 pub fn replace_element(&mut self, element: Element<N>) {
438 _ = self
439 .elements
440 .insert((element.width(), element.order()), element)
441 }
442
443 pub fn cell_node_size(&self, cell: ActiveCellId) -> [usize; N] {
447 let block = self.blocks.active_cell_block(cell);
448 let size = self.blocks.size(block);
449 let position = self.blocks.active_cell_position(cell);
450
451 array::from_fn(|axis| {
452 if position[axis] == size[axis] - 1 {
453 self.width + 1
454 } else {
455 self.width
456 }
457 })
458 }
459
460 pub fn active_node_origin(&self, cell: ActiveCellId) -> [usize; N] {
462 let position = self.blocks.active_cell_position(cell);
463 array::from_fn(|axis| position[axis] * self.width)
464 }
465
466 pub fn cell_needs_coarse_element(&self, cell: ActiveCellId) -> bool {
470 let block = self.blocks.active_cell_block(cell);
471 let block_size = self.blocks.size(block);
472 let boundary = self.block_boundary_classes(block);
473 let position = self.blocks.active_cell_position(cell);
474
475 for face in Face::iterate() {
476 let border = if face.side {
477 block_size[face.axis] - 1
478 } else {
479 0
480 };
481 let on_border = position[face.axis] == border;
482
483 if !boundary[face].has_ghost() && on_border {
484 return true;
485 }
486 }
487
488 false
489 }
490
491 pub fn num_levels(&self) -> usize {
496 self.tree().num_levels()
497 }
498
499 pub fn min_spacing(&self) -> f64 {
503 let max_level = self.num_levels() - 1;
504 let domain = self.tree.domain();
505
506 array::from_fn::<_, N, _>(|axis| {
507 domain.size[axis] / self.width as f64 / 2_f64.powi(max_level as i32)
508 })
509 .iter()
510 .min_by(|a, b| f64::total_cmp(a, b))
511 .cloned()
512 .unwrap_or(1.0)
513 }
514
515 pub fn block_spacing(&self, block: BlockId) -> f64 {
517 let space = self.block_space(block);
518
519 space
520 .spacing()
521 .iter()
522 .min_by(|a, b| f64::total_cmp(a, b))
523 .cloned()
524 .unwrap_or(1.0)
525 }
526
527 pub fn block_compute<F: Fn(&Self, &MeshStore, BlockId) + Sync>(&mut self, f: F) {
530 #[cfg(feature = "parallel")]
531 self.blocks
532 .indices()
533 .par_bridge()
534 .into_par_iter()
535 .for_each(|block| {
536 let store = unsafe { self.stores.get_or_default() };
537 f(self, store, block);
538 store.reset();
539 });
540
541 #[cfg(not(feature = "parallel"))]
542 self.blocks.indices().for_each(|block| {
543 let store = unsafe { self.stores.get_or_default() };
544 f(self, store, block);
545 store.reset();
546 });
547 }
548
549 pub fn try_block_compute<E: Send, F: Fn(&Self, &MeshStore, BlockId) -> Result<(), E> + Sync>(
551 &mut self,
552 f: F,
553 ) -> Result<(), E> {
554 #[cfg(feature = "parallel")]
555 return self
556 .blocks
557 .indices()
558 .par_bridge()
559 .into_par_iter()
560 .try_for_each(|block| {
561 let store = unsafe { self.stores.get_or_default() };
562 let result = f(self, store, block);
563 store.reset();
564 result
565 });
566
567 #[cfg(not(feature = "parallel"))]
568 return self.blocks.indices().try_for_each(|block| {
569 let store = unsafe { self.stores.get_or_default() };
570 let result = f(self, store, block);
571 store.reset();
572 result
573 });
574 }
575
576 pub(crate) fn old_block_compute<F: Fn(&Self, &MeshStore, BlockId) + Sync>(&mut self, f: F) {
579 #[cfg(feature = "parallel")]
580 (0..self.num_old_blocks())
581 .map(BlockId)
582 .par_bridge()
583 .into_par_iter()
584 .for_each(|block| {
585 let store = unsafe { self.stores.get_or_default() };
586 f(self, store, block);
587 store.reset();
588 });
589
590 #[cfg(not(feature = "parallel"))]
591 (0..self.num_old_blocks()).map(BlockId).for_each(|block| {
592 let store = unsafe { self.stores.get_or_default() };
593 f(self, store, block);
594 store.reset();
595 });
596 }
597
598 pub fn l2_norm_system(&mut self, source: ImageRef) -> f64 {
600 source
601 .channels()
602 .map(|label| self.l2_norm(source.channel(label)))
603 .max_by(f64::total_cmp)
604 .unwrap()
605 }
606
607 pub fn max_norm_system(&mut self, source: ImageRef) -> f64 {
609 source
610 .channels()
611 .map(|label| self.max_norm(source.channel(label)))
612 .max_by(f64::total_cmp)
613 .unwrap()
614 }
615
616 pub fn bottom_left_value(&self, src: &[f64]) -> f64 {
619 let space = self.block_space(BlockId(0));
620 let nodes = self.block_nodes(BlockId(0));
621
622 src[nodes][space.index_from_vertex([0; N])]
623 }
624
625 pub fn l2_norm(&mut self, src: &[f64]) -> f64 {
627 let mut result = 0.0;
628
629 for block in self.blocks.indices() {
630 let space = self.block_space(block);
631 let size = space.cell_size();
632
633 let data = &src[self.block_nodes(block)];
634
635 let mut block_result = 0.0;
636
637 for node in space.inner_window() {
638 let index = space.index_from_node(node);
639 let mut value = data[index] * data[index];
640
641 for axis in 0..N {
642 if node[axis] == 0 || node[axis] == size[axis] as isize {
643 value *= 0.5;
644 }
645 }
646
647 block_result += value;
648 }
649
650 for spacing in space.spacing() {
651 block_result *= spacing;
652 }
653
654 result += block_result;
655 }
656
657 result.sqrt()
658 }
659
660 pub fn oscillation_heuristic(&mut self, src: &[f64]) -> f64 {
661 let mut result: f64 = 0.0;
662
663 for block in self.blocks.indices() {
664 let space = self.block_space(block);
665 let cell_size = self.blocks.size(block);
666
667 let data = &src[self.block_nodes(block)];
668
669 for cell in IndexSpace::new(cell_size).iter() {
670 let node_offset: [usize; N] = array::from_fn(|i| self.width * cell[i]);
671 let node_size = [self.width + 1; N];
672
673 let mut maximum = f64::NEG_INFINITY;
674 let mut minimum = f64::INFINITY;
675
676 for local in IndexSpace::new(node_size).iter() {
677 let global: [_; N] = array::from_fn(|axis| node_offset[axis] + local[axis]);
678 let index = space.index_from_vertex(global);
679
680 minimum = minimum.min(data[index]);
681 maximum = maximum.max(data[index]);
682 }
683
684 let cell_result = (maximum - minimum).abs();
685
686 result += cell_result;
687 }
688 }
689
690 result
691 }
692
693 pub fn oscillation_heuristic_system(&mut self, source: ImageRef) -> f64 {
694 source
695 .channels()
696 .map(|cidx| self.oscillation_heuristic(source.channel(cidx)))
697 .max_by(f64::total_cmp)
698 .unwrap()
699 }
700
701 pub fn max_norm(&mut self, src: &[f64]) -> f64 {
703 let mut result = 0.0f64;
704
705 for block in self.blocks.indices() {
706 let space = self.block_space(block);
707 let data = &src[self.block_nodes(block)];
708
709 let mut block_result = 0.0f64;
710
711 for node in space.inner_window() {
712 let index = space.index_from_node(node);
713 block_result = block_result.max(data[index]);
714 }
715
716 result = result.max(block_result);
717 }
718
719 result
720 }
721
722 pub fn write_debug(&self, mut result: impl Write) {
726 writeln!(result, "// **********************").unwrap();
727 writeln!(result, "// Cells ****************").unwrap();
728 writeln!(result, "// **********************").unwrap();
729 writeln!(result).unwrap();
730
731 for cell in self.tree.active_cell_indices() {
732 writeln!(result, "Cell {}", cell.0).unwrap();
733 writeln!(result, " Bounds {:?}", self.tree.active_bounds(cell)).unwrap();
734 writeln!(
735 result,
736 " Block {:?}",
737 self.blocks.active_cell_block(cell)
738 )
739 .unwrap();
740 writeln!(
741 result,
742 " Block Position {:?}",
743 self.blocks.active_cell_position(cell)
744 )
745 .unwrap();
746 }
747
748 writeln!(result).unwrap();
749 writeln!(result, "// **********************").unwrap();
750 writeln!(result, "// Blocks ***************").unwrap();
751 writeln!(result, "// **********************").unwrap();
752 writeln!(result).unwrap();
753
754 for block in self.blocks.indices() {
755 writeln!(result, "Block {block:?}").unwrap();
756 writeln!(result, " Bounds {:?}", self.blocks.bounds(block)).unwrap();
757 writeln!(result, " Size {:?}", self.blocks.size(block)).unwrap();
758 writeln!(result, " Cells {:?}", self.blocks.active_cells(block)).unwrap();
759 writeln!(
760 result,
761 " Vertices {:?}",
762 self.block_space(block).cell_size()
763 )
764 .unwrap();
765 writeln!(
766 result,
767 " Boundary {:?}",
768 self.blocks.boundary_flags(block)
769 )
770 .unwrap();
771 }
772
773 writeln!(result).unwrap();
774 writeln!(result, "// **********************").unwrap();
775 writeln!(result, "// Neighbors ************").unwrap();
776 writeln!(result, "// **********************").unwrap();
777 writeln!(result).unwrap();
778
779 writeln!(result, "// Fine Neighbors").unwrap();
780
781 for neighbor in self.neighbors.fine() {
782 writeln!(result, "Fine Neighbor").unwrap();
783
784 writeln!(
785 result,
786 " Block: {:?}, Neighbor: {:?}",
787 neighbor.block, neighbor.neighbor,
788 )
789 .unwrap();
790 writeln!(
791 result,
792 " Lower: Cell {}, Neighbor {}, Region {}",
793 neighbor.a.cell.0, neighbor.a.neighbor.0, neighbor.a.region,
794 )
795 .unwrap();
796 writeln!(
797 result,
798 " Upper: Cell {}, Neighbor {}, Region {}",
799 neighbor.b.cell.0, neighbor.b.neighbor.0, neighbor.b.region,
800 )
801 .unwrap();
802 }
803
804 writeln!(result).unwrap();
805 writeln!(result, "// Direct Neighbors").unwrap();
806
807 for neighbor in self.neighbors.direct() {
808 writeln!(result, "Direct Neighbor").unwrap();
809
810 writeln!(
811 result,
812 " Block: {:?}, Neighbor: {:?}",
813 neighbor.block, neighbor.neighbor,
814 )
815 .unwrap();
816 writeln!(
817 result,
818 " Lower: Cell {}, Neighbor {}, Region {}",
819 neighbor.a.cell.0, neighbor.a.neighbor.0, neighbor.a.region,
820 )
821 .unwrap();
822 writeln!(
823 result,
824 " Upper: Cell {}, Neighbor {}, Region {}",
825 neighbor.b.cell.0, neighbor.b.neighbor.0, neighbor.b.region,
826 )
827 .unwrap();
828 }
829
830 writeln!(result).unwrap();
831 writeln!(result, "// Coarse Neighbors").unwrap();
832
833 for neighbor in self.neighbors.coarse() {
834 writeln!(result, "Coarse Neighbor").unwrap();
835
836 writeln!(
837 result,
838 " Block: {:?}, Neighbor: {:?}",
839 neighbor.block, neighbor.neighbor,
840 )
841 .unwrap();
842 writeln!(
843 result,
844 " Lower: Cell {}, Neighbor {}, Region {}",
845 neighbor.a.cell.0, neighbor.a.neighbor.0, neighbor.a.region,
846 )
847 .unwrap();
848 writeln!(
849 result,
850 " Upper: Cell {}, Neighbor {}, Region {}",
851 neighbor.b.cell.0, neighbor.b.neighbor.0, neighbor.b.region,
852 )
853 .unwrap();
854 }
855
856 writeln!(result).unwrap();
857 writeln!(result, "// **********************").unwrap();
858 writeln!(result, "// Interfaces ***********").unwrap();
859 writeln!(result, "// **********************").unwrap();
860 writeln!(result).unwrap();
861 }
862}
863
864impl<const N: usize> Clone for Mesh<N> {
865 fn clone(&self) -> Self {
866 Self {
867 tree: self.tree.clone(),
868 width: self.width,
869 ghost: self.ghost,
870 boundary: self.boundary,
871
872 blocks: self.blocks.clone(),
873 neighbors: self.neighbors.clone(),
874 interfaces: self.interfaces.clone(),
875
876 refine_flags: self.refine_flags.clone(),
877 coarsen_flags: self.coarsen_flags.clone(),
878
879 regrid_map: self.regrid_map.clone(),
880 old_blocks: self.old_blocks.clone(),
881 old_cell_splits: self.old_cell_splits.clone(),
882
883 stores: UnsafeThreadCache::default(),
884 elements: HashMap::default(),
885 }
886 }
887}
888
889impl<const N: usize> Default for Mesh<N> {
890 fn default() -> Self {
891 let mut result = Self {
892 tree: Tree::new(HyperBox::UNIT),
893 width: 4,
894 ghost: 1,
895 boundary: FaceArray::default(),
896
897 blocks: TreeBlocks::new([4; N], 1),
898 neighbors: TreeNeighbors::default(),
899 interfaces: TreeInterfaces::default(),
900
901 refine_flags: Vec::default(),
902 coarsen_flags: Vec::default(),
903
904 regrid_map: Vec::default(),
905 old_blocks: TreeBlocks::new([4; N], 1),
906 old_cell_splits: Vec::default(),
907
908 stores: UnsafeThreadCache::default(),
909 elements: HashMap::default(),
910 };
911
912 result.build();
913
914 result
915 }
916}
917
918impl<const N: usize> DataSize for Mesh<N> {
919 const IS_DYNAMIC: bool = false;
920 const STATIC_HEAP_SIZE: usize = 0;
921
922 fn estimate_heap_size(&self) -> usize {
923 self.tree.estimate_heap_size()
924 + self.blocks.estimate_heap_size()
925 + self.neighbors.estimate_heap_size()
926 + self.interfaces.estimate_heap_size()
927 + self.refine_flags.estimate_heap_size()
928 + self.coarsen_flags.estimate_heap_size()
929 + self.regrid_map.estimate_heap_size()
930 + self.old_blocks.estimate_heap_size()
931 + self.old_cell_splits.estimate_heap_size()
932 }
933}
934
935#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
937struct MeshSer<const N: usize> {
938 tree: TreeSer<N>,
939 width: usize,
940 ghost: usize,
941 boundary: FaceArray<N, BoundaryClass>,
942}
943
944impl<const N: usize> From<Mesh<N>> for MeshSer<N> {
945 fn from(value: Mesh<N>) -> Self {
946 MeshSer {
947 tree: value.tree.into(),
948 width: value.width,
949 ghost: value.ghost,
950 boundary: value.boundary,
951 }
952 }
953}
954
955impl<const N: usize> From<MeshSer<N>> for Mesh<N> {
956 fn from(value: MeshSer<N>) -> Self {
957 let mut result = Mesh {
958 tree: value.tree.into(),
959 width: value.width,
960 ghost: value.ghost,
961 boundary: value.boundary,
962 blocks: TreeBlocks::new([value.width; N], value.ghost),
963 old_blocks: TreeBlocks::new([value.width; N], value.ghost),
964
965 ..Default::default()
966 };
967 result.build();
968 result
969 }
970}
971
972#[derive(Clone, Debug)]
973pub struct BlockBoundaryConds<const N: usize, I> {
974 inner: I,
975 physical_boundary_flags: FaceMask<N>,
977}
978
979impl<const N: usize, I: SystemBoundaryConds<N>> SystemBoundaryConds<N>
980 for BlockBoundaryConds<N, I>
981{
982 fn kind(&self, channel: usize, face: Face<N>) -> BoundaryKind {
983 if self.physical_boundary_flags.is_set(face) {
984 self.inner.kind(channel, face)
985 } else {
986 BoundaryKind::Custom
987 }
988 }
989
990 fn dirichlet(&self, channel: usize, position: [f64; N]) -> DirichletParams {
991 self.inner.dirichlet(channel, position)
992 }
993
994 fn radiative(&self, channel: usize, position: [f64; N]) -> crate::prelude::RadiativeParams {
995 self.inner.radiative(channel, position)
996 }
997}
998
999#[cfg(test)]
1000mod tests {
1001 use super::*;
1002 use rand::Rng;
1003 #[test]
1004 fn fuzzy_serialize() -> eyre::Result<()> {
1005 let mut mesh = Mesh::<2>::new(
1006 HyperBox::UNIT,
1007 6,
1008 3,
1009 [
1010 [BoundaryClass::Ghost, BoundaryClass::OneSided],
1011 [BoundaryClass::Ghost, BoundaryClass::OneSided],
1012 ]
1013 .into(),
1014 );
1015 mesh.refine_global();
1016
1017 let mut rng = rand::rng();
1019 for _ in 0..4 {
1020 rng.fill(mesh.refine_flags.as_mut_slice());
1022 mesh.balance_flags();
1024 mesh.regrid();
1026 }
1027
1028 let data = ron::to_string(&mesh)?;
1030 let mesh2: Mesh<2> = ron::from_str(data.as_str())?;
1031
1032 assert_eq!(mesh.tree, mesh2.tree);
1033 assert_eq!(mesh.width, mesh2.width);
1034 assert_eq!(mesh.ghost, mesh2.ghost);
1035 assert_eq!(mesh.boundary, mesh2.boundary);
1036 assert_eq!(mesh.blocks, mesh2.blocks);
1037 assert_eq!(mesh.neighbors, mesh2.neighbors);
1038 assert_eq!(mesh.interfaces, mesh2.interfaces);
1039
1040 Ok(())
1041 }
1042}