1#[cfg(feature = "mpi")]
4use crate::{ParallelGridImpl, traits::ParallelBuilder, types::GraphPartitioner};
5use crate::{
6 grid::local_grid::{SingleElementGrid, SingleElementGridBuilder},
7 traits::Builder,
8 types::Scalar,
9};
10#[cfg(feature = "mpi")]
11use mpi::traits::{Communicator, Equivalence};
12use ndelement::{ciarlet::CiarletElement, map::IdentityMap, types::ReferenceCellType};
13use std::collections::{HashMap, hash_map::Entry::Vacant};
14
15fn regular_sphere_add_points_and_cells<T: Scalar>(
17 b: &mut SingleElementGridBuilder<T>,
18 refinement_level: u32,
19) {
20 let zero = T::from(0.0).unwrap();
21 let one = T::from(1.0).unwrap();
22 let half = T::from(0.5).unwrap();
23 b.add_point(0, &[zero, zero, one]);
24 b.add_point(1, &[one, zero, zero]);
25 b.add_point(2, &[zero, one, zero]);
26 b.add_point(3, &[-one, zero, zero]);
27 b.add_point(4, &[zero, -one, zero]);
28 b.add_point(5, &[zero, zero, -one]);
29 let mut point_n = 6;
30
31 let mut cells = vec![
32 [0, 1, 2],
33 [0, 2, 3],
34 [0, 3, 4],
35 [0, 4, 1],
36 [5, 2, 1],
37 [5, 3, 2],
38 [5, 4, 3],
39 [5, 1, 4],
40 ];
41 let mut v = [[zero, zero, zero], [zero, zero, zero], [zero, zero, zero]];
42
43 for level in 0..refinement_level {
44 let mut edge_points = HashMap::new();
45 let mut new_cells = Vec::with_capacity(8 * usize::pow(6, level));
46 for c in &cells {
47 for (i, v_i) in v.iter_mut().enumerate() {
48 for (j, v_ij) in v_i.iter_mut().enumerate() {
49 *v_ij = b.points[3 * c[i] + j];
50 }
51 }
52 let edges = [[1, 2], [0, 2], [0, 1]]
53 .iter()
54 .map(|[i, j]| {
55 let mut pt_i = c[*i];
56 let mut pt_j = c[*j];
57 if pt_i > pt_j {
58 std::mem::swap(&mut pt_i, &mut pt_j);
59 }
60 if let Vacant(e) = edge_points.entry((pt_i, pt_j)) {
61 let v_i = v[*i];
62 let v_j = v[*j];
63 let mut new_pt = [
64 half * (v_i[0] + v_j[0]),
65 half * (v_i[1] + v_j[1]),
66 half * (v_i[2] + v_j[2]),
67 ];
68 let size = (new_pt.iter().map(|x| x.powi(2)).sum::<T>()).sqrt();
69 for i in new_pt.iter_mut() {
70 *i /= size;
71 }
72 b.add_point(point_n, &new_pt);
73 e.insert(point_n);
74 point_n += 1;
75 }
76 edge_points[&(pt_i, pt_j)]
77 })
78 .collect::<Vec<_>>();
79 new_cells.push([c[0], edges[2], edges[1]]);
80 new_cells.push([c[1], edges[0], edges[2]]);
81 new_cells.push([c[2], edges[1], edges[0]]);
82 new_cells.push([edges[0], edges[1], edges[2]]);
83 }
84 cells = new_cells;
85 }
86 for (i, v) in cells.iter().enumerate() {
87 b.add_cell(i, v);
88 }
89}
90
91pub fn regular_sphere<T: Scalar>(
97 refinement_level: u32,
98) -> SingleElementGrid<T, CiarletElement<T, IdentityMap, T>> {
99 let mut b = SingleElementGridBuilder::new_with_capacity(
100 3,
101 2 + usize::pow(4, refinement_level + 1),
102 8 * usize::pow(4, refinement_level),
103 (ReferenceCellType::Triangle, 1),
104 );
105 regular_sphere_add_points_and_cells(&mut b, refinement_level);
106 b.create_grid()
107}
108
109#[cfg(feature = "mpi")]
111pub fn regular_sphere_distributed<T: Scalar + Equivalence, C: Communicator>(
112 comm: &C,
113 partitioner: GraphPartitioner,
114 refinement_level: u32,
115) -> ParallelGridImpl<'_, C, SingleElementGrid<T, CiarletElement<T, IdentityMap, T>>> {
116 let mut b = SingleElementGridBuilder::new(3, (ReferenceCellType::Triangle, 1));
117 if comm.rank() == 0 {
118 regular_sphere_add_points_and_cells(&mut b, refinement_level);
119 b.create_parallel_grid_root(comm, partitioner)
120 } else {
121 b.create_parallel_grid(comm, 0)
122 }
123}
124
125#[cfg(test)]
126mod test {
127 use super::*;
128 use crate::traits::{GeometryMap, Grid};
129 use approx::assert_relative_eq;
130 use rlst::rlst_dynamic_array;
131
132 #[test]
133 fn test_regular_sphere_0() {
134 let _g = regular_sphere::<f64>(0);
135 }
136
137 #[test]
138 fn test_regular_spheres() {
139 let _g1 = regular_sphere::<f64>(1);
140 let _g2 = regular_sphere::<f64>(2);
141 let _g3 = regular_sphere::<f64>(3);
142 }
143
144 #[test]
145 fn test_normal_is_outward() {
146 for i in 0..3 {
147 let g = regular_sphere::<f64>(i);
148 let mut points = rlst_dynamic_array!(f64, [2, 1]);
149 points[[0, 0]] = 1.0 / 3.0;
150 points[[1, 0]] = 1.0 / 3.0;
151 let map = g.geometry_map(ReferenceCellType::Triangle, 1, &points);
152 let mut mapped_pt = rlst_dynamic_array!(f64, [3, 1]);
153 let mut j = rlst_dynamic_array!(f64, [3, 2, 1]);
154 let mut jinv = rlst_dynamic_array!(f64, [2, 3, 1]);
155 let mut jdet = vec![0.0];
156 let mut normal = rlst_dynamic_array!(f64, [3, 1]);
157 for i in 0..g.entity_count(ReferenceCellType::Triangle) {
158 map.physical_points(i, &mut mapped_pt);
159 map.jacobians_inverses_dets_normals(i, &mut j, &mut jinv, &mut jdet, &mut normal);
160 let dot = mapped_pt
161 .iter_value()
162 .zip(normal.iter_value())
163 .map(|(i, j)| i * j)
164 .sum::<f64>();
165 assert!(dot > 0.0);
166 }
167 }
168 }
169
170 #[test]
171 fn test_normal_is_unit() {
172 for i in 0..3 {
173 let g = regular_sphere::<f64>(i);
174 let mut points = rlst_dynamic_array!(f64, [2, 1]);
175 points[[0, 0]] = 1.0 / 3.0;
176 points[[1, 0]] = 1.0 / 3.0;
177 let map = g.geometry_map(ReferenceCellType::Triangle, 1, &points);
178 let mut mapped_pt = rlst_dynamic_array!(f64, [3, 1]);
179 let mut j = rlst_dynamic_array!(f64, [3, 2, 1]);
180 let mut jinv = rlst_dynamic_array!(f64, [2, 3, 1]);
181 let mut jdet = vec![0.0];
182 let mut normal = rlst_dynamic_array!(f64, [3, 1]);
183 for i in 0..g.entity_count(ReferenceCellType::Triangle) {
184 map.physical_points(i, &mut mapped_pt);
185 map.jacobians_inverses_dets_normals(i, &mut j, &mut jinv, &mut jdet, &mut normal);
186 let dot = normal
187 .iter_value()
188 .zip(normal.iter_value())
189 .map(|(i, j)| i * j)
190 .sum::<f64>();
191 assert_relative_eq!(dot, 1.0, epsilon = 1e-10);
192 }
193 }
194 }
195}