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 Variant {
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: Variant,
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 Variant::Equispaced => (1..degree)
82 .map(|i| num::cast::<_, TGeo>(i).unwrap() / num::cast::<_, TGeo>(degree).unwrap())
83 .collect::<Vec<_>>(),
84 Variant::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 != Variant::Equispaced {
145 unimplemented!();
146 }
147 let mut n = 0;
148 for i0 in 1..degree {
149 for i1 in 1..degree - i0 {
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 p0 in &pts1d {
167 for p1 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 != Variant::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 i0 in 1..degree {
224 for i1 in 1..degree - i0 {
225 for i2 in 1..degree - i0 - 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 p0 in &pts1d {
255 for p1 in &pts1d {
256 for p2 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: Variant,
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: Variant) -> 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 rlst::DynArray;
339
340 #[test]
341 fn test_lagrange_1() {
342 let e = create::<f64, f64>(
343 ReferenceCellType::Triangle,
344 1,
345 Continuity::Standard,
346 Variant::Equispaced,
347 );
348 assert_eq!(e.value_size(), 1);
349 }
350
351 #[test]
352 fn test_lagrange_0_interval() {
353 let e = create::<f64, f64>(
354 ReferenceCellType::Interval,
355 0,
356 Continuity::Discontinuous,
357 Variant::Equispaced,
358 );
359 assert_eq!(e.value_size(), 1);
360 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
361 let mut points = rlst_dynamic_array!(f64, [1, 4]);
362 *points.get_mut([0, 0]).unwrap() = 0.0;
363 *points.get_mut([0, 1]).unwrap() = 0.2;
364 *points.get_mut([0, 2]).unwrap() = 0.4;
365 *points.get_mut([0, 3]).unwrap() = 1.0;
366 e.tabulate(&points, 0, &mut data);
367
368 for pt in 0..4 {
369 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
370 }
371 check_dofs(e);
372 }
373
374 #[test]
375 fn test_lagrange_1_interval() {
376 let e = create::<f64, f64>(
377 ReferenceCellType::Interval,
378 1,
379 Continuity::Standard,
380 Variant::Equispaced,
381 );
382 assert_eq!(e.value_size(), 1);
383 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
384 let mut points = rlst_dynamic_array!(f64, [1, 4]);
385 *points.get_mut([0, 0]).unwrap() = 0.0;
386 *points.get_mut([0, 1]).unwrap() = 0.2;
387 *points.get_mut([0, 2]).unwrap() = 0.4;
388 *points.get_mut([0, 3]).unwrap() = 1.0;
389 e.tabulate(&points, 0, &mut data);
390
391 for pt in 0..4 {
392 let x = *points.get([0, pt]).unwrap();
393 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0 - x);
394 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x);
395 }
396 check_dofs(e);
397 }
398
399 #[test]
400 fn test_lagrange_0_triangle() {
401 let e = create::<f64, f64>(
402 ReferenceCellType::Triangle,
403 0,
404 Continuity::Discontinuous,
405 Variant::Equispaced,
406 );
407 assert_eq!(e.value_size(), 1);
408 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
409
410 let mut points = rlst_dynamic_array!(f64, [2, 6]);
411 *points.get_mut([0, 0]).unwrap() = 0.0;
412 *points.get_mut([1, 0]).unwrap() = 0.0;
413 *points.get_mut([0, 1]).unwrap() = 1.0;
414 *points.get_mut([1, 1]).unwrap() = 0.0;
415 *points.get_mut([0, 2]).unwrap() = 0.0;
416 *points.get_mut([1, 2]).unwrap() = 1.0;
417 *points.get_mut([0, 3]).unwrap() = 0.5;
418 *points.get_mut([1, 3]).unwrap() = 0.0;
419 *points.get_mut([0, 4]).unwrap() = 0.0;
420 *points.get_mut([1, 4]).unwrap() = 0.5;
421 *points.get_mut([0, 5]).unwrap() = 0.5;
422 *points.get_mut([1, 5]).unwrap() = 0.5;
423
424 e.tabulate(&points, 0, &mut data);
425
426 for pt in 0..6 {
427 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
428 }
429 check_dofs(e);
430 }
431
432 #[test]
433 fn test_lagrange_1_triangle() {
434 let e = create::<f64, f64>(
435 ReferenceCellType::Triangle,
436 1,
437 Continuity::Standard,
438 Variant::Equispaced,
439 );
440 assert_eq!(e.value_size(), 1);
441 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
442 let mut points = rlst_dynamic_array!(f64, [2, 6]);
443 *points.get_mut([0, 0]).unwrap() = 0.0;
444 *points.get_mut([1, 0]).unwrap() = 0.0;
445 *points.get_mut([0, 1]).unwrap() = 1.0;
446 *points.get_mut([1, 1]).unwrap() = 0.0;
447 *points.get_mut([0, 2]).unwrap() = 0.0;
448 *points.get_mut([1, 2]).unwrap() = 1.0;
449 *points.get_mut([0, 3]).unwrap() = 0.5;
450 *points.get_mut([1, 3]).unwrap() = 0.0;
451 *points.get_mut([0, 4]).unwrap() = 0.0;
452 *points.get_mut([1, 4]).unwrap() = 0.5;
453 *points.get_mut([0, 5]).unwrap() = 0.5;
454 *points.get_mut([1, 5]).unwrap() = 0.5;
455 e.tabulate(&points, 0, &mut data);
456
457 for pt in 0..6 {
458 let x = *points.get([0, pt]).unwrap();
459 let y = *points.get([1, pt]).unwrap();
460 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0 - x - y);
461 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x);
462 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), y);
463 }
464 check_dofs(e);
465 }
466
467 #[test]
468 fn test_lagrange_0_quadrilateral() {
469 let e = create::<f64, f64>(
470 ReferenceCellType::Quadrilateral,
471 0,
472 Continuity::Discontinuous,
473 Variant::Equispaced,
474 );
475 assert_eq!(e.value_size(), 1);
476 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
477 let mut points = rlst_dynamic_array!(f64, [2, 6]);
478 *points.get_mut([0, 0]).unwrap() = 0.0;
479 *points.get_mut([1, 0]).unwrap() = 0.0;
480 *points.get_mut([0, 1]).unwrap() = 1.0;
481 *points.get_mut([1, 1]).unwrap() = 0.0;
482 *points.get_mut([0, 2]).unwrap() = 0.0;
483 *points.get_mut([1, 2]).unwrap() = 1.0;
484 *points.get_mut([0, 3]).unwrap() = 0.5;
485 *points.get_mut([1, 3]).unwrap() = 0.0;
486 *points.get_mut([0, 4]).unwrap() = 0.0;
487 *points.get_mut([1, 4]).unwrap() = 0.5;
488 *points.get_mut([0, 5]).unwrap() = 0.5;
489 *points.get_mut([1, 5]).unwrap() = 0.5;
490 e.tabulate(&points, 0, &mut data);
491
492 for pt in 0..6 {
493 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
494 }
495 check_dofs(e);
496 }
497
498 #[test]
499 fn test_lagrange_1_quadrilateral() {
500 let e = create::<f64, f64>(
501 ReferenceCellType::Quadrilateral,
502 1,
503 Continuity::Standard,
504 Variant::Equispaced,
505 );
506 assert_eq!(e.value_size(), 1);
507 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
508 let mut points = rlst_dynamic_array!(f64, [2, 6]);
509 *points.get_mut([0, 0]).unwrap() = 0.0;
510 *points.get_mut([1, 0]).unwrap() = 0.0;
511 *points.get_mut([0, 1]).unwrap() = 1.0;
512 *points.get_mut([1, 1]).unwrap() = 0.0;
513 *points.get_mut([0, 2]).unwrap() = 0.0;
514 *points.get_mut([1, 2]).unwrap() = 1.0;
515 *points.get_mut([0, 3]).unwrap() = 1.0;
516 *points.get_mut([1, 3]).unwrap() = 1.0;
517 *points.get_mut([0, 4]).unwrap() = 0.25;
518 *points.get_mut([1, 4]).unwrap() = 0.5;
519 *points.get_mut([0, 5]).unwrap() = 0.3;
520 *points.get_mut([1, 5]).unwrap() = 0.2;
521
522 e.tabulate(&points, 0, &mut data);
523
524 for pt in 0..6 {
525 let x = *points.get([0, pt]).unwrap();
526 let y = *points.get([1, pt]).unwrap();
527 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), (1.0 - x) * (1.0 - y));
528 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x * (1.0 - y));
529 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), (1.0 - x) * y);
530 assert_relative_eq!(*data.get([0, pt, 3, 0]).unwrap(), x * y);
531 }
532 check_dofs(e);
533 }
534
535 #[test]
536 fn test_lagrange_2_quadrilateral() {
537 let e = create::<f64, f64>(
538 ReferenceCellType::Quadrilateral,
539 2,
540 Continuity::Standard,
541 Variant::Equispaced,
542 );
543 assert_eq!(e.value_size(), 1);
544 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
545 let mut points = rlst_dynamic_array!(f64, [2, 6]);
546 *points.get_mut([0, 0]).unwrap() = 0.0;
547 *points.get_mut([1, 0]).unwrap() = 0.0;
548 *points.get_mut([0, 1]).unwrap() = 1.0;
549 *points.get_mut([1, 1]).unwrap() = 0.0;
550 *points.get_mut([0, 2]).unwrap() = 0.0;
551 *points.get_mut([1, 2]).unwrap() = 1.0;
552 *points.get_mut([0, 3]).unwrap() = 1.0;
553 *points.get_mut([1, 3]).unwrap() = 1.0;
554 *points.get_mut([0, 4]).unwrap() = 0.25;
555 *points.get_mut([1, 4]).unwrap() = 0.5;
556 *points.get_mut([0, 5]).unwrap() = 0.3;
557 *points.get_mut([1, 5]).unwrap() = 0.2;
558
559 e.tabulate(&points, 0, &mut data);
560
561 for pt in 0..6 {
562 let x = *points.get([0, pt]).unwrap();
563 let y = *points.get([1, pt]).unwrap();
564 assert_relative_eq!(
565 *data.get([0, pt, 0, 0]).unwrap(),
566 (1.0 - x) * (1.0 - 2.0 * x) * (1.0 - y) * (1.0 - 2.0 * y),
567 epsilon = 1e-14
568 );
569 assert_relative_eq!(
570 *data.get([0, pt, 1, 0]).unwrap(),
571 x * (2.0 * x - 1.0) * (1.0 - y) * (1.0 - 2.0 * y),
572 epsilon = 1e-14
573 );
574 assert_relative_eq!(
575 *data.get([0, pt, 2, 0]).unwrap(),
576 (1.0 - x) * (1.0 - 2.0 * x) * y * (2.0 * y - 1.0),
577 epsilon = 1e-14
578 );
579 assert_relative_eq!(
580 *data.get([0, pt, 3, 0]).unwrap(),
581 x * (2.0 * x - 1.0) * y * (2.0 * y - 1.0),
582 epsilon = 1e-14
583 );
584 assert_relative_eq!(
585 *data.get([0, pt, 4, 0]).unwrap(),
586 4.0 * x * (1.0 - x) * (1.0 - y) * (1.0 - 2.0 * y),
587 epsilon = 1e-14
588 );
589 assert_relative_eq!(
590 *data.get([0, pt, 5, 0]).unwrap(),
591 (1.0 - x) * (1.0 - 2.0 * x) * 4.0 * y * (1.0 - y),
592 epsilon = 1e-14
593 );
594 assert_relative_eq!(
595 *data.get([0, pt, 6, 0]).unwrap(),
596 x * (2.0 * x - 1.0) * 4.0 * y * (1.0 - y),
597 epsilon = 1e-14
598 );
599 assert_relative_eq!(
600 *data.get([0, pt, 7, 0]).unwrap(),
601 4.0 * x * (1.0 - x) * y * (2.0 * y - 1.0),
602 epsilon = 1e-14
603 );
604 assert_relative_eq!(
605 *data.get([0, pt, 8, 0]).unwrap(),
606 4.0 * x * (1.0 - x) * 4.0 * y * (1.0 - y),
607 epsilon = 1e-14
608 );
609 }
610 check_dofs(e);
611 }
612
613 #[test]
614 fn test_lagrange_0_tetrahedron() {
615 let e = create::<f64, f64>(
616 ReferenceCellType::Tetrahedron,
617 0,
618 Continuity::Discontinuous,
619 Variant::Equispaced,
620 );
621 assert_eq!(e.value_size(), 1);
622 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
623 let mut points = rlst_dynamic_array!(f64, [3, 6]);
624 *points.get_mut([0, 0]).unwrap() = 0.0;
625 *points.get_mut([1, 0]).unwrap() = 0.0;
626 *points.get_mut([2, 0]).unwrap() = 0.0;
627 *points.get_mut([0, 1]).unwrap() = 1.0;
628 *points.get_mut([1, 1]).unwrap() = 0.0;
629 *points.get_mut([2, 1]).unwrap() = 0.0;
630 *points.get_mut([0, 2]).unwrap() = 0.0;
631 *points.get_mut([1, 2]).unwrap() = 1.0;
632 *points.get_mut([2, 2]).unwrap() = 0.0;
633 *points.get_mut([0, 3]).unwrap() = 0.5;
634 *points.get_mut([1, 3]).unwrap() = 0.0;
635 *points.get_mut([2, 3]).unwrap() = 0.5;
636 *points.get_mut([0, 4]).unwrap() = 0.0;
637 *points.get_mut([1, 4]).unwrap() = 0.5;
638 *points.get_mut([2, 4]).unwrap() = 0.5;
639 *points.get_mut([0, 5]).unwrap() = 0.5;
640 *points.get_mut([1, 5]).unwrap() = 0.2;
641 *points.get_mut([2, 5]).unwrap() = 0.3;
642 e.tabulate(&points, 0, &mut data);
643
644 for pt in 0..6 {
645 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
646 }
647 check_dofs(e);
648 }
649
650 #[test]
651 fn test_lagrange_1_tetrahedron() {
652 let e = create::<f64, f64>(
653 ReferenceCellType::Tetrahedron,
654 1,
655 Continuity::Standard,
656 Variant::Equispaced,
657 );
658 assert_eq!(e.value_size(), 1);
659 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
660 let mut points = rlst_dynamic_array!(f64, [3, 6]);
661 *points.get_mut([0, 0]).unwrap() = 0.0;
662 *points.get_mut([1, 0]).unwrap() = 0.0;
663 *points.get_mut([2, 0]).unwrap() = 0.0;
664 *points.get_mut([0, 1]).unwrap() = 1.0;
665 *points.get_mut([1, 1]).unwrap() = 0.0;
666 *points.get_mut([2, 1]).unwrap() = 0.0;
667 *points.get_mut([0, 2]).unwrap() = 0.0;
668 *points.get_mut([1, 2]).unwrap() = 0.8;
669 *points.get_mut([2, 2]).unwrap() = 0.2;
670 *points.get_mut([0, 3]).unwrap() = 0.0;
671 *points.get_mut([1, 3]).unwrap() = 0.0;
672 *points.get_mut([2, 3]).unwrap() = 0.8;
673 *points.get_mut([0, 4]).unwrap() = 0.25;
674 *points.get_mut([1, 4]).unwrap() = 0.5;
675 *points.get_mut([2, 4]).unwrap() = 0.1;
676 *points.get_mut([0, 5]).unwrap() = 0.2;
677 *points.get_mut([1, 5]).unwrap() = 0.1;
678 *points.get_mut([2, 5]).unwrap() = 0.15;
679
680 e.tabulate(&points, 0, &mut data);
681
682 for pt in 0..6 {
683 let x = *points.get([0, pt]).unwrap();
684 let y = *points.get([1, pt]).unwrap();
685 let z = *points.get([2, pt]).unwrap();
686 assert_relative_eq!(
687 *data.get([0, pt, 0, 0]).unwrap(),
688 1.0 - x - y - z,
689 epsilon = 1e-14
690 );
691 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x, epsilon = 1e-14);
692 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), y, epsilon = 1e-14);
693 assert_relative_eq!(*data.get([0, pt, 3, 0]).unwrap(), z, epsilon = 1e-14);
694 }
695 check_dofs(e);
696 }
697
698 #[test]
699 fn test_lagrange_0_hexahedron() {
700 let e = create::<f64, f64>(
701 ReferenceCellType::Hexahedron,
702 0,
703 Continuity::Discontinuous,
704 Variant::Equispaced,
705 );
706 assert_eq!(e.value_size(), 1);
707 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
708 let mut points = rlst_dynamic_array!(f64, [3, 6]);
709 *points.get_mut([0, 0]).unwrap() = 0.0;
710 *points.get_mut([1, 0]).unwrap() = 0.0;
711 *points.get_mut([2, 0]).unwrap() = 0.0;
712 *points.get_mut([0, 1]).unwrap() = 1.0;
713 *points.get_mut([1, 1]).unwrap() = 0.0;
714 *points.get_mut([2, 1]).unwrap() = 0.0;
715 *points.get_mut([0, 2]).unwrap() = 0.0;
716 *points.get_mut([1, 2]).unwrap() = 1.0;
717 *points.get_mut([2, 2]).unwrap() = 0.0;
718 *points.get_mut([0, 3]).unwrap() = 0.5;
719 *points.get_mut([1, 3]).unwrap() = 0.0;
720 *points.get_mut([2, 3]).unwrap() = 0.5;
721 *points.get_mut([0, 4]).unwrap() = 0.0;
722 *points.get_mut([1, 4]).unwrap() = 0.5;
723 *points.get_mut([2, 4]).unwrap() = 0.5;
724 *points.get_mut([0, 5]).unwrap() = 0.5;
725 *points.get_mut([1, 5]).unwrap() = 0.5;
726 *points.get_mut([2, 5]).unwrap() = 0.5;
727 e.tabulate(&points, 0, &mut data);
728
729 for pt in 0..6 {
730 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
731 }
732 check_dofs(e);
733 }
734
735 #[test]
736 fn test_lagrange_1_hexahedron() {
737 let e = create::<f64, f64>(
738 ReferenceCellType::Hexahedron,
739 1,
740 Continuity::Standard,
741 Variant::Equispaced,
742 );
743 assert_eq!(e.value_size(), 1);
744 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
745 let mut points = rlst_dynamic_array!(f64, [3, 6]);
746 *points.get_mut([0, 0]).unwrap() = 0.0;
747 *points.get_mut([1, 0]).unwrap() = 0.0;
748 *points.get_mut([2, 0]).unwrap() = 0.0;
749 *points.get_mut([0, 1]).unwrap() = 1.0;
750 *points.get_mut([1, 1]).unwrap() = 0.0;
751 *points.get_mut([2, 1]).unwrap() = 0.0;
752 *points.get_mut([0, 2]).unwrap() = 0.0;
753 *points.get_mut([1, 2]).unwrap() = 1.0;
754 *points.get_mut([2, 2]).unwrap() = 1.0;
755 *points.get_mut([0, 3]).unwrap() = 1.0;
756 *points.get_mut([1, 3]).unwrap() = 1.0;
757 *points.get_mut([2, 3]).unwrap() = 1.0;
758 *points.get_mut([0, 4]).unwrap() = 0.25;
759 *points.get_mut([1, 4]).unwrap() = 0.5;
760 *points.get_mut([2, 4]).unwrap() = 0.1;
761 *points.get_mut([0, 5]).unwrap() = 0.3;
762 *points.get_mut([1, 5]).unwrap() = 0.2;
763 *points.get_mut([2, 5]).unwrap() = 0.4;
764
765 e.tabulate(&points, 0, &mut data);
766
767 for pt in 0..6 {
768 let x = *points.get([0, pt]).unwrap();
769 let y = *points.get([1, pt]).unwrap();
770 let z = *points.get([2, pt]).unwrap();
771 assert_relative_eq!(
772 *data.get([0, pt, 0, 0]).unwrap(),
773 (1.0 - x) * (1.0 - y) * (1.0 - z),
774 epsilon = 1e-14
775 );
776 assert_relative_eq!(
777 *data.get([0, pt, 1, 0]).unwrap(),
778 x * (1.0 - y) * (1.0 - z),
779 epsilon = 1e-14
780 );
781 assert_relative_eq!(
782 *data.get([0, pt, 2, 0]).unwrap(),
783 (1.0 - x) * y * (1.0 - z),
784 epsilon = 1e-14
785 );
786 assert_relative_eq!(
787 *data.get([0, pt, 3, 0]).unwrap(),
788 x * y * (1.0 - z),
789 epsilon = 1e-14
790 );
791 assert_relative_eq!(
792 *data.get([0, pt, 4, 0]).unwrap(),
793 (1.0 - x) * (1.0 - y) * z,
794 epsilon = 1e-14
795 );
796 assert_relative_eq!(
797 *data.get([0, pt, 5, 0]).unwrap(),
798 x * (1.0 - y) * z,
799 epsilon = 1e-14
800 );
801 assert_relative_eq!(
802 *data.get([0, pt, 6, 0]).unwrap(),
803 (1.0 - x) * y * z,
804 epsilon = 1e-14
805 );
806 assert_relative_eq!(
807 *data.get([0, pt, 7, 0]).unwrap(),
808 x * y * z,
809 epsilon = 1e-14
810 );
811 }
812 check_dofs(e);
813 }
814
815 #[test]
816 fn test_lagrange_higher_degree_triangle() {
817 create::<f64, f64>(
818 ReferenceCellType::Triangle,
819 2,
820 Continuity::Standard,
821 Variant::Equispaced,
822 );
823 create::<f64, f64>(
824 ReferenceCellType::Triangle,
825 3,
826 Continuity::Standard,
827 Variant::Equispaced,
828 );
829 create::<f64, f64>(
830 ReferenceCellType::Triangle,
831 4,
832 Continuity::Standard,
833 Variant::Equispaced,
834 );
835 create::<f64, f64>(
836 ReferenceCellType::Triangle,
837 5,
838 Continuity::Standard,
839 Variant::Equispaced,
840 );
841
842 create::<f64, f64>(
843 ReferenceCellType::Triangle,
844 2,
845 Continuity::Discontinuous,
846 Variant::Equispaced,
847 );
848 create::<f64, f64>(
849 ReferenceCellType::Triangle,
850 3,
851 Continuity::Discontinuous,
852 Variant::Equispaced,
853 );
854 create::<f64, f64>(
855 ReferenceCellType::Triangle,
856 4,
857 Continuity::Discontinuous,
858 Variant::Equispaced,
859 );
860 create::<f64, f64>(
861 ReferenceCellType::Triangle,
862 5,
863 Continuity::Discontinuous,
864 Variant::Equispaced,
865 );
866 }
867
868 #[test]
869 fn test_lagrange_higher_degree_interval() {
870 create::<f64, f64>(
871 ReferenceCellType::Interval,
872 2,
873 Continuity::Standard,
874 Variant::Equispaced,
875 );
876 create::<f64, f64>(
877 ReferenceCellType::Interval,
878 3,
879 Continuity::Standard,
880 Variant::Equispaced,
881 );
882 create::<f64, f64>(
883 ReferenceCellType::Interval,
884 4,
885 Continuity::Standard,
886 Variant::Equispaced,
887 );
888 create::<f64, f64>(
889 ReferenceCellType::Interval,
890 5,
891 Continuity::Standard,
892 Variant::Equispaced,
893 );
894
895 create::<f64, f64>(
896 ReferenceCellType::Interval,
897 2,
898 Continuity::Discontinuous,
899 Variant::Equispaced,
900 );
901 create::<f64, f64>(
902 ReferenceCellType::Interval,
903 3,
904 Continuity::Discontinuous,
905 Variant::Equispaced,
906 );
907 create::<f64, f64>(
908 ReferenceCellType::Interval,
909 4,
910 Continuity::Discontinuous,
911 Variant::Equispaced,
912 );
913 create::<f64, f64>(
914 ReferenceCellType::Interval,
915 5,
916 Continuity::Discontinuous,
917 Variant::Equispaced,
918 );
919 }
920
921 #[test]
922 fn test_lagrange_higher_degree_quadrilateral() {
923 create::<f64, f64>(
924 ReferenceCellType::Quadrilateral,
925 2,
926 Continuity::Standard,
927 Variant::Equispaced,
928 );
929 create::<f64, f64>(
930 ReferenceCellType::Quadrilateral,
931 3,
932 Continuity::Standard,
933 Variant::Equispaced,
934 );
935 create::<f64, f64>(
936 ReferenceCellType::Quadrilateral,
937 4,
938 Continuity::Standard,
939 Variant::Equispaced,
940 );
941 create::<f64, f64>(
942 ReferenceCellType::Quadrilateral,
943 5,
944 Continuity::Standard,
945 Variant::Equispaced,
946 );
947
948 create::<f64, f64>(
949 ReferenceCellType::Quadrilateral,
950 2,
951 Continuity::Discontinuous,
952 Variant::Equispaced,
953 );
954 create::<f64, f64>(
955 ReferenceCellType::Quadrilateral,
956 3,
957 Continuity::Discontinuous,
958 Variant::Equispaced,
959 );
960 create::<f64, f64>(
961 ReferenceCellType::Quadrilateral,
962 4,
963 Continuity::Discontinuous,
964 Variant::Equispaced,
965 );
966 create::<f64, f64>(
967 ReferenceCellType::Quadrilateral,
968 5,
969 Continuity::Discontinuous,
970 Variant::Equispaced,
971 );
972 }
973
974 #[test]
975 fn test_lagrange_interval_equispaced() {
976 let e = create::<f64, f64>(
977 ReferenceCellType::Interval,
978 4,
979 Continuity::Discontinuous,
980 Variant::Equispaced,
981 );
982
983 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 2));
984 let mut points = rlst_dynamic_array!(f64, [1, 2]);
985 *points.get_mut([0, 0]).unwrap() = 0.25;
986 *points.get_mut([0, 1]).unwrap() = 0.75;
987
988 e.tabulate(&points, 0, &mut data);
989
990 for pt in 0..data.shape()[1] {
991 for basis in 0..data.shape()[1] {
992 assert!(
993 data.get([0, pt, basis, 0]).unwrap().abs() < 1e-10
994 || (1.0 - data.get([0, pt, basis, 0]).unwrap()).abs() < 1e-14
995 );
996 }
997 }
998 }
999
1000 #[test]
1001 fn test_lagrange_interval_gll() {
1002 let e = create::<f64, f64>(
1003 ReferenceCellType::Interval,
1004 4,
1005 Continuity::Discontinuous,
1006 Variant::GLL,
1007 );
1008
1009 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 2));
1010 let mut points = rlst_dynamic_array!(f64, [1, 2]);
1011 *points.get_mut([0, 0]).unwrap() = 0.25;
1012 *points.get_mut([0, 1]).unwrap() = 0.75;
1013
1014 e.tabulate(&points, 0, &mut data);
1015
1016 for pt in 0..data.shape()[1] {
1017 for basis in 0..data.shape()[1] {
1018 assert!(data.get([0, pt, basis, 0]).unwrap().abs() > 1e-10);
1019 }
1020 }
1021 }
1022
1023 #[test]
1024 fn test_lagrange_quadrilateral_equispaced() {
1025 let e = create::<f64, f64>(
1026 ReferenceCellType::Quadrilateral,
1027 4,
1028 Continuity::Discontinuous,
1029 Variant::Equispaced,
1030 );
1031
1032 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
1033 let mut points = rlst_dynamic_array!(f64, [2, 4]);
1034 *points.get_mut([0, 0]).unwrap() = 0.25;
1035 *points.get_mut([1, 0]).unwrap() = 0.25;
1036 *points.get_mut([0, 1]).unwrap() = 0.25;
1037 *points.get_mut([1, 1]).unwrap() = 0.75;
1038 *points.get_mut([0, 2]).unwrap() = 0.75;
1039 *points.get_mut([1, 2]).unwrap() = 0.25;
1040 *points.get_mut([0, 3]).unwrap() = 0.75;
1041 *points.get_mut([1, 3]).unwrap() = 0.75;
1042
1043 e.tabulate(&points, 0, &mut data);
1044
1045 for pt in 0..data.shape()[1] {
1046 for basis in 0..data.shape()[1] {
1047 assert!(
1048 data.get([0, pt, basis, 0]).unwrap().abs() < 1e-10
1049 || (1.0 - data.get([0, pt, basis, 0]).unwrap()).abs() < 1e-14
1050 );
1051 }
1052 }
1053 }
1054
1055 #[test]
1056 fn test_lagrange_quadrilateral_gll() {
1057 let e = create::<f64, f64>(
1058 ReferenceCellType::Quadrilateral,
1059 4,
1060 Continuity::Discontinuous,
1061 Variant::GLL,
1062 );
1063
1064 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
1065 let mut points = rlst_dynamic_array!(f64, [2, 4]);
1066 *points.get_mut([0, 0]).unwrap() = 0.25;
1067 *points.get_mut([1, 0]).unwrap() = 0.25;
1068 *points.get_mut([0, 1]).unwrap() = 0.25;
1069 *points.get_mut([1, 1]).unwrap() = 0.75;
1070 *points.get_mut([0, 2]).unwrap() = 0.75;
1071 *points.get_mut([1, 2]).unwrap() = 0.25;
1072 *points.get_mut([0, 3]).unwrap() = 0.75;
1073 *points.get_mut([1, 3]).unwrap() = 0.75;
1074
1075 e.tabulate(&points, 0, &mut data);
1076
1077 for pt in 0..data.shape()[1] {
1078 for basis in 0..data.shape()[1] {
1079 assert!(data.get([0, pt, basis, 0]).unwrap().abs() > 1e-10);
1080 }
1081 }
1082 }
1083}