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