1use approx::assert_relative_eq;
2use itertools::izip;
3use ndelement::{
4 ciarlet::{lagrange, nedelec, raviart_thomas},
5 traits::{FiniteElement, MappedFiniteElement},
6 types::{Continuity, ReferenceCellType},
7};
8use ndmesh::{
9 mesh::local_mesh::SingleElementMeshBuilder,
10 traits::{Builder, GeometryMap, Mesh},
11};
12use rlst::{DynArray, rlst_dynamic_array};
13
14fn test_lagrange_push_forward() {
16 let mut b = SingleElementMeshBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
17 b.add_point(0, &[0.0, 0.0, 0.0]);
18 b.add_point(1, &[1.0, 0.0, 0.0]);
19 b.add_point(2, &[2.0, 0.0, 1.0]);
20 b.add_point(3, &[0.0, 1.0, 0.0]);
21 b.add_cell(0, &[0, 1, 3]);
22 b.add_cell(1, &[1, 2, 3]);
23 let mesh = b.create_mesh();
24
25 let e = lagrange::create::<f64, f64>(
26 ReferenceCellType::Triangle,
27 4,
28 Continuity::Standard,
29 lagrange::Variant::Equispaced,
30 );
31
32 let npts = 5;
33
34 let mut cell0_points = rlst_dynamic_array!(f64, [2, npts]);
35 for i in 0..npts {
36 cell0_points[[1, i]] = i as f64 / (npts - 1) as f64;
37 cell0_points[[0, i]] = 1.0 - cell0_points[[1, i]];
38 }
39 let mut cell0_table = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, npts));
40 e.tabulate(&cell0_points, 0, &mut cell0_table);
41
42 let mut points = rlst_dynamic_array!(f64, [2, npts]);
43 for i in 0..npts {
44 points[[0, i]] = 0.0;
45 points[[1, i]] = i as f64 / (npts - 1) as f64;
46 }
47
48 let mut table = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, npts));
49 e.tabulate(&points, 0, &mut table);
50
51 let gmap = mesh.geometry_map(ReferenceCellType::Triangle, 1, &points);
52
53 let mut jacobians = rlst_dynamic_array!(f64, [mesh.geometry_dim(), mesh.topology_dim(), npts]);
54 let mut jinv = rlst_dynamic_array!(f64, [mesh.topology_dim(), mesh.geometry_dim(), npts]);
55 let mut jdets = vec![0.0; npts];
56
57 gmap.jacobians_inverses_dets(1, &mut jacobians, &mut jinv, &mut jdets);
58
59 let mut cell1_table = DynArray::<f64, 4>::from_shape(table.shape());
60 e.push_forward(&table, 0, &jacobians, &jdets, &jinv, &mut cell1_table);
61
62 for (cell0_dof, cell1_dof) in izip!(
64 e.entity_closure_dofs(1, 1).unwrap(),
65 e.entity_closure_dofs(1, 0).unwrap()
66 ) {
67 for i in 0..npts {
68 assert_relative_eq!(
69 cell0_table[[0, i, *cell0_dof, 0]],
70 cell1_table[[0, i, *cell1_dof, 0]],
71 epsilon = 1e-10
72 );
73 }
74 }
75}
76
77fn test_rt_push_forward() {
79 let mut b = SingleElementMeshBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
80 b.add_point(0, &[0.0, 0.0, 0.0]);
81 b.add_point(1, &[1.0, 0.0, 0.0]);
82 b.add_point(2, &[2.0, 0.0, 1.0]);
83 b.add_point(3, &[0.0, 1.0, 0.0]);
84 b.add_cell(0, &[0, 1, 3]);
85 b.add_cell(1, &[1, 2, 3]);
86 let mesh = b.create_mesh();
87
88 let e =
89 raviart_thomas::create::<f64, f64>(ReferenceCellType::Triangle, 4, Continuity::Standard);
90
91 let npts = 5;
92
93 let mut cell0_points = rlst_dynamic_array!(f64, [2, npts]);
94 for i in 0..npts {
95 cell0_points[[1, i]] = i as f64 / (npts - 1) as f64;
96 cell0_points[[0, i]] = 1.0 - cell0_points[[1, i]];
97 }
98 let mut cell0_table = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, npts));
99 e.tabulate(&cell0_points, 0, &mut cell0_table);
100
101 let mut points = rlst_dynamic_array!(f64, [2, npts]);
102 for i in 0..npts {
103 points[[0, i]] = 0.0;
104 points[[1, i]] = i as f64 / (npts - 1) as f64;
105 }
106
107 let mut table = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, npts));
108 e.tabulate(&points, 0, &mut table);
109
110 let gmap = mesh.geometry_map(ReferenceCellType::Triangle, 1, &points);
111
112 let mut jacobians = rlst_dynamic_array!(f64, [mesh.geometry_dim(), mesh.topology_dim(), npts]);
113 let mut jinv = rlst_dynamic_array!(f64, [mesh.topology_dim(), mesh.geometry_dim(), npts]);
114 let mut jdets = vec![0.0; npts];
115
116 gmap.jacobians_inverses_dets(1, &mut jacobians, &mut jinv, &mut jdets);
117
118 let mut cell1_table =
119 DynArray::<f64, 4>::from_shape([table.shape()[0], table.shape()[1], table.shape()[2], 3]);
120 e.push_forward(&table, 0, &jacobians, &jdets, &jinv, &mut cell1_table);
121
122 for (cell0_dof, cell1_dof) in izip!(
124 e.entity_closure_dofs(1, 0).unwrap(),
125 e.entity_closure_dofs(1, 1).unwrap()
126 ) {
127 for i in 0..npts {
128 assert_relative_eq!(
129 (cell0_table[[0, i, *cell0_dof, 0]] + cell0_table[[0, i, *cell0_dof, 1]])
130 / f64::sqrt(2.0),
131 (cell1_table[[0, i, *cell1_dof, 0]]
132 + cell1_table[[0, i, *cell1_dof, 1]]
133 + 2.0 * cell1_table[[0, i, *cell1_dof, 2]])
134 / f64::sqrt(6.0),
135 epsilon = 1e-10
136 );
137 }
138 }
139}
140
141fn test_nc_push_forward() {
143 let mut b = SingleElementMeshBuilder::<f64>::new(3, (ReferenceCellType::Triangle, 1));
144 b.add_point(0, &[0.0, 0.0, 0.0]);
145 b.add_point(1, &[1.0, 0.0, 0.0]);
146 b.add_point(2, &[2.0, 0.0, 1.0]);
147 b.add_point(3, &[0.0, 1.0, 0.0]);
148 b.add_cell(0, &[0, 1, 3]);
149 b.add_cell(1, &[1, 2, 3]);
150 let mesh = b.create_mesh();
151
152 let e = nedelec::create::<f64, f64>(ReferenceCellType::Triangle, 4, Continuity::Standard);
153
154 let npts = 5;
155
156 let mut cell0_points = rlst_dynamic_array!(f64, [2, npts]);
157 for i in 0..npts {
158 cell0_points[[1, i]] = i as f64 / (npts - 1) as f64;
159 cell0_points[[0, i]] = 1.0 - cell0_points[[1, i]];
160 }
161 let mut cell0_table = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, npts));
162 e.tabulate(&cell0_points, 0, &mut cell0_table);
163
164 let mut points = rlst_dynamic_array!(f64, [2, npts]);
165 for i in 0..npts {
166 points[[0, i]] = 0.0;
167 points[[1, i]] = i as f64 / (npts - 1) as f64;
168 }
169
170 let mut table = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, npts));
171 e.tabulate(&points, 0, &mut table);
172
173 let gmap = mesh.geometry_map(ReferenceCellType::Triangle, 1, &points);
174
175 let mut jacobians = rlst_dynamic_array!(f64, [mesh.geometry_dim(), mesh.topology_dim(), npts]);
176 let mut jinv = rlst_dynamic_array!(f64, [mesh.topology_dim(), mesh.geometry_dim(), npts]);
177 let mut jdets = vec![0.0; npts];
178
179 gmap.jacobians_inverses_dets(1, &mut jacobians, &mut jinv, &mut jdets);
180
181 let mut cell1_table =
182 DynArray::<f64, 4>::from_shape([table.shape()[0], table.shape()[1], table.shape()[2], 3]);
183 e.push_forward(&table, 0, &jacobians, &jdets, &jinv, &mut cell1_table);
184
185 for (cell0_dof, cell1_dof) in izip!(
187 e.entity_closure_dofs(1, 0).unwrap(),
188 e.entity_closure_dofs(1, 1).unwrap()
189 ) {
190 for i in 0..npts {
191 assert_relative_eq!(
192 (cell0_table[[0, i, *cell0_dof, 0]] - cell0_table[[0, i, *cell0_dof, 1]])
193 / f64::sqrt(2.0),
194 (cell1_table[[0, i, *cell1_dof, 0]] - cell1_table[[0, i, *cell1_dof, 1]])
195 / f64::sqrt(2.0),
196 epsilon = 1e-10
197 );
198 }
199 }
200}
201
202fn main() {
204 println!("Testing Lagrange push forward (identity)");
205 test_lagrange_push_forward();
206
207 println!("Testing Raviart-Thomas push forward (contravariant Piola)");
208 test_rt_push_forward();
209
210 println!("Testing Nedelec push forward (covariant Piola)");
211 test_nc_push_forward();
212}