1use super::CiarletElement;
4use crate::map::IdentityMap;
5use crate::polynomials::polynomial_count;
6use crate::reference_cell;
7use crate::traits::ElementFamily;
8use crate::types::{Continuity, ReferenceCellType};
9use quadraturerules::{Domain, QuadratureRule, single_integral_quadrature};
10use rlst::dense::linalg::lapack::interface::{getrf::Getrf, getri::Getri};
11use rlst::{RlstScalar, rlst_dynamic_array};
12use std::marker::PhantomData;
13
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
17#[repr(u8)]
18pub enum LagrangeVariant {
19 Equispaced,
21 GLL,
23}
24
25pub fn create<T: RlstScalar + Getrf + Getri, TGeo: RlstScalar>(
27 cell_type: ReferenceCellType,
28 degree: usize,
29 continuity: Continuity,
30 variant: LagrangeVariant,
31) -> CiarletElement<T, IdentityMap, TGeo> {
32 let dim = polynomial_count(cell_type, degree);
33 let tdim = reference_cell::dim(cell_type);
34 let mut wcoeffs = rlst_dynamic_array!(T, [dim, 1, dim]);
35 for i in 0..dim {
36 *wcoeffs.get_mut([i, 0, i]).unwrap() = T::from(1.0).unwrap();
37 }
38
39 let mut x = [vec![], vec![], vec![], vec![]];
40 let mut m = [vec![], vec![], vec![], vec![]];
41 let entity_counts = reference_cell::entity_counts(cell_type);
42 let vertices = reference_cell::vertices::<TGeo>(cell_type);
43 if degree == 0 {
44 if continuity == Continuity::Standard {
45 panic!("Cannot create continuous degree 0 Lagrange element");
46 }
47 for (d, counts) in entity_counts.iter().enumerate() {
48 for _e in 0..*counts {
49 x[d].push(rlst_dynamic_array!(TGeo, [tdim, 0]));
50 m[d].push(rlst_dynamic_array!(T, [0, 1, 0]));
51 }
52 }
53 let mut midp = rlst_dynamic_array!(TGeo, [tdim, 1]);
54 let nvertices = entity_counts[0];
55 for i in 0..tdim {
56 for vertex in &vertices {
57 *midp.get_mut([i, 0]).unwrap() += num::cast::<_, TGeo>(vertex[i]).unwrap();
58 }
59 *midp.get_mut([i, 0]).unwrap() /= num::cast::<_, TGeo>(nvertices).unwrap();
60 }
61 x[tdim].push(midp);
62 let mut mentry = rlst_dynamic_array!(T, [1, 1, 1]);
63 *mentry.get_mut([0, 0, 0]).unwrap() = T::from(1.0).unwrap();
64 m[tdim].push(mentry);
65 } else {
66 let edges = reference_cell::edges(cell_type);
67 let faces = reference_cell::faces(cell_type);
68 let volumes = reference_cell::volumes(cell_type);
69 for vertex in &vertices {
70 let mut pts = rlst_dynamic_array!(TGeo, [tdim, 1]);
71 for (i, v) in vertex.iter().enumerate() {
72 *pts.get_mut([i, 0]).unwrap() = num::cast::<_, TGeo>(*v).unwrap();
73 }
74 x[0].push(pts);
75 let mut mentry = rlst_dynamic_array!(T, [1, 1, 1]);
76 *mentry.get_mut([0, 0, 0]).unwrap() = T::from(1.0).unwrap();
77 m[0].push(mentry);
78 }
79
80 let pts1d = match variant {
81 LagrangeVariant::Equispaced => (1..degree)
82 .map(|i| num::cast::<_, TGeo>(i).unwrap() / num::cast::<_, TGeo>(degree).unwrap())
83 .collect::<Vec<_>>(),
84 LagrangeVariant::GLL => {
85 let (points, _weights) = single_integral_quadrature(
86 QuadratureRule::GaussLobattoLegendre,
87 Domain::Interval,
88 degree - 1,
89 )
90 .unwrap();
91 (1..degree)
92 .map(|i| num::cast::<_, TGeo>(points[2 * i + 1]).unwrap())
93 .collect::<Vec<_>>()
94 }
95 };
96
97 for e in &edges {
98 let mut pts = rlst_dynamic_array!(TGeo, [tdim, degree - 1]);
99 let [vn0, vn1] = e[..] else {
100 panic!();
101 };
102 let v0 = &vertices[vn0];
103 let v1 = &vertices[vn1];
104 let mut ident = rlst_dynamic_array!(T, [degree - 1, 1, degree - 1]);
105
106 for (i, p) in pts1d.iter().enumerate() {
107 *ident.get_mut([i, 0, i]).unwrap() = T::from(1.0).unwrap();
108 for j in 0..tdim {
109 *pts.get_mut([j, i]).unwrap() = num::cast::<_, TGeo>(v0[j]).unwrap()
110 + *p * num::cast::<_, TGeo>(v1[j] - v0[j]).unwrap();
111 }
112 }
113 x[1].push(pts);
114 m[1].push(ident);
115 }
116 for (e, face_type) in reference_cell::entity_types(cell_type)[2]
117 .iter()
118 .enumerate()
119 {
120 let npts = match face_type {
121 ReferenceCellType::Triangle => {
122 if degree > 2 {
123 (degree - 1) * (degree - 2) / 2
124 } else {
125 0
126 }
127 }
128 ReferenceCellType::Quadrilateral => (degree - 1).pow(2),
129 _ => {
130 panic!("Unsupported face type");
131 }
132 };
133 let mut pts = rlst_dynamic_array!(TGeo, [tdim, npts]);
134
135 let [vn0, vn1, vn2] = faces[e][..3] else {
136 panic!();
137 };
138 let v0 = &vertices[vn0];
139 let v1 = &vertices[vn1];
140 let v2 = &vertices[vn2];
141
142 match face_type {
143 ReferenceCellType::Triangle => {
144 if variant != LagrangeVariant::Equispaced {
145 unimplemented!();
146 }
147 let mut n = 0;
148 for i1 in 1..degree {
149 for i0 in 1..degree - i1 {
150 for j in 0..tdim {
151 *pts.get_mut([j, n]).unwrap() = num::cast::<_, TGeo>(v0[j])
152 .unwrap()
153 + num::cast::<_, TGeo>(i0).unwrap()
154 / num::cast::<_, TGeo>(degree).unwrap()
155 * num::cast::<_, TGeo>(v1[j] - v0[j]).unwrap()
156 + num::cast::<_, TGeo>(i1).unwrap()
157 / num::cast::<_, TGeo>(degree).unwrap()
158 * num::cast::<_, TGeo>(v2[j] - v0[j]).unwrap();
159 }
160 n += 1;
161 }
162 }
163 }
164 ReferenceCellType::Quadrilateral => {
165 let mut n = 0;
166 for p1 in &pts1d {
167 for p0 in &pts1d {
168 for j in 0..tdim {
169 *pts.get_mut([j, n]).unwrap() = num::cast::<_, TGeo>(v0[j])
170 .unwrap()
171 + *p0 * num::cast::<_, TGeo>(v1[j] - v0[j]).unwrap()
172 + *p1 * num::cast::<_, TGeo>(v2[j] - v0[j]).unwrap();
173 }
174 n += 1;
175 }
176 }
177 }
178 _ => {
179 panic!("Unsupported face type.");
180 }
181 };
182
183 let mut ident = rlst_dynamic_array!(T, [npts, 1, npts]);
184 for i in 0..npts {
185 *ident.get_mut([i, 0, i]).unwrap() = T::from(1.0).unwrap();
186 }
187 x[2].push(pts);
188 m[2].push(ident);
189 }
190 for (e, volume_type) in reference_cell::entity_types(cell_type)[3]
191 .iter()
192 .enumerate()
193 {
194 let npts = match volume_type {
195 ReferenceCellType::Tetrahedron => {
196 if degree > 2 {
197 (degree - 1) * (degree - 2) * (degree - 3) / 6
198 } else {
199 0
200 }
201 }
202 ReferenceCellType::Hexahedron => (degree - 1).pow(3),
203 _ => {
204 panic!("Unsupported face type");
205 }
206 };
207 let mut pts = rlst_dynamic_array!(TGeo, [tdim, npts]);
208
209 match volume_type {
210 ReferenceCellType::Tetrahedron => {
211 if variant != LagrangeVariant::Equispaced {
212 unimplemented!();
213 }
214 let [vn0, vn1, vn2, vn3] = volumes[e][..4] else {
215 panic!();
216 };
217 let v0 = &vertices[vn0];
218 let v1 = &vertices[vn1];
219 let v2 = &vertices[vn2];
220 let v3 = &vertices[vn3];
221
222 let mut n = 0;
223 for i2 in 1..degree {
224 for i1 in 1..degree - i2 {
225 for i0 in 1..degree - i2 - i1 {
226 for j in 0..tdim {
227 *pts.get_mut([j, n]).unwrap() = num::cast::<_, TGeo>(v0[j])
228 .unwrap()
229 + num::cast::<_, TGeo>(i0).unwrap()
230 / num::cast::<_, TGeo>(degree).unwrap()
231 * num::cast::<_, TGeo>(v1[j] - v0[j]).unwrap()
232 + num::cast::<_, TGeo>(i1).unwrap()
233 / num::cast::<_, TGeo>(degree).unwrap()
234 * num::cast::<_, TGeo>(v2[j] - v0[j]).unwrap()
235 + num::cast::<_, TGeo>(i2).unwrap()
236 / num::cast::<_, TGeo>(degree).unwrap()
237 * num::cast::<_, TGeo>(v3[j] - v0[j]).unwrap();
238 }
239 n += 1;
240 }
241 }
242 }
243 }
244 ReferenceCellType::Hexahedron => {
245 let [vn0, vn1, vn2, _, vn3] = volumes[e][..5] else {
246 panic!();
247 };
248 let v0 = &vertices[vn0];
249 let v1 = &vertices[vn1];
250 let v2 = &vertices[vn2];
251 let v3 = &vertices[vn3];
252
253 let mut n = 0;
254 for p2 in &pts1d {
255 for p1 in &pts1d {
256 for p0 in &pts1d {
257 for j in 0..tdim {
258 *pts.get_mut([j, n]).unwrap() = num::cast::<_, TGeo>(v0[j])
259 .unwrap()
260 + *p0 * num::cast::<_, TGeo>(v1[j] - v0[j]).unwrap()
261 + *p1 * num::cast::<_, TGeo>(v2[j] - v0[j]).unwrap()
262 + *p2 * num::cast::<_, TGeo>(v3[j] - v0[j]).unwrap();
263 }
264 n += 1;
265 }
266 }
267 }
268 }
269 _ => {
270 panic!("Unsupported face type.");
271 }
272 };
273
274 let mut ident = rlst_dynamic_array!(T, [npts, 1, npts]);
275 for i in 0..npts {
276 *ident.get_mut([i, 0, i]).unwrap() = T::from(1.0).unwrap();
277 }
278 x[3].push(pts);
279 m[3].push(ident);
280 }
281 }
282 CiarletElement::<T, IdentityMap, TGeo>::create(
283 "Lagrange".to_string(),
284 cell_type,
285 degree,
286 vec![],
287 wcoeffs,
288 x,
289 m,
290 continuity,
291 degree,
292 IdentityMap {},
293 )
294}
295
296pub struct LagrangeElementFamily<T: RlstScalar + Getrf + Getri = f64, TGeo: RlstScalar = f64> {
301 degree: usize,
302 continuity: Continuity,
303 variant: LagrangeVariant,
304 _t: PhantomData<T>,
305 _tgeo: PhantomData<TGeo>,
306}
307
308impl<T: RlstScalar + Getrf + Getri, TGeo: RlstScalar> LagrangeElementFamily<T, TGeo> {
309 pub fn new(degree: usize, continuity: Continuity, variant: LagrangeVariant) -> Self {
311 Self {
312 degree,
313 continuity,
314 variant,
315 _t: PhantomData,
316 _tgeo: PhantomData,
317 }
318 }
319}
320
321impl<T: RlstScalar + Getrf + Getri, TGeo: RlstScalar> ElementFamily
322 for LagrangeElementFamily<T, TGeo>
323{
324 type T = T;
325 type FiniteElement = CiarletElement<T, IdentityMap, TGeo>;
326 type CellType = ReferenceCellType;
327 fn element(&self, cell_type: ReferenceCellType) -> CiarletElement<T, IdentityMap, TGeo> {
328 create::<T, TGeo>(cell_type, self.degree, self.continuity, self.variant)
329 }
330}
331
332#[cfg(test)]
333mod test {
334 use super::super::test::check_dofs;
335 use super::*;
336 use crate::traits::FiniteElement;
337 use approx::*;
338 use paste::paste;
339 use rlst::DynArray;
340
341 #[test]
342 fn test_lagrange_1() {
343 let e = create::<f64, f64>(
344 ReferenceCellType::Triangle,
345 1,
346 Continuity::Standard,
347 LagrangeVariant::Equispaced,
348 );
349 assert_eq!(e.value_size(), 1);
350 }
351
352 #[test]
353 fn test_lagrange_0_interval() {
354 let e = create::<f64, f64>(
355 ReferenceCellType::Interval,
356 0,
357 Continuity::Discontinuous,
358 LagrangeVariant::Equispaced,
359 );
360 assert_eq!(e.value_size(), 1);
361 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
362 let mut points = rlst_dynamic_array!(f64, [1, 4]);
363 *points.get_mut([0, 0]).unwrap() = 0.0;
364 *points.get_mut([0, 1]).unwrap() = 0.2;
365 *points.get_mut([0, 2]).unwrap() = 0.4;
366 *points.get_mut([0, 3]).unwrap() = 1.0;
367 e.tabulate(&points, 0, &mut data);
368
369 for pt in 0..4 {
370 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
371 }
372 check_dofs(e);
373 }
374
375 #[test]
376 fn test_lagrange_1_interval() {
377 let e = create::<f64, f64>(
378 ReferenceCellType::Interval,
379 1,
380 Continuity::Standard,
381 LagrangeVariant::Equispaced,
382 );
383 assert_eq!(e.value_size(), 1);
384 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
385 let mut points = rlst_dynamic_array!(f64, [1, 4]);
386 *points.get_mut([0, 0]).unwrap() = 0.0;
387 *points.get_mut([0, 1]).unwrap() = 0.2;
388 *points.get_mut([0, 2]).unwrap() = 0.4;
389 *points.get_mut([0, 3]).unwrap() = 1.0;
390 e.tabulate(&points, 0, &mut data);
391
392 for pt in 0..4 {
393 let x = *points.get([0, pt]).unwrap();
394 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0 - x);
395 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x);
396 }
397 check_dofs(e);
398 }
399
400 #[test]
401 fn test_lagrange_0_triangle() {
402 let e = create::<f64, f64>(
403 ReferenceCellType::Triangle,
404 0,
405 Continuity::Discontinuous,
406 LagrangeVariant::Equispaced,
407 );
408 assert_eq!(e.value_size(), 1);
409 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
410
411 let mut points = rlst_dynamic_array!(f64, [2, 6]);
412 *points.get_mut([0, 0]).unwrap() = 0.0;
413 *points.get_mut([1, 0]).unwrap() = 0.0;
414 *points.get_mut([0, 1]).unwrap() = 1.0;
415 *points.get_mut([1, 1]).unwrap() = 0.0;
416 *points.get_mut([0, 2]).unwrap() = 0.0;
417 *points.get_mut([1, 2]).unwrap() = 1.0;
418 *points.get_mut([0, 3]).unwrap() = 0.5;
419 *points.get_mut([1, 3]).unwrap() = 0.0;
420 *points.get_mut([0, 4]).unwrap() = 0.0;
421 *points.get_mut([1, 4]).unwrap() = 0.5;
422 *points.get_mut([0, 5]).unwrap() = 0.5;
423 *points.get_mut([1, 5]).unwrap() = 0.5;
424
425 e.tabulate(&points, 0, &mut data);
426
427 for pt in 0..6 {
428 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
429 }
430 check_dofs(e);
431 }
432
433 #[test]
434 fn test_lagrange_1_triangle() {
435 let e = create::<f64, f64>(
436 ReferenceCellType::Triangle,
437 1,
438 Continuity::Standard,
439 LagrangeVariant::Equispaced,
440 );
441 assert_eq!(e.value_size(), 1);
442 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
443 let mut points = rlst_dynamic_array!(f64, [2, 6]);
444 *points.get_mut([0, 0]).unwrap() = 0.0;
445 *points.get_mut([1, 0]).unwrap() = 0.0;
446 *points.get_mut([0, 1]).unwrap() = 1.0;
447 *points.get_mut([1, 1]).unwrap() = 0.0;
448 *points.get_mut([0, 2]).unwrap() = 0.0;
449 *points.get_mut([1, 2]).unwrap() = 1.0;
450 *points.get_mut([0, 3]).unwrap() = 0.5;
451 *points.get_mut([1, 3]).unwrap() = 0.0;
452 *points.get_mut([0, 4]).unwrap() = 0.0;
453 *points.get_mut([1, 4]).unwrap() = 0.5;
454 *points.get_mut([0, 5]).unwrap() = 0.5;
455 *points.get_mut([1, 5]).unwrap() = 0.5;
456 e.tabulate(&points, 0, &mut data);
457
458 for pt in 0..6 {
459 let x = *points.get([0, pt]).unwrap();
460 let y = *points.get([1, pt]).unwrap();
461 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0 - x - y);
462 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x);
463 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), y);
464 }
465 check_dofs(e);
466 }
467
468 #[test]
469 fn test_lagrange_0_quadrilateral() {
470 let e = create::<f64, f64>(
471 ReferenceCellType::Quadrilateral,
472 0,
473 Continuity::Discontinuous,
474 LagrangeVariant::Equispaced,
475 );
476 assert_eq!(e.value_size(), 1);
477 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
478 let mut points = rlst_dynamic_array!(f64, [2, 6]);
479 *points.get_mut([0, 0]).unwrap() = 0.0;
480 *points.get_mut([1, 0]).unwrap() = 0.0;
481 *points.get_mut([0, 1]).unwrap() = 1.0;
482 *points.get_mut([1, 1]).unwrap() = 0.0;
483 *points.get_mut([0, 2]).unwrap() = 0.0;
484 *points.get_mut([1, 2]).unwrap() = 1.0;
485 *points.get_mut([0, 3]).unwrap() = 0.5;
486 *points.get_mut([1, 3]).unwrap() = 0.0;
487 *points.get_mut([0, 4]).unwrap() = 0.0;
488 *points.get_mut([1, 4]).unwrap() = 0.5;
489 *points.get_mut([0, 5]).unwrap() = 0.5;
490 *points.get_mut([1, 5]).unwrap() = 0.5;
491 e.tabulate(&points, 0, &mut data);
492
493 for pt in 0..6 {
494 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
495 }
496 check_dofs(e);
497 }
498
499 #[test]
500 fn test_lagrange_1_quadrilateral() {
501 let e = create::<f64, f64>(
502 ReferenceCellType::Quadrilateral,
503 1,
504 Continuity::Standard,
505 LagrangeVariant::Equispaced,
506 );
507 assert_eq!(e.value_size(), 1);
508 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
509 let mut points = rlst_dynamic_array!(f64, [2, 6]);
510 *points.get_mut([0, 0]).unwrap() = 0.0;
511 *points.get_mut([1, 0]).unwrap() = 0.0;
512 *points.get_mut([0, 1]).unwrap() = 1.0;
513 *points.get_mut([1, 1]).unwrap() = 0.0;
514 *points.get_mut([0, 2]).unwrap() = 0.0;
515 *points.get_mut([1, 2]).unwrap() = 1.0;
516 *points.get_mut([0, 3]).unwrap() = 1.0;
517 *points.get_mut([1, 3]).unwrap() = 1.0;
518 *points.get_mut([0, 4]).unwrap() = 0.25;
519 *points.get_mut([1, 4]).unwrap() = 0.5;
520 *points.get_mut([0, 5]).unwrap() = 0.3;
521 *points.get_mut([1, 5]).unwrap() = 0.2;
522
523 e.tabulate(&points, 0, &mut data);
524
525 for pt in 0..6 {
526 let x = *points.get([0, pt]).unwrap();
527 let y = *points.get([1, pt]).unwrap();
528 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), (1.0 - x) * (1.0 - y));
529 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x * (1.0 - y));
530 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), (1.0 - x) * y);
531 assert_relative_eq!(*data.get([0, pt, 3, 0]).unwrap(), x * y);
532 }
533 check_dofs(e);
534 }
535
536 #[test]
537 fn test_lagrange_2_quadrilateral() {
538 let e = create::<f64, f64>(
539 ReferenceCellType::Quadrilateral,
540 2,
541 Continuity::Standard,
542 LagrangeVariant::Equispaced,
543 );
544 assert_eq!(e.value_size(), 1);
545 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
546 let mut points = rlst_dynamic_array!(f64, [2, 6]);
547 *points.get_mut([0, 0]).unwrap() = 0.0;
548 *points.get_mut([1, 0]).unwrap() = 0.0;
549 *points.get_mut([0, 1]).unwrap() = 1.0;
550 *points.get_mut([1, 1]).unwrap() = 0.0;
551 *points.get_mut([0, 2]).unwrap() = 0.0;
552 *points.get_mut([1, 2]).unwrap() = 1.0;
553 *points.get_mut([0, 3]).unwrap() = 1.0;
554 *points.get_mut([1, 3]).unwrap() = 1.0;
555 *points.get_mut([0, 4]).unwrap() = 0.25;
556 *points.get_mut([1, 4]).unwrap() = 0.5;
557 *points.get_mut([0, 5]).unwrap() = 0.3;
558 *points.get_mut([1, 5]).unwrap() = 0.2;
559
560 e.tabulate(&points, 0, &mut data);
561
562 for pt in 0..6 {
563 let x = *points.get([0, pt]).unwrap();
564 let y = *points.get([1, pt]).unwrap();
565 assert_relative_eq!(
566 *data.get([0, pt, 0, 0]).unwrap(),
567 (1.0 - x) * (1.0 - 2.0 * x) * (1.0 - y) * (1.0 - 2.0 * y),
568 epsilon = 1e-14
569 );
570 assert_relative_eq!(
571 *data.get([0, pt, 1, 0]).unwrap(),
572 x * (2.0 * x - 1.0) * (1.0 - y) * (1.0 - 2.0 * y),
573 epsilon = 1e-14
574 );
575 assert_relative_eq!(
576 *data.get([0, pt, 2, 0]).unwrap(),
577 (1.0 - x) * (1.0 - 2.0 * x) * y * (2.0 * y - 1.0),
578 epsilon = 1e-14
579 );
580 assert_relative_eq!(
581 *data.get([0, pt, 3, 0]).unwrap(),
582 x * (2.0 * x - 1.0) * y * (2.0 * y - 1.0),
583 epsilon = 1e-14
584 );
585 assert_relative_eq!(
586 *data.get([0, pt, 4, 0]).unwrap(),
587 4.0 * x * (1.0 - x) * (1.0 - y) * (1.0 - 2.0 * y),
588 epsilon = 1e-14
589 );
590 assert_relative_eq!(
591 *data.get([0, pt, 5, 0]).unwrap(),
592 (1.0 - x) * (1.0 - 2.0 * x) * 4.0 * y * (1.0 - y),
593 epsilon = 1e-14
594 );
595 assert_relative_eq!(
596 *data.get([0, pt, 6, 0]).unwrap(),
597 x * (2.0 * x - 1.0) * 4.0 * y * (1.0 - y),
598 epsilon = 1e-14
599 );
600 assert_relative_eq!(
601 *data.get([0, pt, 7, 0]).unwrap(),
602 4.0 * x * (1.0 - x) * y * (2.0 * y - 1.0),
603 epsilon = 1e-14
604 );
605 assert_relative_eq!(
606 *data.get([0, pt, 8, 0]).unwrap(),
607 4.0 * x * (1.0 - x) * 4.0 * y * (1.0 - y),
608 epsilon = 1e-14
609 );
610 }
611 check_dofs(e);
612 }
613
614 #[test]
615 fn test_lagrange_0_tetrahedron() {
616 let e = create::<f64, f64>(
617 ReferenceCellType::Tetrahedron,
618 0,
619 Continuity::Discontinuous,
620 LagrangeVariant::Equispaced,
621 );
622 assert_eq!(e.value_size(), 1);
623 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
624 let mut points = rlst_dynamic_array!(f64, [3, 6]);
625 *points.get_mut([0, 0]).unwrap() = 0.0;
626 *points.get_mut([1, 0]).unwrap() = 0.0;
627 *points.get_mut([2, 0]).unwrap() = 0.0;
628 *points.get_mut([0, 1]).unwrap() = 1.0;
629 *points.get_mut([1, 1]).unwrap() = 0.0;
630 *points.get_mut([2, 1]).unwrap() = 0.0;
631 *points.get_mut([0, 2]).unwrap() = 0.0;
632 *points.get_mut([1, 2]).unwrap() = 1.0;
633 *points.get_mut([2, 2]).unwrap() = 0.0;
634 *points.get_mut([0, 3]).unwrap() = 0.5;
635 *points.get_mut([1, 3]).unwrap() = 0.0;
636 *points.get_mut([2, 3]).unwrap() = 0.5;
637 *points.get_mut([0, 4]).unwrap() = 0.0;
638 *points.get_mut([1, 4]).unwrap() = 0.5;
639 *points.get_mut([2, 4]).unwrap() = 0.5;
640 *points.get_mut([0, 5]).unwrap() = 0.5;
641 *points.get_mut([1, 5]).unwrap() = 0.2;
642 *points.get_mut([2, 5]).unwrap() = 0.3;
643 e.tabulate(&points, 0, &mut data);
644
645 for pt in 0..6 {
646 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
647 }
648 check_dofs(e);
649 }
650
651 #[test]
652 fn test_lagrange_1_tetrahedron() {
653 let e = create::<f64, f64>(
654 ReferenceCellType::Tetrahedron,
655 1,
656 Continuity::Standard,
657 LagrangeVariant::Equispaced,
658 );
659 assert_eq!(e.value_size(), 1);
660 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
661 let mut points = rlst_dynamic_array!(f64, [3, 6]);
662 *points.get_mut([0, 0]).unwrap() = 0.0;
663 *points.get_mut([1, 0]).unwrap() = 0.0;
664 *points.get_mut([2, 0]).unwrap() = 0.0;
665 *points.get_mut([0, 1]).unwrap() = 1.0;
666 *points.get_mut([1, 1]).unwrap() = 0.0;
667 *points.get_mut([2, 1]).unwrap() = 0.0;
668 *points.get_mut([0, 2]).unwrap() = 0.0;
669 *points.get_mut([1, 2]).unwrap() = 0.8;
670 *points.get_mut([2, 2]).unwrap() = 0.2;
671 *points.get_mut([0, 3]).unwrap() = 0.0;
672 *points.get_mut([1, 3]).unwrap() = 0.0;
673 *points.get_mut([2, 3]).unwrap() = 0.8;
674 *points.get_mut([0, 4]).unwrap() = 0.25;
675 *points.get_mut([1, 4]).unwrap() = 0.5;
676 *points.get_mut([2, 4]).unwrap() = 0.1;
677 *points.get_mut([0, 5]).unwrap() = 0.2;
678 *points.get_mut([1, 5]).unwrap() = 0.1;
679 *points.get_mut([2, 5]).unwrap() = 0.15;
680
681 e.tabulate(&points, 0, &mut data);
682
683 for pt in 0..6 {
684 let x = *points.get([0, pt]).unwrap();
685 let y = *points.get([1, pt]).unwrap();
686 let z = *points.get([2, pt]).unwrap();
687 assert_relative_eq!(
688 *data.get([0, pt, 0, 0]).unwrap(),
689 1.0 - x - y - z,
690 epsilon = 1e-14
691 );
692 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x, epsilon = 1e-14);
693 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), y, epsilon = 1e-14);
694 assert_relative_eq!(*data.get([0, pt, 3, 0]).unwrap(), z, epsilon = 1e-14);
695 }
696 check_dofs(e);
697 }
698
699 #[test]
700 fn test_lagrange_0_hexahedron() {
701 let e = create::<f64, f64>(
702 ReferenceCellType::Hexahedron,
703 0,
704 Continuity::Discontinuous,
705 LagrangeVariant::Equispaced,
706 );
707 assert_eq!(e.value_size(), 1);
708 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
709 let mut points = rlst_dynamic_array!(f64, [3, 6]);
710 *points.get_mut([0, 0]).unwrap() = 0.0;
711 *points.get_mut([1, 0]).unwrap() = 0.0;
712 *points.get_mut([2, 0]).unwrap() = 0.0;
713 *points.get_mut([0, 1]).unwrap() = 1.0;
714 *points.get_mut([1, 1]).unwrap() = 0.0;
715 *points.get_mut([2, 1]).unwrap() = 0.0;
716 *points.get_mut([0, 2]).unwrap() = 0.0;
717 *points.get_mut([1, 2]).unwrap() = 1.0;
718 *points.get_mut([2, 2]).unwrap() = 0.0;
719 *points.get_mut([0, 3]).unwrap() = 0.5;
720 *points.get_mut([1, 3]).unwrap() = 0.0;
721 *points.get_mut([2, 3]).unwrap() = 0.5;
722 *points.get_mut([0, 4]).unwrap() = 0.0;
723 *points.get_mut([1, 4]).unwrap() = 0.5;
724 *points.get_mut([2, 4]).unwrap() = 0.5;
725 *points.get_mut([0, 5]).unwrap() = 0.5;
726 *points.get_mut([1, 5]).unwrap() = 0.5;
727 *points.get_mut([2, 5]).unwrap() = 0.5;
728 e.tabulate(&points, 0, &mut data);
729
730 for pt in 0..6 {
731 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
732 }
733 check_dofs(e);
734 }
735
736 #[test]
737 fn test_lagrange_1_hexahedron() {
738 let e = create::<f64, f64>(
739 ReferenceCellType::Hexahedron,
740 1,
741 Continuity::Standard,
742 LagrangeVariant::Equispaced,
743 );
744 assert_eq!(e.value_size(), 1);
745 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
746 let mut points = rlst_dynamic_array!(f64, [3, 6]);
747 *points.get_mut([0, 0]).unwrap() = 0.0;
748 *points.get_mut([1, 0]).unwrap() = 0.0;
749 *points.get_mut([2, 0]).unwrap() = 0.0;
750 *points.get_mut([0, 1]).unwrap() = 1.0;
751 *points.get_mut([1, 1]).unwrap() = 0.0;
752 *points.get_mut([2, 1]).unwrap() = 0.0;
753 *points.get_mut([0, 2]).unwrap() = 0.0;
754 *points.get_mut([1, 2]).unwrap() = 1.0;
755 *points.get_mut([2, 2]).unwrap() = 1.0;
756 *points.get_mut([0, 3]).unwrap() = 1.0;
757 *points.get_mut([1, 3]).unwrap() = 1.0;
758 *points.get_mut([2, 3]).unwrap() = 1.0;
759 *points.get_mut([0, 4]).unwrap() = 0.25;
760 *points.get_mut([1, 4]).unwrap() = 0.5;
761 *points.get_mut([2, 4]).unwrap() = 0.1;
762 *points.get_mut([0, 5]).unwrap() = 0.3;
763 *points.get_mut([1, 5]).unwrap() = 0.2;
764 *points.get_mut([2, 5]).unwrap() = 0.4;
765
766 e.tabulate(&points, 0, &mut data);
767
768 for pt in 0..6 {
769 let x = *points.get([0, pt]).unwrap();
770 let y = *points.get([1, pt]).unwrap();
771 let z = *points.get([2, pt]).unwrap();
772 assert_relative_eq!(
773 *data.get([0, pt, 0, 0]).unwrap(),
774 (1.0 - x) * (1.0 - y) * (1.0 - z),
775 epsilon = 1e-14
776 );
777 assert_relative_eq!(
778 *data.get([0, pt, 1, 0]).unwrap(),
779 x * (1.0 - y) * (1.0 - z),
780 epsilon = 1e-14
781 );
782 assert_relative_eq!(
783 *data.get([0, pt, 2, 0]).unwrap(),
784 (1.0 - x) * y * (1.0 - z),
785 epsilon = 1e-14
786 );
787 assert_relative_eq!(
788 *data.get([0, pt, 3, 0]).unwrap(),
789 x * y * (1.0 - z),
790 epsilon = 1e-14
791 );
792 assert_relative_eq!(
793 *data.get([0, pt, 4, 0]).unwrap(),
794 (1.0 - x) * (1.0 - y) * z,
795 epsilon = 1e-14
796 );
797 assert_relative_eq!(
798 *data.get([0, pt, 5, 0]).unwrap(),
799 x * (1.0 - y) * z,
800 epsilon = 1e-14
801 );
802 assert_relative_eq!(
803 *data.get([0, pt, 6, 0]).unwrap(),
804 (1.0 - x) * y * z,
805 epsilon = 1e-14
806 );
807 assert_relative_eq!(
808 *data.get([0, pt, 7, 0]).unwrap(),
809 x * y * z,
810 epsilon = 1e-14
811 );
812 }
813 check_dofs(e);
814 }
815
816 #[test]
817 fn test_lagrange_higher_degree_triangle() {
818 create::<f64, f64>(
819 ReferenceCellType::Triangle,
820 2,
821 Continuity::Standard,
822 LagrangeVariant::Equispaced,
823 );
824 create::<f64, f64>(
825 ReferenceCellType::Triangle,
826 3,
827 Continuity::Standard,
828 LagrangeVariant::Equispaced,
829 );
830 create::<f64, f64>(
831 ReferenceCellType::Triangle,
832 4,
833 Continuity::Standard,
834 LagrangeVariant::Equispaced,
835 );
836 create::<f64, f64>(
837 ReferenceCellType::Triangle,
838 5,
839 Continuity::Standard,
840 LagrangeVariant::Equispaced,
841 );
842
843 create::<f64, f64>(
844 ReferenceCellType::Triangle,
845 2,
846 Continuity::Discontinuous,
847 LagrangeVariant::Equispaced,
848 );
849 create::<f64, f64>(
850 ReferenceCellType::Triangle,
851 3,
852 Continuity::Discontinuous,
853 LagrangeVariant::Equispaced,
854 );
855 create::<f64, f64>(
856 ReferenceCellType::Triangle,
857 4,
858 Continuity::Discontinuous,
859 LagrangeVariant::Equispaced,
860 );
861 create::<f64, f64>(
862 ReferenceCellType::Triangle,
863 5,
864 Continuity::Discontinuous,
865 LagrangeVariant::Equispaced,
866 );
867 }
868
869 #[test]
870 fn test_lagrange_higher_degree_interval() {
871 create::<f64, f64>(
872 ReferenceCellType::Interval,
873 2,
874 Continuity::Standard,
875 LagrangeVariant::Equispaced,
876 );
877 create::<f64, f64>(
878 ReferenceCellType::Interval,
879 3,
880 Continuity::Standard,
881 LagrangeVariant::Equispaced,
882 );
883 create::<f64, f64>(
884 ReferenceCellType::Interval,
885 4,
886 Continuity::Standard,
887 LagrangeVariant::Equispaced,
888 );
889 create::<f64, f64>(
890 ReferenceCellType::Interval,
891 5,
892 Continuity::Standard,
893 LagrangeVariant::Equispaced,
894 );
895
896 create::<f64, f64>(
897 ReferenceCellType::Interval,
898 2,
899 Continuity::Discontinuous,
900 LagrangeVariant::Equispaced,
901 );
902 create::<f64, f64>(
903 ReferenceCellType::Interval,
904 3,
905 Continuity::Discontinuous,
906 LagrangeVariant::Equispaced,
907 );
908 create::<f64, f64>(
909 ReferenceCellType::Interval,
910 4,
911 Continuity::Discontinuous,
912 LagrangeVariant::Equispaced,
913 );
914 create::<f64, f64>(
915 ReferenceCellType::Interval,
916 5,
917 Continuity::Discontinuous,
918 LagrangeVariant::Equispaced,
919 );
920 }
921
922 #[test]
923 fn test_lagrange_higher_degree_quadrilateral() {
924 create::<f64, f64>(
925 ReferenceCellType::Quadrilateral,
926 2,
927 Continuity::Standard,
928 LagrangeVariant::Equispaced,
929 );
930 create::<f64, f64>(
931 ReferenceCellType::Quadrilateral,
932 3,
933 Continuity::Standard,
934 LagrangeVariant::Equispaced,
935 );
936 create::<f64, f64>(
937 ReferenceCellType::Quadrilateral,
938 4,
939 Continuity::Standard,
940 LagrangeVariant::Equispaced,
941 );
942 create::<f64, f64>(
943 ReferenceCellType::Quadrilateral,
944 5,
945 Continuity::Standard,
946 LagrangeVariant::Equispaced,
947 );
948
949 create::<f64, f64>(
950 ReferenceCellType::Quadrilateral,
951 2,
952 Continuity::Discontinuous,
953 LagrangeVariant::Equispaced,
954 );
955 create::<f64, f64>(
956 ReferenceCellType::Quadrilateral,
957 3,
958 Continuity::Discontinuous,
959 LagrangeVariant::Equispaced,
960 );
961 create::<f64, f64>(
962 ReferenceCellType::Quadrilateral,
963 4,
964 Continuity::Discontinuous,
965 LagrangeVariant::Equispaced,
966 );
967 create::<f64, f64>(
968 ReferenceCellType::Quadrilateral,
969 5,
970 Continuity::Discontinuous,
971 LagrangeVariant::Equispaced,
972 );
973 }
974
975 #[test]
976 fn test_lagrange_interval_equispaced() {
977 let e = create::<f64, f64>(
978 ReferenceCellType::Interval,
979 4,
980 Continuity::Discontinuous,
981 LagrangeVariant::Equispaced,
982 );
983
984 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 2));
985 let mut points = rlst_dynamic_array!(f64, [1, 2]);
986 *points.get_mut([0, 0]).unwrap() = 0.25;
987 *points.get_mut([0, 1]).unwrap() = 0.75;
988
989 e.tabulate(&points, 0, &mut data);
990
991 for pt in 0..data.shape()[1] {
992 for basis in 0..data.shape()[1] {
993 assert!(
994 data.get([0, pt, basis, 0]).unwrap().abs() < 1e-10
995 || (1.0 - data.get([0, pt, basis, 0]).unwrap()).abs() < 1e-14
996 );
997 }
998 }
999 }
1000
1001 #[test]
1002 fn test_lagrange_interval_gll() {
1003 let e = create::<f64, f64>(
1004 ReferenceCellType::Interval,
1005 4,
1006 Continuity::Discontinuous,
1007 LagrangeVariant::GLL,
1008 );
1009
1010 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 2));
1011 let mut points = rlst_dynamic_array!(f64, [1, 2]);
1012 *points.get_mut([0, 0]).unwrap() = 0.25;
1013 *points.get_mut([0, 1]).unwrap() = 0.75;
1014
1015 e.tabulate(&points, 0, &mut data);
1016
1017 for pt in 0..data.shape()[1] {
1018 for basis in 0..data.shape()[1] {
1019 assert!(data.get([0, pt, basis, 0]).unwrap().abs() > 1e-10);
1020 }
1021 }
1022 }
1023
1024 #[test]
1025 fn test_lagrange_quadrilateral_equispaced() {
1026 let e = create::<f64, f64>(
1027 ReferenceCellType::Quadrilateral,
1028 4,
1029 Continuity::Discontinuous,
1030 LagrangeVariant::Equispaced,
1031 );
1032
1033 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
1034 let mut points = rlst_dynamic_array!(f64, [2, 4]);
1035 *points.get_mut([0, 0]).unwrap() = 0.25;
1036 *points.get_mut([1, 0]).unwrap() = 0.25;
1037 *points.get_mut([0, 1]).unwrap() = 0.25;
1038 *points.get_mut([1, 1]).unwrap() = 0.75;
1039 *points.get_mut([0, 2]).unwrap() = 0.75;
1040 *points.get_mut([1, 2]).unwrap() = 0.25;
1041 *points.get_mut([0, 3]).unwrap() = 0.75;
1042 *points.get_mut([1, 3]).unwrap() = 0.75;
1043
1044 e.tabulate(&points, 0, &mut data);
1045
1046 for pt in 0..data.shape()[1] {
1047 for basis in 0..data.shape()[1] {
1048 assert!(
1049 data.get([0, pt, basis, 0]).unwrap().abs() < 1e-10
1050 || (1.0 - data.get([0, pt, basis, 0]).unwrap()).abs() < 1e-14
1051 );
1052 }
1053 }
1054 }
1055
1056 #[test]
1057 fn test_lagrange_quadrilateral_gll() {
1058 let e = create::<f64, f64>(
1059 ReferenceCellType::Quadrilateral,
1060 4,
1061 Continuity::Discontinuous,
1062 LagrangeVariant::GLL,
1063 );
1064
1065 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
1066 let mut points = rlst_dynamic_array!(f64, [2, 4]);
1067 *points.get_mut([0, 0]).unwrap() = 0.25;
1068 *points.get_mut([1, 0]).unwrap() = 0.25;
1069 *points.get_mut([0, 1]).unwrap() = 0.25;
1070 *points.get_mut([1, 1]).unwrap() = 0.75;
1071 *points.get_mut([0, 2]).unwrap() = 0.75;
1072 *points.get_mut([1, 2]).unwrap() = 0.25;
1073 *points.get_mut([0, 3]).unwrap() = 0.75;
1074 *points.get_mut([1, 3]).unwrap() = 0.75;
1075
1076 e.tabulate(&points, 0, &mut data);
1077
1078 for pt in 0..data.shape()[1] {
1079 for basis in 0..data.shape()[1] {
1080 assert!(data.get([0, pt, basis, 0]).unwrap().abs() > 1e-10);
1081 }
1082 }
1083 }
1084
1085 fn ordered(x: &[f64], y: &[f64]) -> bool {
1086 assert_eq!(x.len(), y.len());
1087 if x.is_empty() {
1088 false
1089 } else if (x[x.len() - 1] - y[y.len() - 1]).abs() < 1e-8 {
1090 ordered(&x[..x.len() - 1], &y[..y.len() - 1])
1091 } else {
1092 x[x.len() - 1] < y[y.len() - 1]
1093 }
1094 }
1095
1096 macro_rules! test_point_ordering {
1097 ($cell:ident, $max_degree:expr) => {
1098 paste! {
1099 #[test]
1100 fn [<test_point_ordering_ $cell:lower>]() {
1101 for degree in 3..=[<$max_degree>] {
1102 let e = create::<f64, f64>(
1103 ReferenceCellType::[<$cell>],
1104 degree,
1105 Continuity::Standard,
1106 LagrangeVariant::Equispaced,
1107 );
1108 for pt_sets in &e.interpolation_points {
1109 for pts in pt_sets {
1110 if pts.shape()[1] > 0 {
1111 for i in 0..pts.shape()[1] - 1 {
1112 assert!(ordered(&pts.r().col(i).data().unwrap(), &pts.r().col(i + 1).data().unwrap()));
1113 }
1114 }
1115 }
1116 }
1117 }
1118 }
1119 }
1120 };
1121 }
1122
1123 test_point_ordering!(Triangle, 7);
1124 test_point_ordering!(Quadrilateral, 7);
1125 test_point_ordering!(Tetrahedron, 6);
1126 test_point_ordering!(Hexahedron, 4);
1127}