1extern crate blas_src;
30extern crate lapack_src;
31
32use crate::math;
33use crate::polynomials::{legendre_shape, polynomial_count, tabulate_legendre_polynomials};
34use crate::reference_cell;
35use crate::traits::{FiniteElement, Map, MappedFiniteElement};
36use crate::types::{Continuity, DofTransformation, ReferenceCellType, Transformation};
37use itertools::izip;
38use rlst::RlstScalar;
39use rlst::{Array, DynArray, Inverse, MutableArrayImpl, ValueArrayImpl, rlst_dynamic_array};
40use std::collections::HashMap;
41use std::fmt::{Debug, Formatter};
42
43pub mod lagrange;
44pub mod nedelec;
45pub mod raviart_thomas;
46pub use lagrange::LagrangeElementFamily;
47pub use nedelec::NedelecFirstKindElementFamily;
48pub use raviart_thomas::RaviartThomasElementFamily;
49
50type EntityPoints<T> = [Vec<DynArray<T, 2>>; 4];
51type EntityWeights<T> = [Vec<DynArray<T, 3>>; 4];
52
53fn compute_derivative_count(nderivs: usize, cell_type: ReferenceCellType) -> usize {
55 match cell_type {
56 ReferenceCellType::Point => 0,
57 ReferenceCellType::Interval => nderivs + 1,
58 ReferenceCellType::Triangle => (nderivs + 1) * (nderivs + 2) / 2,
59 ReferenceCellType::Quadrilateral => (nderivs + 1) * (nderivs + 2) / 2,
60 ReferenceCellType::Tetrahedron => (nderivs + 1) * (nderivs + 2) * (nderivs + 3) / 6,
61 ReferenceCellType::Hexahedron => (nderivs + 1) * (nderivs + 2) * (nderivs + 3) / 6,
62 ReferenceCellType::Prism => (nderivs + 1) * (nderivs + 2) * (nderivs + 3) / 6,
63 ReferenceCellType::Pyramid => (nderivs + 1) * (nderivs + 2) * (nderivs + 3) / 6,
64 }
65}
66
67pub struct CiarletElement<T: RlstScalar, M: Map, TGeo: RlstScalar = <T as RlstScalar>::Real> {
69 family_name: String,
70 cell_type: ReferenceCellType,
71 degree: usize,
72 embedded_superdegree: usize,
73 value_shape: Vec<usize>,
74 value_size: usize,
75 continuity: Continuity,
76 dim: usize,
77 coefficients: DynArray<T, 3>,
78 entity_dofs: [Vec<Vec<usize>>; 4],
79 entity_closure_dofs: [Vec<Vec<usize>>; 4],
80 interpolation_points: EntityPoints<TGeo>,
81 interpolation_weights: EntityWeights<T>,
82 map: M,
83 dof_transformations: HashMap<(ReferenceCellType, Transformation), DofTransformation<T>>,
84}
85
86impl<T: RlstScalar, M: Map, TGeo: RlstScalar> Debug for CiarletElement<T, M, TGeo> {
87 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
88 f.debug_tuple("CiarletElement")
89 .field(&self.family_name)
90 .field(&self.cell_type)
91 .field(&self.degree)
92 .finish()
93 }
94}
95
96impl<T: RlstScalar, M: Map, TGeo: RlstScalar> CiarletElement<T, M, TGeo>
97where
98 DynArray<T, 2>: Inverse<Output = DynArray<T, 2>>,
99{
100 #[allow(clippy::too_many_arguments)]
108 pub fn create(
109 family_name: String,
110 cell_type: ReferenceCellType,
111 degree: usize,
112 value_shape: Vec<usize>,
113 polynomial_coeffs: DynArray<T, 3>,
114 interpolation_points: EntityPoints<TGeo>,
115 interpolation_weights: EntityWeights<T>,
116 continuity: Continuity,
117 embedded_superdegree: usize,
118 map: M,
119 ) -> Self {
120 let mut dim = 0;
121 let mut npts = 0;
122
123 for emats in &interpolation_weights {
124 for mat in emats {
125 dim += mat.shape()[0];
126 npts += mat.shape()[2];
127 }
128 }
129 let tdim = reference_cell::dim(cell_type);
130
131 let mut value_size = 1;
132 for i in &value_shape {
133 value_size *= *i;
134 }
135
136 for matrices in &interpolation_weights {
137 for mat in matrices {
138 if mat.shape()[1] != value_size {
139 panic!("Incompatible value size");
140 }
141 }
142 }
143
144 let new_pts = if continuity == Continuity::Discontinuous {
146 let mut new_pts: EntityPoints<TGeo> = [vec![], vec![], vec![], vec![]];
147 let mut all_pts = rlst_dynamic_array!(TGeo, [tdim, npts]);
148 for (i, pts_i) in interpolation_points.iter().take(tdim).enumerate() {
149 for _pts in pts_i {
150 new_pts[i].push(rlst_dynamic_array!(TGeo, [tdim, 0]));
151 }
152 }
153 let mut col = 0;
154 for pts_i in interpolation_points.iter() {
155 for pts in pts_i {
156 let ncols = pts.shape()[1];
157 all_pts
158 .r_mut()
159 .into_subview([0, col], [tdim, ncols])
160 .fill_from(pts);
161 col += ncols;
162 }
163 }
164 new_pts[tdim].push(all_pts);
165 new_pts
166 } else {
167 interpolation_points
168 };
169 let new_wts = if continuity == Continuity::Discontinuous {
170 let mut new_wts = [vec![], vec![], vec![], vec![]];
171 let mut pn = 0;
172 let mut dn = 0;
173 let mut all_mat = rlst_dynamic_array!(T, [dim, value_size, npts]);
174 for (i, mi) in interpolation_weights.iter().take(tdim).enumerate() {
175 for _mat in mi {
176 new_wts[i].push(rlst_dynamic_array!(T, [0, value_size, 0]));
177 }
178 }
179 for mi in interpolation_weights.iter() {
180 for mat in mi {
181 let dim0 = mat.shape()[0];
182 let dim2 = mat.shape()[2];
183 all_mat
184 .r_mut()
185 .into_subview([dn, 0, pn], [dim0, value_size, dim2])
186 .fill_from(mat);
187 dn += dim0;
188 pn += dim2;
189 }
190 }
191 new_wts[tdim].push(all_mat);
192 new_wts
193 } else {
194 interpolation_weights
195 };
196
197 let pdim = polynomial_count(cell_type, embedded_superdegree);
199 let mut d_matrix = rlst_dynamic_array!(T, [value_size, pdim, dim]);
200
201 let mut dof = 0;
202 for d in 0..4 {
203 for (e, pts) in new_pts[d].iter().enumerate() {
204 if pts.shape()[1] > 0 {
205 let mut table = rlst_dynamic_array!(T, [1, pdim, pts.shape()[1]]);
206 tabulate_legendre_polynomials(
207 cell_type,
208 pts,
209 embedded_superdegree,
210 0,
211 &mut table,
212 );
213 let mat = &new_wts[d][e];
214 for i in 0..mat.shape()[0] {
215 for l in 0..pdim {
216 for j in 0..value_size {
217 *d_matrix.get_mut([j, l, dof + i]).unwrap() = mat
219 .r()
220 .slice::<2>(0, i)
221 .slice(0, j)
222 .inner(&table.r().slice::<2>(0, 0).slice(0, l))
223 .unwrap();
224 }
225 }
226 }
227 dof += mat.shape()[0];
228 }
229 }
230 }
231
232 let mut dual_mat = rlst::rlst_dynamic_array!(T, [dim, dim]);
234
235 for i in 0..dim {
236 for j in 0..dim {
237 *dual_mat.get_mut([i, j]).unwrap() = (0..value_size)
238 .map(|k| {
239 (0..pdim)
240 .map(|l| {
241 *polynomial_coeffs.get([i, k, l]).unwrap()
242 * *d_matrix.get([k, l, j]).unwrap()
243 })
244 .sum::<T>()
245 })
246 .sum::<T>();
247 }
248 }
249
250 let inverse = dual_mat.inverse().unwrap();
251
252 let mut coefficients = rlst_dynamic_array!(T, [dim, value_size, pdim]);
253 for i in 0..dim {
254 for j in 0..value_size {
255 for k in 0..pdim {
256 *coefficients.get_mut([i, j, k]).unwrap() = inverse
258 .r()
259 .slice::<1>(0, i)
260 .inner(&polynomial_coeffs.r().slice::<2>(1, j).slice(1, k))
261 .unwrap();
262 }
263 }
264 }
265
266 let mut entity_dofs = [vec![], vec![], vec![], vec![]];
268 let mut dof = 0;
269 for i in 0..4 {
270 for wts in &new_wts[i] {
271 let dofs = (dof..dof + wts.shape()[0]).collect::<Vec<_>>();
272 entity_dofs[i].push(dofs);
273 dof += wts.shape()[0];
274 }
275 }
276 let connectivity = reference_cell::connectivity(cell_type);
277 let mut entity_closure_dofs = [vec![], vec![], vec![], vec![]];
278 for (edim, (ecdofs, connectivity_edim)) in
279 izip!(entity_closure_dofs.iter_mut(), &connectivity).enumerate()
280 {
281 for connectivity_edim_eindex in connectivity_edim {
282 let mut cdofs = vec![];
283 for (edim2, connectivity_edim_eindex_edim2) in
284 connectivity_edim_eindex.iter().take(edim + 1).enumerate()
285 {
286 for index in connectivity_edim_eindex_edim2 {
287 for i in &entity_dofs[edim2][*index] {
288 cdofs.push(*i)
289 }
290 }
291 }
292 ecdofs.push(cdofs);
293 }
294 }
295
296 let mut dof_transformations = HashMap::new();
298 for (entity, entity_id, transform, f) in match cell_type {
299 ReferenceCellType::Point => vec![],
300 ReferenceCellType::Interval => vec![],
301 ReferenceCellType::Triangle => vec![(
302 ReferenceCellType::Interval,
303 0,
304 Transformation::Reflection,
305 (|x| vec![x[1], x[0]]) as fn(&[TGeo]) -> Vec<TGeo>,
306 )],
307 ReferenceCellType::Quadrilateral => vec![(
308 ReferenceCellType::Interval,
309 0,
310 Transformation::Reflection,
311 (|x| vec![TGeo::one() - x[0], x[1]]) as fn(&[TGeo]) -> Vec<TGeo>,
312 )],
313 ReferenceCellType::Tetrahedron => vec![
314 (
315 ReferenceCellType::Interval,
316 0,
317 Transformation::Reflection,
318 (|x| vec![x[0], x[2], x[1]]) as fn(&[TGeo]) -> Vec<TGeo>,
319 ),
320 (
321 ReferenceCellType::Triangle,
322 0,
323 Transformation::Rotation,
324 (|x| vec![x[1], x[2], x[0]]) as fn(&[TGeo]) -> Vec<TGeo>,
325 ),
326 (
327 ReferenceCellType::Triangle,
328 0,
329 Transformation::Reflection,
330 (|x| vec![x[0], x[2], x[1]]) as fn(&[TGeo]) -> Vec<TGeo>,
331 ),
332 ],
333 ReferenceCellType::Hexahedron => vec![
334 (
335 ReferenceCellType::Interval,
336 0,
337 Transformation::Reflection,
338 (|x| vec![TGeo::one() - x[0], x[1], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
339 ),
340 (
341 ReferenceCellType::Quadrilateral,
342 0,
343 Transformation::Rotation,
344 (|x| vec![x[1], TGeo::one() - x[0], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
345 ),
346 (
347 ReferenceCellType::Quadrilateral,
348 0,
349 Transformation::Reflection,
350 (|x| vec![x[1], x[0], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
351 ),
352 ],
353 ReferenceCellType::Prism => vec![
354 (
355 ReferenceCellType::Interval,
356 0,
357 Transformation::Reflection,
358 (|x| vec![TGeo::one() - x[0], x[1], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
359 ),
360 (
361 ReferenceCellType::Triangle,
362 0,
363 Transformation::Rotation,
364 (|x| vec![x[1], TGeo::one() - x[1] - x[0], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
365 ),
366 (
367 ReferenceCellType::Triangle,
368 0,
369 Transformation::Reflection,
370 (|x| vec![x[1], x[0], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
371 ),
372 (
373 ReferenceCellType::Quadrilateral,
374 1,
375 Transformation::Rotation,
376 (|x| vec![x[2], TGeo::one() - x[1], x[0]]) as fn(&[TGeo]) -> Vec<TGeo>,
377 ),
378 (
379 ReferenceCellType::Quadrilateral,
380 1,
381 Transformation::Reflection,
382 (|x| vec![x[2], x[1], x[0]]) as fn(&[TGeo]) -> Vec<TGeo>,
383 ),
384 ],
385 ReferenceCellType::Pyramid => vec![
386 (
387 ReferenceCellType::Interval,
388 0,
389 Transformation::Reflection,
390 (|x| vec![TGeo::one() - x[0], x[1], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
391 ),
392 (
393 ReferenceCellType::Triangle,
394 1,
395 Transformation::Rotation,
396 (|x| vec![x[2], x[1], TGeo::one() - x[2] - x[0]]) as fn(&[TGeo]) -> Vec<TGeo>,
397 ),
398 (
399 ReferenceCellType::Triangle,
400 1,
401 Transformation::Reflection,
402 (|x| vec![x[2], x[1], x[0]]) as fn(&[TGeo]) -> Vec<TGeo>,
403 ),
404 (
405 ReferenceCellType::Quadrilateral,
406 0,
407 Transformation::Rotation,
408 (|x| vec![x[1], TGeo::one() - x[0], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
409 ),
410 (
411 ReferenceCellType::Quadrilateral,
412 0,
413 Transformation::Reflection,
414 (|x| vec![x[1], x[0], x[2]]) as fn(&[TGeo]) -> Vec<TGeo>,
415 ),
416 ],
417 } {
418 let edim = reference_cell::dim(entity);
419 let ref_pts = &new_pts[edim][entity_id];
420 let npts = ref_pts.shape()[1];
421
422 let finv = match transform {
423 Transformation::Reflection => {
424 (|x, f| f(x)) as fn(&[TGeo], fn(&[TGeo]) -> Vec<TGeo>) -> Vec<TGeo>
425 }
426 Transformation::Rotation => match entity {
427 ReferenceCellType::Interval => {
428 (|x, f| f(x)) as fn(&[TGeo], fn(&[TGeo]) -> Vec<TGeo>) -> Vec<TGeo>
429 }
430 ReferenceCellType::Triangle => {
431 (|x, f| f(&f(x))) as fn(&[TGeo], fn(&[TGeo]) -> Vec<TGeo>) -> Vec<TGeo>
432 }
433 ReferenceCellType::Quadrilateral => {
434 (|x, f| f(&f(&f(x)))) as fn(&[TGeo], fn(&[TGeo]) -> Vec<TGeo>) -> Vec<TGeo>
435 }
436 _ => panic!("Unsupported entity: {entity:?}"),
437 },
438 };
439
440 let mut pts = DynArray::<TGeo, 2>::from_shape(ref_pts.shape());
441 for p in 0..npts {
442 for (i, c) in finv(
443 &ref_pts.data().unwrap()[ref_pts.shape()[0] * p..ref_pts.shape()[0] * (p + 1)],
444 f,
445 )
446 .iter()
447 .enumerate()
448 {
449 *pts.get_mut([i, p]).unwrap() = *c
450 }
451 }
452
453 let wts = &new_wts[edim][entity_id];
454 let edofs = &entity_dofs[edim][entity_id];
455 let endofs = edofs.len();
456 let mut j = rlst_dynamic_array![TGeo, [npts, tdim, tdim]];
457 for t_in in 0..tdim {
458 for (t_out, (a, b)) in izip!(
459 f(&vec![TGeo::zero(); tdim]),
460 f(&{
461 let mut axis = vec![TGeo::zero(); tdim];
462 axis[t_in] = TGeo::one();
463 axis
464 })
465 )
466 .enumerate()
467 {
468 for p in 0..npts {
469 *j.get_mut([p, t_out, t_in]).unwrap() = b - a;
470 }
471 }
472 }
473 let jdet = vec![
475 match transform {
476 Transformation::Reflection => -TGeo::one(),
477 Transformation::Rotation => TGeo::one(),
478 };
479 npts
480 ];
481 let mut jinv = rlst_dynamic_array![TGeo, [npts, tdim, tdim]];
482 for t_in in 0..tdim {
483 for (t_out, (a, b)) in izip!(
484 finv(&vec![TGeo::zero(); tdim], f),
485 finv(
486 &{
487 let mut axis = vec![TGeo::zero(); tdim];
488 axis[t_in] = TGeo::one();
489 axis
490 },
491 f
492 )
493 )
494 .enumerate()
495 {
496 for p in 0..npts {
497 *jinv.get_mut([p, t_out, t_in]).unwrap() = TGeo::from(b - a).unwrap();
498 }
499 }
500 }
501
502 let mut table = DynArray::<T, 3>::from_shape(legendre_shape(
503 cell_type,
504 &pts,
505 embedded_superdegree,
506 0,
507 ));
508 tabulate_legendre_polynomials(cell_type, &pts, embedded_superdegree, 0, &mut table);
509
510 let mut data = rlst_dynamic_array!(T, [1, npts, endofs, value_size]);
511 for p in 0..npts {
512 for j in 0..value_size {
513 for (b, dof) in edofs.iter().enumerate() {
514 *data.get_mut([0, p, b, j]).unwrap() = coefficients
516 .r()
517 .slice::<2>(0, *dof)
518 .slice(0, j)
519 .inner(&table.r().slice::<2>(0, 0).slice(1, p))
520 .unwrap();
521 }
522 }
523 }
524
525 let mut pushed_data = rlst_dynamic_array!(T, [1, npts, endofs, value_size]);
526 map.push_forward(&data, 0, &j, &jdet, &jinv, &mut pushed_data);
527
528 let mut dof_transform = rlst_dynamic_array!(T, [edofs.len(), edofs.len()]);
529 for i in 0..edofs.len() {
530 for j in 0..edofs.len() {
531 *dof_transform.get_mut([i, j]).unwrap() = (0..value_size)
532 .map(|l| {
533 (0..npts)
534 .map(|m| {
535 *wts.get([j, l, m]).unwrap()
536 * *pushed_data.get([0, m, i, l]).unwrap()
537 })
538 .sum::<T>()
539 })
540 .sum::<T>();
541 }
542 }
543
544 let perm = math::prepare_matrix(&mut dof_transform);
545
546 let mut is_identity = true;
548 'outer: for j in 0..edofs.len() {
549 for i in 0..edofs.len() {
550 if (*dof_transform.get([i, j]).unwrap()
551 - if i == j { T::one() } else { T::zero() })
552 .abs()
553 > T::from(1e-8).unwrap().re()
554 {
555 is_identity = false;
556 break 'outer;
557 }
558 }
559 }
560
561 if is_identity {
562 let mut is_unpermuted = true;
563 for (i, p) in perm.iter().enumerate() {
564 if i != *p {
565 is_unpermuted = false;
566 break;
567 }
568 }
569 if is_unpermuted {
570 dof_transformations.insert((entity, transform), DofTransformation::Identity);
571 } else {
572 dof_transformations
573 .insert((entity, transform), DofTransformation::Permutation(perm));
574 }
575 } else {
576 dof_transformations.insert(
577 (entity, transform),
578 DofTransformation::Transformation(dof_transform, perm),
579 );
580 }
581 }
582 CiarletElement::<T, M, TGeo> {
583 family_name,
584 cell_type,
585 degree,
586 embedded_superdegree,
587 value_shape,
588 value_size,
589 continuity,
590 dim,
591 coefficients,
592 entity_dofs,
593 entity_closure_dofs,
594 interpolation_points: new_pts,
595 interpolation_weights: new_wts,
596 map,
597 dof_transformations,
598 }
599 }
600
601 pub fn degree(&self) -> usize {
603 self.degree
604 }
605 pub fn continuity(&self) -> Continuity {
607 self.continuity
608 }
609 pub fn interpolation_points(&self) -> &EntityPoints<TGeo> {
611 &self.interpolation_points
612 }
613 pub fn interpolation_weights(&self) -> &EntityWeights<T> {
615 &self.interpolation_weights
616 }
617}
618
619impl<T: RlstScalar, M: Map, TGeoInternal: RlstScalar> FiniteElement
620 for CiarletElement<T, M, TGeoInternal>
621{
622 type CellType = ReferenceCellType;
623 type T = T;
624
625 fn value_shape(&self) -> &[usize] {
626 &self.value_shape
627 }
628
629 fn value_size(&self) -> usize {
630 self.value_size
631 }
632
633 fn cell_type(&self) -> ReferenceCellType {
634 self.cell_type
635 }
636
637 fn dim(&self) -> usize {
638 self.dim
639 }
640
641 fn tabulate<
642 TGeo: RlstScalar,
643 Array2Impl: ValueArrayImpl<TGeo, 2>,
644 Array4MutImpl: MutableArrayImpl<T, 4>,
645 >(
646 &self,
647 points: &Array<Array2Impl, 2>,
648 nderivs: usize,
649 data: &mut Array<Array4MutImpl, 4>,
650 ) {
651 let mut table = DynArray::<T, 3>::from_shape(legendre_shape(
652 self.cell_type,
653 points,
654 self.embedded_superdegree,
655 nderivs,
656 ));
657 tabulate_legendre_polynomials(
658 self.cell_type,
659 points,
660 self.embedded_superdegree,
661 nderivs,
662 &mut table,
663 );
664
665 for d in 0..table.shape()[0] {
666 for p in 0..points.shape()[1] {
667 for j in 0..self.value_size {
668 for b in 0..self.dim {
669 *data.get_mut([d, p, b, j]).unwrap() = self
671 .coefficients
672 .r()
673 .slice::<2>(0, b)
674 .slice(0, j)
675 .inner(&table.r().slice::<2>(0, d).slice(1, p))
676 .unwrap();
677 }
678 }
679 }
680 }
681 }
682
683 fn tabulate_array_shape(&self, nderivs: usize, npoints: usize) -> [usize; 4] {
684 let deriv_count = compute_derivative_count(nderivs, self.cell_type());
685 let point_count = npoints;
686 let basis_count = self.dim();
687 let value_size = self.value_size();
688 [deriv_count, point_count, basis_count, value_size]
689 }
690
691 fn entity_dofs(&self, entity_dim: usize, entity_number: usize) -> Option<&[usize]> {
692 if entity_dim < 4 && entity_number < self.entity_dofs[entity_dim].len() {
693 Some(&self.entity_dofs[entity_dim][entity_number])
694 } else {
695 None
696 }
697 }
698
699 fn entity_closure_dofs(&self, entity_dim: usize, entity_number: usize) -> Option<&[usize]> {
700 if entity_dim < 4 && entity_number < self.entity_closure_dofs[entity_dim].len() {
701 Some(&self.entity_closure_dofs[entity_dim][entity_number])
702 } else {
703 None
704 }
705 }
706}
707
708impl<T: RlstScalar, M: Map, TGeoInternal: RlstScalar> MappedFiniteElement
709 for CiarletElement<T, M, TGeoInternal>
710{
711 type TransformationType = Transformation;
712
713 fn lagrange_superdegree(&self) -> usize {
714 self.embedded_superdegree
715 }
716
717 fn push_forward<
718 TGeo: RlstScalar,
719 Array3GeoImpl: ValueArrayImpl<TGeo, 3>,
720 Array4Impl: ValueArrayImpl<T, 4>,
721 Array4MutImpl: MutableArrayImpl<T, 4>,
722 >(
723 &self,
724 reference_values: &Array<Array4Impl, 4>,
725 nderivs: usize,
726 jacobians: &Array<Array3GeoImpl, 3>,
727 jacobian_determinants: &[TGeo],
728 inverse_jacobians: &Array<Array3GeoImpl, 3>,
729 physical_values: &mut Array<Array4MutImpl, 4>,
730 ) {
731 self.map.push_forward(
732 reference_values,
733 nderivs,
734 jacobians,
735 jacobian_determinants,
736 inverse_jacobians,
737 physical_values,
738 )
739 }
740
741 fn pull_back<
742 TGeo: RlstScalar,
743 Array3GeoImpl: ValueArrayImpl<TGeo, 3>,
744 Array4Impl: ValueArrayImpl<T, 4>,
745 Array4MutImpl: MutableArrayImpl<T, 4>,
746 >(
747 &self,
748 physical_values: &Array<Array4Impl, 4>,
749 nderivs: usize,
750 jacobians: &Array<Array3GeoImpl, 3>,
751 jacobian_determinants: &[TGeo],
752 inverse_jacobians: &Array<Array3GeoImpl, 3>,
753 reference_values: &mut Array<Array4MutImpl, 4>,
754 ) {
755 self.map.pull_back(
756 physical_values,
757 nderivs,
758 jacobians,
759 jacobian_determinants,
760 inverse_jacobians,
761 reference_values,
762 )
763 }
764
765 fn physical_value_shape(&self, gdim: usize) -> Vec<usize> {
766 self.map.physical_value_shape(gdim)
767 }
768
769 fn dof_transformation(
770 &self,
771 entity: ReferenceCellType,
772 transformation: Transformation,
773 ) -> Option<&DofTransformation<T>> {
774 self.dof_transformations.get(&(entity, transformation))
775 }
776
777 fn apply_dof_permutations<Type>(&self, data: &mut [Type], cell_orientation: i32) {
778 debug_assert_eq!(data.len() % self.dim, 0);
779 let block_size = data.len() / self.dim;
780 let tdim = reference_cell::dim(self.cell_type);
781 let mut n = 0;
782 if tdim > 1
783 && let Some(perm) = match self
784 .dof_transformations
785 .get(&(ReferenceCellType::Interval, Transformation::Reflection))
786 {
787 Some(DofTransformation::Permutation(p)) => Some(p),
788 Some(DofTransformation::Transformation(_, p)) => Some(p),
789 _ => None,
790 }
791 {
792 for dofs in &self.entity_dofs[1] {
793 #[cfg(debug_assertions)]
794 for (i, j) in izip!(&dofs[..dofs.len() - 1], &dofs[1..]) {
795 assert_eq!(i + 1, *j);
796 }
797 if (cell_orientation >> n) & 1 == 1 {
798 math::apply_permutation(
799 perm,
800 &mut data[block_size * dofs[0]..block_size * (dofs[dofs.len() - 1] + 1)],
801 )
802 }
803 n += 1
804 }
805 }
806 if tdim > 2 {
807 for (ftype, dofs) in izip!(
808 &reference_cell::entity_types(self.cell_type)[2],
809 &self.entity_dofs[2]
810 ) {
811 #[cfg(debug_assertions)]
812 for (i, j) in izip!(&dofs[..dofs.len() - 1], &dofs[1..]) {
813 assert_eq!(i + 1, *j);
814 }
815 if let Some(perm) = match self
816 .dof_transformations
817 .get(&(*ftype, Transformation::Rotation))
818 {
819 Some(DofTransformation::Permutation(p)) => Some(p),
820 Some(DofTransformation::Transformation(_, p)) => Some(p),
821 _ => None,
822 } {
823 for _ in 0..(cell_orientation >> n) & 3 {
824 math::apply_permutation(
825 perm,
826 &mut data
827 [block_size * dofs[0]..block_size * (dofs[dofs.len() - 1] + 1)],
828 )
829 }
830 }
831 n += 2;
832 if let Some(perm) = match self
833 .dof_transformations
834 .get(&(*ftype, Transformation::Reflection))
835 {
836 Some(DofTransformation::Permutation(p)) => Some(p),
837 Some(DofTransformation::Transformation(_, p)) => Some(p),
838 _ => None,
839 } && (cell_orientation >> n) & 1 == 1
840 {
841 math::apply_permutation(
842 perm,
843 &mut data[block_size * dofs[0]..block_size * (dofs[dofs.len() - 1] + 1)],
844 )
845 }
846 n += 1;
847 }
848 }
849 }
850
851 fn apply_dof_transformations(&self, data: &mut [T], cell_orientation: i32) {
852 debug_assert_eq!(data.len() % self.dim, 0);
853 let block_size = data.len() / self.dim;
854 let tdim = reference_cell::dim(self.cell_type);
855 let mut n = 0;
856 if tdim > 1
857 && let Some(mat) = match self
858 .dof_transformations
859 .get(&(ReferenceCellType::Interval, Transformation::Reflection))
860 {
861 Some(DofTransformation::Transformation(m, _)) => Some(m),
862 _ => None,
863 }
864 {
865 for dofs in &self.entity_dofs[1] {
866 #[cfg(debug_assertions)]
867 for (i, j) in izip!(&dofs[..dofs.len() - 1], &dofs[1..]) {
868 assert_eq!(i + 1, *j);
869 }
870 if (cell_orientation >> n) & 1 == 1 {
871 math::apply_matrix(
872 mat,
873 &mut data[block_size * dofs[0]..block_size * (dofs[dofs.len() - 1] + 1)],
874 )
875 }
876 n += 1
877 }
878 }
879 if tdim > 2 {
880 for (ftype, dofs) in izip!(
881 &reference_cell::entity_types(self.cell_type)[2],
882 &self.entity_dofs[2]
883 ) {
884 #[cfg(debug_assertions)]
885 for (i, j) in izip!(&dofs[..dofs.len() - 1], &dofs[1..]) {
886 assert_eq!(i + 1, *j);
887 }
888 if let Some(mat) = match self
889 .dof_transformations
890 .get(&(*ftype, Transformation::Rotation))
891 {
892 Some(DofTransformation::Transformation(m, _)) => Some(m),
893 _ => None,
894 } {
895 for _ in 0..(cell_orientation >> n) & 3 {
896 math::apply_matrix(
897 mat,
898 &mut data
899 [block_size * dofs[0]..block_size * (dofs[dofs.len() - 1] + 1)],
900 )
901 }
902 }
903 n += 2;
904 if let Some(mat) = match self
905 .dof_transformations
906 .get(&(*ftype, Transformation::Reflection))
907 {
908 Some(DofTransformation::Transformation(m, _)) => Some(m),
909 _ => None,
910 } && (cell_orientation >> n) & 1 == 1
911 {
912 math::apply_matrix(
913 mat,
914 &mut data[block_size * dofs[0]..block_size * (dofs[dofs.len() - 1] + 1)],
915 )
916 }
917 n += 1;
918 }
919 }
920 }
921}
922
923#[cfg(test)]
924mod test {
925 use super::*;
926 use approx::*;
927 use paste::paste;
928 use rlst::rlst_dynamic_array;
929
930 fn check_dofs(e: impl FiniteElement<CellType = ReferenceCellType>) {
931 let mut ndofs = 0;
932 for (dim, entity_count) in match e.cell_type() {
933 ReferenceCellType::Point => vec![1],
934 ReferenceCellType::Interval => vec![2, 1],
935 ReferenceCellType::Triangle => vec![3, 3, 1],
936 ReferenceCellType::Quadrilateral => vec![4, 4, 1],
937 ReferenceCellType::Tetrahedron => vec![4, 6, 4, 1],
938 ReferenceCellType::Hexahedron => vec![8, 12, 6, 1],
939 ReferenceCellType::Prism => vec![6, 9, 5, 1],
940 ReferenceCellType::Pyramid => vec![5, 8, 5, 1],
941 }
942 .iter()
943 .enumerate()
944 {
945 for entity in 0..*entity_count {
946 ndofs += e.entity_dofs(dim, entity).unwrap().len();
947 }
948 }
949 assert_eq!(ndofs, e.dim());
950 }
951
952 #[test]
953 fn test_lagrange_1() {
954 let e = lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 1, Continuity::Standard);
955 assert_eq!(e.value_size(), 1);
956 }
957
958 #[test]
959 fn test_lagrange_0_interval() {
960 let e =
961 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 0, Continuity::Discontinuous);
962 assert_eq!(e.value_size(), 1);
963 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
964 let mut points = rlst_dynamic_array!(f64, [1, 4]);
965 *points.get_mut([0, 0]).unwrap() = 0.0;
966 *points.get_mut([0, 1]).unwrap() = 0.2;
967 *points.get_mut([0, 2]).unwrap() = 0.4;
968 *points.get_mut([0, 3]).unwrap() = 1.0;
969 e.tabulate(&points, 0, &mut data);
970
971 for pt in 0..4 {
972 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
973 }
974 check_dofs(e);
975 }
976
977 #[test]
978 fn test_lagrange_1_interval() {
979 let e = lagrange::create::<f64, f64>(ReferenceCellType::Interval, 1, Continuity::Standard);
980 assert_eq!(e.value_size(), 1);
981 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 4));
982 let mut points = rlst_dynamic_array!(f64, [1, 4]);
983 *points.get_mut([0, 0]).unwrap() = 0.0;
984 *points.get_mut([0, 1]).unwrap() = 0.2;
985 *points.get_mut([0, 2]).unwrap() = 0.4;
986 *points.get_mut([0, 3]).unwrap() = 1.0;
987 e.tabulate(&points, 0, &mut data);
988
989 for pt in 0..4 {
990 let x = *points.get([0, pt]).unwrap();
991 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0 - x);
992 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x);
993 }
994 check_dofs(e);
995 }
996
997 #[test]
998 fn test_lagrange_0_triangle() {
999 let e =
1000 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 0, Continuity::Discontinuous);
1001 assert_eq!(e.value_size(), 1);
1002 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1003
1004 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1005 *points.get_mut([0, 0]).unwrap() = 0.0;
1006 *points.get_mut([1, 0]).unwrap() = 0.0;
1007 *points.get_mut([0, 1]).unwrap() = 1.0;
1008 *points.get_mut([1, 1]).unwrap() = 0.0;
1009 *points.get_mut([0, 2]).unwrap() = 0.0;
1010 *points.get_mut([1, 2]).unwrap() = 1.0;
1011 *points.get_mut([0, 3]).unwrap() = 0.5;
1012 *points.get_mut([1, 3]).unwrap() = 0.0;
1013 *points.get_mut([0, 4]).unwrap() = 0.0;
1014 *points.get_mut([1, 4]).unwrap() = 0.5;
1015 *points.get_mut([0, 5]).unwrap() = 0.5;
1016 *points.get_mut([1, 5]).unwrap() = 0.5;
1017
1018 e.tabulate(&points, 0, &mut data);
1019
1020 for pt in 0..6 {
1021 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
1022 }
1023 check_dofs(e);
1024 }
1025
1026 #[test]
1027 fn test_lagrange_1_triangle() {
1028 let e = lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 1, Continuity::Standard);
1029 assert_eq!(e.value_size(), 1);
1030 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1031 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1032 *points.get_mut([0, 0]).unwrap() = 0.0;
1033 *points.get_mut([1, 0]).unwrap() = 0.0;
1034 *points.get_mut([0, 1]).unwrap() = 1.0;
1035 *points.get_mut([1, 1]).unwrap() = 0.0;
1036 *points.get_mut([0, 2]).unwrap() = 0.0;
1037 *points.get_mut([1, 2]).unwrap() = 1.0;
1038 *points.get_mut([0, 3]).unwrap() = 0.5;
1039 *points.get_mut([1, 3]).unwrap() = 0.0;
1040 *points.get_mut([0, 4]).unwrap() = 0.0;
1041 *points.get_mut([1, 4]).unwrap() = 0.5;
1042 *points.get_mut([0, 5]).unwrap() = 0.5;
1043 *points.get_mut([1, 5]).unwrap() = 0.5;
1044 e.tabulate(&points, 0, &mut data);
1045
1046 for pt in 0..6 {
1047 let x = *points.get([0, pt]).unwrap();
1048 let y = *points.get([1, pt]).unwrap();
1049 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0 - x - y);
1050 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x);
1051 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), y);
1052 }
1053 check_dofs(e);
1054 }
1055
1056 #[test]
1057 fn test_lagrange_0_quadrilateral() {
1058 let e = lagrange::create::<f64, f64>(
1059 ReferenceCellType::Quadrilateral,
1060 0,
1061 Continuity::Discontinuous,
1062 );
1063 assert_eq!(e.value_size(), 1);
1064 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1065 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1066 *points.get_mut([0, 0]).unwrap() = 0.0;
1067 *points.get_mut([1, 0]).unwrap() = 0.0;
1068 *points.get_mut([0, 1]).unwrap() = 1.0;
1069 *points.get_mut([1, 1]).unwrap() = 0.0;
1070 *points.get_mut([0, 2]).unwrap() = 0.0;
1071 *points.get_mut([1, 2]).unwrap() = 1.0;
1072 *points.get_mut([0, 3]).unwrap() = 0.5;
1073 *points.get_mut([1, 3]).unwrap() = 0.0;
1074 *points.get_mut([0, 4]).unwrap() = 0.0;
1075 *points.get_mut([1, 4]).unwrap() = 0.5;
1076 *points.get_mut([0, 5]).unwrap() = 0.5;
1077 *points.get_mut([1, 5]).unwrap() = 0.5;
1078 e.tabulate(&points, 0, &mut data);
1079
1080 for pt in 0..6 {
1081 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
1082 }
1083 check_dofs(e);
1084 }
1085
1086 #[test]
1087 fn test_lagrange_1_quadrilateral() {
1088 let e =
1089 lagrange::create::<f64, f64>(ReferenceCellType::Quadrilateral, 1, Continuity::Standard);
1090 assert_eq!(e.value_size(), 1);
1091 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1092 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1093 *points.get_mut([0, 0]).unwrap() = 0.0;
1094 *points.get_mut([1, 0]).unwrap() = 0.0;
1095 *points.get_mut([0, 1]).unwrap() = 1.0;
1096 *points.get_mut([1, 1]).unwrap() = 0.0;
1097 *points.get_mut([0, 2]).unwrap() = 0.0;
1098 *points.get_mut([1, 2]).unwrap() = 1.0;
1099 *points.get_mut([0, 3]).unwrap() = 1.0;
1100 *points.get_mut([1, 3]).unwrap() = 1.0;
1101 *points.get_mut([0, 4]).unwrap() = 0.25;
1102 *points.get_mut([1, 4]).unwrap() = 0.5;
1103 *points.get_mut([0, 5]).unwrap() = 0.3;
1104 *points.get_mut([1, 5]).unwrap() = 0.2;
1105
1106 e.tabulate(&points, 0, &mut data);
1107
1108 for pt in 0..6 {
1109 let x = *points.get([0, pt]).unwrap();
1110 let y = *points.get([1, pt]).unwrap();
1111 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), (1.0 - x) * (1.0 - y));
1112 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x * (1.0 - y));
1113 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), (1.0 - x) * y);
1114 assert_relative_eq!(*data.get([0, pt, 3, 0]).unwrap(), x * y);
1115 }
1116 check_dofs(e);
1117 }
1118
1119 #[test]
1120 fn test_lagrange_2_quadrilateral() {
1121 let e =
1122 lagrange::create::<f64, f64>(ReferenceCellType::Quadrilateral, 2, Continuity::Standard);
1123 assert_eq!(e.value_size(), 1);
1124 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1125 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1126 *points.get_mut([0, 0]).unwrap() = 0.0;
1127 *points.get_mut([1, 0]).unwrap() = 0.0;
1128 *points.get_mut([0, 1]).unwrap() = 1.0;
1129 *points.get_mut([1, 1]).unwrap() = 0.0;
1130 *points.get_mut([0, 2]).unwrap() = 0.0;
1131 *points.get_mut([1, 2]).unwrap() = 1.0;
1132 *points.get_mut([0, 3]).unwrap() = 1.0;
1133 *points.get_mut([1, 3]).unwrap() = 1.0;
1134 *points.get_mut([0, 4]).unwrap() = 0.25;
1135 *points.get_mut([1, 4]).unwrap() = 0.5;
1136 *points.get_mut([0, 5]).unwrap() = 0.3;
1137 *points.get_mut([1, 5]).unwrap() = 0.2;
1138
1139 e.tabulate(&points, 0, &mut data);
1140
1141 for pt in 0..6 {
1142 let x = *points.get([0, pt]).unwrap();
1143 let y = *points.get([1, pt]).unwrap();
1144 assert_relative_eq!(
1145 *data.get([0, pt, 0, 0]).unwrap(),
1146 (1.0 - x) * (1.0 - 2.0 * x) * (1.0 - y) * (1.0 - 2.0 * y),
1147 epsilon = 1e-14
1148 );
1149 assert_relative_eq!(
1150 *data.get([0, pt, 1, 0]).unwrap(),
1151 x * (2.0 * x - 1.0) * (1.0 - y) * (1.0 - 2.0 * y),
1152 epsilon = 1e-14
1153 );
1154 assert_relative_eq!(
1155 *data.get([0, pt, 2, 0]).unwrap(),
1156 (1.0 - x) * (1.0 - 2.0 * x) * y * (2.0 * y - 1.0),
1157 epsilon = 1e-14
1158 );
1159 assert_relative_eq!(
1160 *data.get([0, pt, 3, 0]).unwrap(),
1161 x * (2.0 * x - 1.0) * y * (2.0 * y - 1.0),
1162 epsilon = 1e-14
1163 );
1164 assert_relative_eq!(
1165 *data.get([0, pt, 4, 0]).unwrap(),
1166 4.0 * x * (1.0 - x) * (1.0 - y) * (1.0 - 2.0 * y),
1167 epsilon = 1e-14
1168 );
1169 assert_relative_eq!(
1170 *data.get([0, pt, 5, 0]).unwrap(),
1171 (1.0 - x) * (1.0 - 2.0 * x) * 4.0 * y * (1.0 - y),
1172 epsilon = 1e-14
1173 );
1174 assert_relative_eq!(
1175 *data.get([0, pt, 6, 0]).unwrap(),
1176 x * (2.0 * x - 1.0) * 4.0 * y * (1.0 - y),
1177 epsilon = 1e-14
1178 );
1179 assert_relative_eq!(
1180 *data.get([0, pt, 7, 0]).unwrap(),
1181 4.0 * x * (1.0 - x) * y * (2.0 * y - 1.0),
1182 epsilon = 1e-14
1183 );
1184 assert_relative_eq!(
1185 *data.get([0, pt, 8, 0]).unwrap(),
1186 4.0 * x * (1.0 - x) * 4.0 * y * (1.0 - y),
1187 epsilon = 1e-14
1188 );
1189 }
1190 check_dofs(e);
1191 }
1192
1193 #[test]
1194 fn test_lagrange_0_tetrahedron() {
1195 let e = lagrange::create::<f64, f64>(
1196 ReferenceCellType::Tetrahedron,
1197 0,
1198 Continuity::Discontinuous,
1199 );
1200 assert_eq!(e.value_size(), 1);
1201 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1202 let mut points = rlst_dynamic_array!(f64, [3, 6]);
1203 *points.get_mut([0, 0]).unwrap() = 0.0;
1204 *points.get_mut([1, 0]).unwrap() = 0.0;
1205 *points.get_mut([2, 0]).unwrap() = 0.0;
1206 *points.get_mut([0, 1]).unwrap() = 1.0;
1207 *points.get_mut([1, 1]).unwrap() = 0.0;
1208 *points.get_mut([2, 1]).unwrap() = 0.0;
1209 *points.get_mut([0, 2]).unwrap() = 0.0;
1210 *points.get_mut([1, 2]).unwrap() = 1.0;
1211 *points.get_mut([2, 2]).unwrap() = 0.0;
1212 *points.get_mut([0, 3]).unwrap() = 0.5;
1213 *points.get_mut([1, 3]).unwrap() = 0.0;
1214 *points.get_mut([2, 3]).unwrap() = 0.5;
1215 *points.get_mut([0, 4]).unwrap() = 0.0;
1216 *points.get_mut([1, 4]).unwrap() = 0.5;
1217 *points.get_mut([2, 4]).unwrap() = 0.5;
1218 *points.get_mut([0, 5]).unwrap() = 0.5;
1219 *points.get_mut([1, 5]).unwrap() = 0.2;
1220 *points.get_mut([2, 5]).unwrap() = 0.3;
1221 e.tabulate(&points, 0, &mut data);
1222
1223 for pt in 0..6 {
1224 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
1225 }
1226 check_dofs(e);
1227 }
1228
1229 #[test]
1230 fn test_lagrange_1_tetrahedron() {
1231 let e =
1232 lagrange::create::<f64, f64>(ReferenceCellType::Tetrahedron, 1, Continuity::Standard);
1233 assert_eq!(e.value_size(), 1);
1234 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1235 let mut points = rlst_dynamic_array!(f64, [3, 6]);
1236 *points.get_mut([0, 0]).unwrap() = 0.0;
1237 *points.get_mut([1, 0]).unwrap() = 0.0;
1238 *points.get_mut([2, 0]).unwrap() = 0.0;
1239 *points.get_mut([0, 1]).unwrap() = 1.0;
1240 *points.get_mut([1, 1]).unwrap() = 0.0;
1241 *points.get_mut([2, 1]).unwrap() = 0.0;
1242 *points.get_mut([0, 2]).unwrap() = 0.0;
1243 *points.get_mut([1, 2]).unwrap() = 0.8;
1244 *points.get_mut([2, 2]).unwrap() = 0.2;
1245 *points.get_mut([0, 3]).unwrap() = 0.0;
1246 *points.get_mut([1, 3]).unwrap() = 0.0;
1247 *points.get_mut([2, 3]).unwrap() = 0.8;
1248 *points.get_mut([0, 4]).unwrap() = 0.25;
1249 *points.get_mut([1, 4]).unwrap() = 0.5;
1250 *points.get_mut([2, 4]).unwrap() = 0.1;
1251 *points.get_mut([0, 5]).unwrap() = 0.2;
1252 *points.get_mut([1, 5]).unwrap() = 0.1;
1253 *points.get_mut([2, 5]).unwrap() = 0.15;
1254
1255 e.tabulate(&points, 0, &mut data);
1256
1257 for pt in 0..6 {
1258 let x = *points.get([0, pt]).unwrap();
1259 let y = *points.get([1, pt]).unwrap();
1260 let z = *points.get([2, pt]).unwrap();
1261 assert_relative_eq!(
1262 *data.get([0, pt, 0, 0]).unwrap(),
1263 1.0 - x - y - z,
1264 epsilon = 1e-14
1265 );
1266 assert_relative_eq!(*data.get([0, pt, 1, 0]).unwrap(), x, epsilon = 1e-14);
1267 assert_relative_eq!(*data.get([0, pt, 2, 0]).unwrap(), y, epsilon = 1e-14);
1268 assert_relative_eq!(*data.get([0, pt, 3, 0]).unwrap(), z, epsilon = 1e-14);
1269 }
1270 check_dofs(e);
1271 }
1272
1273 #[test]
1274 fn test_lagrange_0_hexahedron() {
1275 let e = lagrange::create::<f64, f64>(
1276 ReferenceCellType::Hexahedron,
1277 0,
1278 Continuity::Discontinuous,
1279 );
1280 assert_eq!(e.value_size(), 1);
1281 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1282 let mut points = rlst_dynamic_array!(f64, [3, 6]);
1283 *points.get_mut([0, 0]).unwrap() = 0.0;
1284 *points.get_mut([1, 0]).unwrap() = 0.0;
1285 *points.get_mut([2, 0]).unwrap() = 0.0;
1286 *points.get_mut([0, 1]).unwrap() = 1.0;
1287 *points.get_mut([1, 1]).unwrap() = 0.0;
1288 *points.get_mut([2, 1]).unwrap() = 0.0;
1289 *points.get_mut([0, 2]).unwrap() = 0.0;
1290 *points.get_mut([1, 2]).unwrap() = 1.0;
1291 *points.get_mut([2, 2]).unwrap() = 0.0;
1292 *points.get_mut([0, 3]).unwrap() = 0.5;
1293 *points.get_mut([1, 3]).unwrap() = 0.0;
1294 *points.get_mut([2, 3]).unwrap() = 0.5;
1295 *points.get_mut([0, 4]).unwrap() = 0.0;
1296 *points.get_mut([1, 4]).unwrap() = 0.5;
1297 *points.get_mut([2, 4]).unwrap() = 0.5;
1298 *points.get_mut([0, 5]).unwrap() = 0.5;
1299 *points.get_mut([1, 5]).unwrap() = 0.5;
1300 *points.get_mut([2, 5]).unwrap() = 0.5;
1301 e.tabulate(&points, 0, &mut data);
1302
1303 for pt in 0..6 {
1304 assert_relative_eq!(*data.get([0, pt, 0, 0]).unwrap(), 1.0);
1305 }
1306 check_dofs(e);
1307 }
1308
1309 #[test]
1310 fn test_lagrange_1_hexahedron() {
1311 let e =
1312 lagrange::create::<f64, f64>(ReferenceCellType::Hexahedron, 1, Continuity::Standard);
1313 assert_eq!(e.value_size(), 1);
1314 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1315 let mut points = rlst_dynamic_array!(f64, [3, 6]);
1316 *points.get_mut([0, 0]).unwrap() = 0.0;
1317 *points.get_mut([1, 0]).unwrap() = 0.0;
1318 *points.get_mut([2, 0]).unwrap() = 0.0;
1319 *points.get_mut([0, 1]).unwrap() = 1.0;
1320 *points.get_mut([1, 1]).unwrap() = 0.0;
1321 *points.get_mut([2, 1]).unwrap() = 0.0;
1322 *points.get_mut([0, 2]).unwrap() = 0.0;
1323 *points.get_mut([1, 2]).unwrap() = 1.0;
1324 *points.get_mut([2, 2]).unwrap() = 1.0;
1325 *points.get_mut([0, 3]).unwrap() = 1.0;
1326 *points.get_mut([1, 3]).unwrap() = 1.0;
1327 *points.get_mut([2, 3]).unwrap() = 1.0;
1328 *points.get_mut([0, 4]).unwrap() = 0.25;
1329 *points.get_mut([1, 4]).unwrap() = 0.5;
1330 *points.get_mut([2, 4]).unwrap() = 0.1;
1331 *points.get_mut([0, 5]).unwrap() = 0.3;
1332 *points.get_mut([1, 5]).unwrap() = 0.2;
1333 *points.get_mut([2, 5]).unwrap() = 0.4;
1334
1335 e.tabulate(&points, 0, &mut data);
1336
1337 for pt in 0..6 {
1338 let x = *points.get([0, pt]).unwrap();
1339 let y = *points.get([1, pt]).unwrap();
1340 let z = *points.get([2, pt]).unwrap();
1341 assert_relative_eq!(
1342 *data.get([0, pt, 0, 0]).unwrap(),
1343 (1.0 - x) * (1.0 - y) * (1.0 - z),
1344 epsilon = 1e-14
1345 );
1346 assert_relative_eq!(
1347 *data.get([0, pt, 1, 0]).unwrap(),
1348 x * (1.0 - y) * (1.0 - z),
1349 epsilon = 1e-14
1350 );
1351 assert_relative_eq!(
1352 *data.get([0, pt, 2, 0]).unwrap(),
1353 (1.0 - x) * y * (1.0 - z),
1354 epsilon = 1e-14
1355 );
1356 assert_relative_eq!(
1357 *data.get([0, pt, 3, 0]).unwrap(),
1358 x * y * (1.0 - z),
1359 epsilon = 1e-14
1360 );
1361 assert_relative_eq!(
1362 *data.get([0, pt, 4, 0]).unwrap(),
1363 (1.0 - x) * (1.0 - y) * z,
1364 epsilon = 1e-14
1365 );
1366 assert_relative_eq!(
1367 *data.get([0, pt, 5, 0]).unwrap(),
1368 x * (1.0 - y) * z,
1369 epsilon = 1e-14
1370 );
1371 assert_relative_eq!(
1372 *data.get([0, pt, 6, 0]).unwrap(),
1373 (1.0 - x) * y * z,
1374 epsilon = 1e-14
1375 );
1376 assert_relative_eq!(
1377 *data.get([0, pt, 7, 0]).unwrap(),
1378 x * y * z,
1379 epsilon = 1e-14
1380 );
1381 }
1382 check_dofs(e);
1383 }
1384
1385 #[test]
1386 fn test_lagrange_higher_degree_triangle() {
1387 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 2, Continuity::Standard);
1388 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 3, Continuity::Standard);
1389 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 4, Continuity::Standard);
1390 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 5, Continuity::Standard);
1391
1392 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 2, Continuity::Discontinuous);
1393 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 3, Continuity::Discontinuous);
1394 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 4, Continuity::Discontinuous);
1395 lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 5, Continuity::Discontinuous);
1396 }
1397
1398 #[test]
1399 fn test_lagrange_higher_degree_interval() {
1400 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 2, Continuity::Standard);
1401 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 3, Continuity::Standard);
1402 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 4, Continuity::Standard);
1403 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 5, Continuity::Standard);
1404
1405 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 2, Continuity::Discontinuous);
1406 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 3, Continuity::Discontinuous);
1407 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 4, Continuity::Discontinuous);
1408 lagrange::create::<f64, f64>(ReferenceCellType::Interval, 5, Continuity::Discontinuous);
1409 }
1410
1411 #[test]
1412 fn test_lagrange_higher_degree_quadrilateral() {
1413 lagrange::create::<f64, f64>(ReferenceCellType::Quadrilateral, 2, Continuity::Standard);
1414 lagrange::create::<f64, f64>(ReferenceCellType::Quadrilateral, 3, Continuity::Standard);
1415 lagrange::create::<f64, f64>(ReferenceCellType::Quadrilateral, 4, Continuity::Standard);
1416 lagrange::create::<f64, f64>(ReferenceCellType::Quadrilateral, 5, Continuity::Standard);
1417
1418 lagrange::create::<f64, f64>(
1419 ReferenceCellType::Quadrilateral,
1420 2,
1421 Continuity::Discontinuous,
1422 );
1423 lagrange::create::<f64, f64>(
1424 ReferenceCellType::Quadrilateral,
1425 3,
1426 Continuity::Discontinuous,
1427 );
1428 lagrange::create::<f64, f64>(
1429 ReferenceCellType::Quadrilateral,
1430 4,
1431 Continuity::Discontinuous,
1432 );
1433 lagrange::create::<f64, f64>(
1434 ReferenceCellType::Quadrilateral,
1435 5,
1436 Continuity::Discontinuous,
1437 );
1438 }
1439
1440 #[test]
1441 fn test_raviart_thomas_1_triangle() {
1442 let e = raviart_thomas::create::<f64, f64>(
1443 ReferenceCellType::Triangle,
1444 1,
1445 Continuity::Standard,
1446 );
1447 assert_eq!(e.value_size(), 2);
1448 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1449 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1450 *points.get_mut([0, 0]).unwrap() = 0.0;
1451 *points.get_mut([1, 0]).unwrap() = 0.0;
1452 *points.get_mut([0, 1]).unwrap() = 1.0;
1453 *points.get_mut([1, 1]).unwrap() = 0.0;
1454 *points.get_mut([0, 2]).unwrap() = 0.0;
1455 *points.get_mut([1, 2]).unwrap() = 1.0;
1456 *points.get_mut([0, 3]).unwrap() = 0.5;
1457 *points.get_mut([1, 3]).unwrap() = 0.0;
1458 *points.get_mut([0, 4]).unwrap() = 0.0;
1459 *points.get_mut([1, 4]).unwrap() = 0.5;
1460 *points.get_mut([0, 5]).unwrap() = 0.5;
1461 *points.get_mut([1, 5]).unwrap() = 0.5;
1462 e.tabulate(&points, 0, &mut data);
1463
1464 for pt in 0..6 {
1465 let x = *points.get([0, pt]).unwrap();
1466 let y = *points.get([1, pt]).unwrap();
1467 for (i, basis_f) in [[-x, -y], [x - 1.0, y], [-x, 1.0 - y]].iter().enumerate() {
1468 for (d, value) in basis_f.iter().enumerate() {
1469 assert_relative_eq!(*data.get([0, pt, i, d]).unwrap(), value, epsilon = 1e-14);
1470 }
1471 }
1472 }
1473 check_dofs(e);
1474 }
1475
1476 #[test]
1477 fn test_raviart_thomas_2_triangle() {
1478 let e = raviart_thomas::create::<f64, f64>(
1479 ReferenceCellType::Triangle,
1480 2,
1481 Continuity::Standard,
1482 );
1483 assert_eq!(e.value_size(), 2);
1484 check_dofs(e);
1485 }
1486
1487 #[test]
1488 fn test_raviart_thomas_3_triangle() {
1489 let e = raviart_thomas::create::<f64, f64>(
1490 ReferenceCellType::Triangle,
1491 3,
1492 Continuity::Standard,
1493 );
1494 assert_eq!(e.value_size(), 2);
1495 check_dofs(e);
1496 }
1497
1498 #[test]
1499 fn test_raviart_thomas_1_quadrilateral() {
1500 let e = raviart_thomas::create::<f64, f64>(
1501 ReferenceCellType::Quadrilateral,
1502 1,
1503 Continuity::Standard,
1504 );
1505 assert_eq!(e.value_size(), 2);
1506 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1507 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1508 *points.get_mut([0, 0]).unwrap() = 0.0;
1509 *points.get_mut([1, 0]).unwrap() = 0.0;
1510 *points.get_mut([0, 1]).unwrap() = 1.0;
1511 *points.get_mut([1, 1]).unwrap() = 0.0;
1512 *points.get_mut([0, 2]).unwrap() = 0.0;
1513 *points.get_mut([1, 2]).unwrap() = 1.0;
1514 *points.get_mut([0, 3]).unwrap() = 0.5;
1515 *points.get_mut([1, 3]).unwrap() = 0.0;
1516 *points.get_mut([0, 4]).unwrap() = 1.0;
1517 *points.get_mut([1, 4]).unwrap() = 0.5;
1518 *points.get_mut([0, 5]).unwrap() = 0.5;
1519 *points.get_mut([1, 5]).unwrap() = 0.5;
1520 e.tabulate(&points, 0, &mut data);
1521
1522 for pt in 0..6 {
1523 let x = *points.get([0, pt]).unwrap();
1524 let y = *points.get([1, pt]).unwrap();
1525 for (i, basis_f) in [[0.0, 1.0 - y], [x - 1.0, 0.0], [-x, 0.0], [0.0, y]]
1526 .iter()
1527 .enumerate()
1528 {
1529 for (d, value) in basis_f.iter().enumerate() {
1530 assert_relative_eq!(*data.get([0, pt, i, d]).unwrap(), value, epsilon = 1e-14);
1531 }
1532 }
1533 }
1534 check_dofs(e);
1535 }
1536
1537 #[test]
1538 fn test_raviart_thomas_2_quadrilateral() {
1539 let e = raviart_thomas::create::<f64, f64>(
1540 ReferenceCellType::Quadrilateral,
1541 2,
1542 Continuity::Standard,
1543 );
1544 assert_eq!(e.value_size(), 2);
1545 check_dofs(e);
1546 }
1547
1548 #[test]
1549 fn test_raviart_thomas_3_quadrilateral() {
1550 let e = raviart_thomas::create::<f64, f64>(
1551 ReferenceCellType::Quadrilateral,
1552 3,
1553 Continuity::Standard,
1554 );
1555 assert_eq!(e.value_size(), 2);
1556 check_dofs(e);
1557 }
1558
1559 #[test]
1560 fn test_raviart_thomas_1_tetrahedron() {
1561 let e = raviart_thomas::create::<f64, f64>(
1562 ReferenceCellType::Tetrahedron,
1563 1,
1564 Continuity::Standard,
1565 );
1566 assert_eq!(e.value_size(), 3);
1567 check_dofs(e);
1568 }
1569
1570 #[test]
1571 fn test_raviart_thomas_2_tetrahedron() {
1572 let e = raviart_thomas::create::<f64, f64>(
1573 ReferenceCellType::Tetrahedron,
1574 2,
1575 Continuity::Standard,
1576 );
1577 assert_eq!(e.value_size(), 3);
1578 check_dofs(e);
1579 }
1580
1581 #[test]
1582 fn test_raviart_thomas_3_tetrahedron() {
1583 let e = raviart_thomas::create::<f64, f64>(
1584 ReferenceCellType::Tetrahedron,
1585 3,
1586 Continuity::Standard,
1587 );
1588 assert_eq!(e.value_size(), 3);
1589 check_dofs(e);
1590 }
1591
1592 #[test]
1593 fn test_raviart_thomas_1_hexahedron() {
1594 let e = raviart_thomas::create::<f64, f64>(
1595 ReferenceCellType::Hexahedron,
1596 1,
1597 Continuity::Standard,
1598 );
1599 assert_eq!(e.value_size(), 3);
1600 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1601 let mut points = rlst_dynamic_array!(f64, [3, 6]);
1602 *points.get_mut([0, 0]).unwrap() = 0.0;
1603 *points.get_mut([1, 0]).unwrap() = 0.0;
1604 *points.get_mut([2, 0]).unwrap() = 0.0;
1605 *points.get_mut([0, 1]).unwrap() = 1.0;
1606 *points.get_mut([1, 1]).unwrap() = 0.0;
1607 *points.get_mut([2, 1]).unwrap() = 0.8;
1608 *points.get_mut([0, 2]).unwrap() = 0.0;
1609 *points.get_mut([1, 2]).unwrap() = 1.0;
1610 *points.get_mut([2, 2]).unwrap() = 1.0;
1611 *points.get_mut([0, 3]).unwrap() = 0.5;
1612 *points.get_mut([1, 3]).unwrap() = 0.0;
1613 *points.get_mut([2, 3]).unwrap() = 0.1;
1614 *points.get_mut([0, 4]).unwrap() = 1.0;
1615 *points.get_mut([1, 4]).unwrap() = 0.5;
1616 *points.get_mut([2, 4]).unwrap() = 0.5;
1617 *points.get_mut([0, 5]).unwrap() = 0.5;
1618 *points.get_mut([1, 5]).unwrap() = 0.5;
1619 *points.get_mut([2, 5]).unwrap() = 1.0;
1620 e.tabulate(&points, 0, &mut data);
1621
1622 for pt in 0..6 {
1623 let x = *points.get([0, pt]).unwrap();
1624 let y = *points.get([1, pt]).unwrap();
1625 let z = *points.get([2, pt]).unwrap();
1626 for (i, basis_f) in [
1627 [0.0, 0.0, 1.0 - z],
1628 [0.0, y - 1.0, 0.0],
1629 [1.0 - x, 0.0, 0.0],
1630 [x, 0.0, 0.0],
1631 [0.0, -y, 0.0],
1632 [0.0, 0.0, z],
1633 ]
1634 .iter()
1635 .enumerate()
1636 {
1637 for (d, value) in basis_f.iter().enumerate() {
1638 assert_relative_eq!(*data.get([0, pt, i, d]).unwrap(), value, epsilon = 1e-14);
1639 }
1640 }
1641 }
1642 check_dofs(e);
1643 }
1644
1645 #[test]
1646 fn test_raviart_thomas_2_hexahedron() {
1647 let e = raviart_thomas::create::<f64, f64>(
1648 ReferenceCellType::Hexahedron,
1649 2,
1650 Continuity::Standard,
1651 );
1652 assert_eq!(e.value_size(), 3);
1653 check_dofs(e);
1654 }
1655
1656 #[test]
1657 fn test_nedelec_1_triangle() {
1658 let e = nedelec::create::<f64, f64>(ReferenceCellType::Triangle, 1, Continuity::Standard);
1659 assert_eq!(e.value_size(), 2);
1660 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1661 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1662 *points.get_mut([0, 0]).unwrap() = 0.0;
1663 *points.get_mut([1, 0]).unwrap() = 0.0;
1664 *points.get_mut([0, 1]).unwrap() = 1.0;
1665 *points.get_mut([1, 1]).unwrap() = 0.0;
1666 *points.get_mut([0, 2]).unwrap() = 0.0;
1667 *points.get_mut([1, 2]).unwrap() = 1.0;
1668 *points.get_mut([0, 3]).unwrap() = 0.5;
1669 *points.get_mut([1, 3]).unwrap() = 0.0;
1670 *points.get_mut([0, 4]).unwrap() = 0.0;
1671 *points.get_mut([1, 4]).unwrap() = 0.5;
1672 *points.get_mut([0, 5]).unwrap() = 0.5;
1673 *points.get_mut([1, 5]).unwrap() = 0.5;
1674 e.tabulate(&points, 0, &mut data);
1675
1676 for pt in 0..6 {
1677 let x = *points.get([0, pt]).unwrap();
1678 let y = *points.get([1, pt]).unwrap();
1679 for (i, basis_f) in [[-y, x], [y, 1.0 - x], [1.0 - y, x]].iter().enumerate() {
1680 for (d, value) in basis_f.iter().enumerate() {
1681 assert_relative_eq!(*data.get([0, pt, i, d]).unwrap(), value, epsilon = 1e-14);
1682 }
1683 }
1684 }
1685 check_dofs(e);
1686 }
1687
1688 #[test]
1689 fn test_nedelec_2_triangle() {
1690 let e = nedelec::create::<f64, f64>(ReferenceCellType::Triangle, 2, Continuity::Standard);
1691 assert_eq!(e.value_size(), 2);
1692 check_dofs(e);
1693 }
1694
1695 #[test]
1696 fn test_nedelec_3_triangle() {
1697 let e = nedelec::create::<f64, f64>(ReferenceCellType::Triangle, 3, Continuity::Standard);
1698 assert_eq!(e.value_size(), 2);
1699 check_dofs(e);
1700 }
1701
1702 #[test]
1703 fn test_nedelec_1_quadrilateral() {
1704 let e =
1705 nedelec::create::<f64, f64>(ReferenceCellType::Quadrilateral, 1, Continuity::Standard);
1706 assert_eq!(e.value_size(), 2);
1707 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1708 let mut points = rlst_dynamic_array!(f64, [2, 6]);
1709 *points.get_mut([0, 0]).unwrap() = 0.0;
1710 *points.get_mut([1, 0]).unwrap() = 0.0;
1711 *points.get_mut([0, 1]).unwrap() = 1.0;
1712 *points.get_mut([1, 1]).unwrap() = 0.0;
1713 *points.get_mut([0, 2]).unwrap() = 0.0;
1714 *points.get_mut([1, 2]).unwrap() = 1.0;
1715 *points.get_mut([0, 3]).unwrap() = 0.5;
1716 *points.get_mut([1, 3]).unwrap() = 0.0;
1717 *points.get_mut([0, 4]).unwrap() = 1.0;
1718 *points.get_mut([1, 4]).unwrap() = 0.5;
1719 *points.get_mut([0, 5]).unwrap() = 0.5;
1720 *points.get_mut([1, 5]).unwrap() = 0.5;
1721 e.tabulate(&points, 0, &mut data);
1722
1723 for pt in 0..6 {
1724 let x = *points.get([0, pt]).unwrap();
1725 let y = *points.get([1, pt]).unwrap();
1726 for (i, basis_f) in [[1.0 - y, 0.0], [0.0, 1.0 - x], [0.0, x], [y, 0.0]]
1727 .iter()
1728 .enumerate()
1729 {
1730 for (d, value) in basis_f.iter().enumerate() {
1731 assert_relative_eq!(*data.get([0, pt, i, d]).unwrap(), value, epsilon = 1e-14);
1732 }
1733 }
1734 }
1735 check_dofs(e);
1736 }
1737
1738 #[test]
1739 fn test_nedelec_2_quadrilateral() {
1740 let e =
1741 nedelec::create::<f64, f64>(ReferenceCellType::Quadrilateral, 2, Continuity::Standard);
1742 assert_eq!(e.value_size(), 2);
1743 check_dofs(e);
1744 }
1745
1746 #[test]
1747 fn test_nedelec_3_quadrilateral() {
1748 let e =
1749 nedelec::create::<f64, f64>(ReferenceCellType::Quadrilateral, 3, Continuity::Standard);
1750 assert_eq!(e.value_size(), 2);
1751 check_dofs(e);
1752 }
1753
1754 #[test]
1755 fn test_nedelec_1_tetrahedron() {
1756 let e =
1757 nedelec::create::<f64, f64>(ReferenceCellType::Tetrahedron, 1, Continuity::Standard);
1758 assert_eq!(e.value_size(), 3);
1759 check_dofs(e);
1760 }
1761
1762 #[test]
1763 fn test_nedelec_2_tetrahedron() {
1764 let e =
1765 nedelec::create::<f64, f64>(ReferenceCellType::Tetrahedron, 2, Continuity::Standard);
1766 assert_eq!(e.value_size(), 3);
1767 check_dofs(e);
1768 }
1769
1770 #[test]
1771 fn test_nedelec_3_tetrahedron() {
1772 let e =
1773 nedelec::create::<f64, f64>(ReferenceCellType::Tetrahedron, 3, Continuity::Standard);
1774 assert_eq!(e.value_size(), 3);
1775 check_dofs(e);
1776 }
1777
1778 #[test]
1779 fn test_nedelec_1_hexahedron() {
1780 let e = nedelec::create::<f64, f64>(ReferenceCellType::Hexahedron, 1, Continuity::Standard);
1781 assert_eq!(e.value_size(), 3);
1782 let mut data = DynArray::<f64, 4>::from_shape(e.tabulate_array_shape(0, 6));
1783 let mut points = rlst_dynamic_array!(f64, [3, 6]);
1784 *points.get_mut([0, 0]).unwrap() = 0.0;
1785 *points.get_mut([1, 0]).unwrap() = 0.0;
1786 *points.get_mut([2, 0]).unwrap() = 0.0;
1787 *points.get_mut([0, 1]).unwrap() = 1.0;
1788 *points.get_mut([1, 1]).unwrap() = 0.0;
1789 *points.get_mut([2, 1]).unwrap() = 0.8;
1790 *points.get_mut([0, 2]).unwrap() = 0.0;
1791 *points.get_mut([1, 2]).unwrap() = 1.0;
1792 *points.get_mut([2, 2]).unwrap() = 1.0;
1793 *points.get_mut([0, 3]).unwrap() = 0.5;
1794 *points.get_mut([1, 3]).unwrap() = 0.0;
1795 *points.get_mut([2, 3]).unwrap() = 0.1;
1796 *points.get_mut([0, 4]).unwrap() = 1.0;
1797 *points.get_mut([1, 4]).unwrap() = 0.5;
1798 *points.get_mut([2, 4]).unwrap() = 0.5;
1799 *points.get_mut([0, 5]).unwrap() = 0.5;
1800 *points.get_mut([1, 5]).unwrap() = 0.5;
1801 *points.get_mut([2, 5]).unwrap() = 1.0;
1802 e.tabulate(&points, 0, &mut data);
1803
1804 for pt in 0..6 {
1805 let x = *points.get([0, pt]).unwrap();
1806 let y = *points.get([1, pt]).unwrap();
1807 let z = *points.get([2, pt]).unwrap();
1808 for (i, basis_f) in [
1809 [(1.0 - y) * (1.0 - z), 0.0, 0.0],
1810 [0.0, (1.0 - x) * (1.0 - z), 0.0],
1811 [0.0, 0.0, (1.0 - x) * (1.0 - y)],
1812 [0.0, x * (1.0 - z), 0.0],
1813 [0.0, 0.0, x * (1.0 - y)],
1814 [y * (1.0 - z), 0.0, 0.0],
1815 [0.0, 0.0, (1.0 - x) * y],
1816 [0.0, 0.0, x * y],
1817 [(1.0 - y) * z, 0.0, 0.0],
1818 [0.0, (1.0 - x) * z, 0.0],
1819 [0.0, x * z, 0.0],
1820 [y * z, 0.0, 0.0],
1821 ]
1822 .iter()
1823 .enumerate()
1824 {
1825 for (d, value) in basis_f.iter().enumerate() {
1826 assert_relative_eq!(*data.get([0, pt, i, d]).unwrap(), value, epsilon = 1e-14);
1827 }
1828 }
1829 }
1830 check_dofs(e);
1831 }
1832
1833 #[test]
1834 fn test_nedelec_2_hexahedron() {
1835 let e = nedelec::create::<f64, f64>(ReferenceCellType::Hexahedron, 2, Continuity::Standard);
1836 assert_eq!(e.value_size(), 3);
1837 check_dofs(e);
1838 }
1839
1840 macro_rules! test_entity_closure_dofs_lagrange {
1841 ($cell:ident, $degree:expr) => {
1842 paste! {
1843 #[test]
1844 fn [<test_entity_closure_dofs_ $cell:lower _ $degree>]() {
1845 let e = lagrange::create::<f64, f64>(ReferenceCellType::[<$cell>], [<$degree>], Continuity::Standard);
1846 let c = reference_cell::connectivity(ReferenceCellType::[<$cell>]);
1847
1848 for (dim, entities) in c.iter().enumerate() {
1849 for (n, entity) in entities.iter().enumerate() {
1850 let ecd = e.entity_closure_dofs(dim, n).unwrap();
1851 let mut len = 0;
1852 for (sub_dim, sub_entities) in entity.iter().take(dim + 1).enumerate() {
1853 for sub_entity in sub_entities {
1854 let dofs = e.entity_dofs(sub_dim, *sub_entity).unwrap();
1855 len += dofs.len();
1856 for dof in dofs {
1857 assert!(ecd.contains(dof));
1858 }
1859 }
1860 }
1861 assert_eq!(ecd.len(), len);
1862 }
1863 }
1864 }
1865 }
1866 };
1867 }
1868
1869 test_entity_closure_dofs_lagrange!(Interval, 2);
1870 test_entity_closure_dofs_lagrange!(Interval, 3);
1871 test_entity_closure_dofs_lagrange!(Interval, 4);
1872 test_entity_closure_dofs_lagrange!(Interval, 5);
1873 test_entity_closure_dofs_lagrange!(Triangle, 2);
1874 test_entity_closure_dofs_lagrange!(Triangle, 3);
1875 test_entity_closure_dofs_lagrange!(Triangle, 4);
1876 test_entity_closure_dofs_lagrange!(Triangle, 5);
1877 test_entity_closure_dofs_lagrange!(Quadrilateral, 2);
1878 test_entity_closure_dofs_lagrange!(Quadrilateral, 3);
1879 test_entity_closure_dofs_lagrange!(Quadrilateral, 4);
1880 test_entity_closure_dofs_lagrange!(Quadrilateral, 5);
1881 test_entity_closure_dofs_lagrange!(Tetrahedron, 2);
1882 test_entity_closure_dofs_lagrange!(Tetrahedron, 3);
1883 test_entity_closure_dofs_lagrange!(Tetrahedron, 4);
1884 test_entity_closure_dofs_lagrange!(Tetrahedron, 5);
1885 test_entity_closure_dofs_lagrange!(Hexahedron, 2);
1886 test_entity_closure_dofs_lagrange!(Hexahedron, 3);
1887
1888 macro_rules! test_dof_transformations {
1889 ($cell:ident, $element:ident, $degree:expr) => {
1890 paste! {
1891
1892 #[test]
1893 fn [<test_dof_transformations_ $cell:lower _ $element:lower _ $degree>]() {
1894 let e = [<$element>]::create::<f64, f64>(ReferenceCellType::[<$cell>], [<$degree>], Continuity::Standard);
1895 let tdim = reference_cell::dim(ReferenceCellType::[<$cell>]);
1896 for edim in 1..tdim {
1897 for entity in &reference_cell::entity_types(ReferenceCellType::[<$cell>])[edim] {
1898 for t in match edim {
1899 1 => vec![Transformation::Reflection],
1900 2 => vec![Transformation::Reflection, Transformation::Rotation],
1901 _ => { panic!("Shouldn't test this dimension"); },
1902 } {
1903 let order = match t {
1904 Transformation::Reflection => 2,
1905 Transformation::Rotation => match entity {
1906 ReferenceCellType::Triangle => 3,
1907 ReferenceCellType::Quadrilateral => 4,
1908 _ => {
1909 panic!("Unsupported entity type: {entity:?}");
1910 }
1911 },
1912 };
1913 match e.dof_transformation(*entity, t).unwrap() {
1914 DofTransformation::Identity => {}
1915 DofTransformation::Permutation(p) => {
1916 let mut data = (0..p.len()).collect::<Vec<_>>();
1917 for _ in 0..order {
1918 math::apply_permutation(p, &mut data);
1919 }
1920 for (i, j) in data.iter().enumerate() {
1921 assert_eq!(i, *j);
1922 }
1923 }
1924 DofTransformation::Transformation(m, p) => {
1925 let mut data = (0..p.len()).map(|i| i as f64).collect::<Vec<_>>();
1926 for _ in 0..order {
1927 math::apply_perm_and_matrix(m, p, &mut data);
1928 }
1929 for (i, j) in data.iter().enumerate() {
1930 assert_relative_eq!(i as f64, j, epsilon=1e-10);
1931 }
1932 }
1933 }
1934 }
1935 }
1936 }
1937 }
1938 }
1939 };
1940 }
1941
1942 test_dof_transformations!(Triangle, lagrange, 1);
1943 test_dof_transformations!(Triangle, lagrange, 2);
1944 test_dof_transformations!(Triangle, lagrange, 3);
1945 test_dof_transformations!(Quadrilateral, lagrange, 1);
1946 test_dof_transformations!(Quadrilateral, lagrange, 2);
1947 test_dof_transformations!(Quadrilateral, lagrange, 3);
1948 test_dof_transformations!(Tetrahedron, lagrange, 1);
1949 test_dof_transformations!(Tetrahedron, lagrange, 2);
1950 test_dof_transformations!(Tetrahedron, lagrange, 3);
1951 test_dof_transformations!(Hexahedron, lagrange, 1);
1952 test_dof_transformations!(Hexahedron, lagrange, 2);
1953 test_dof_transformations!(Hexahedron, lagrange, 3);
1954 test_dof_transformations!(Triangle, nedelec, 1);
1955 test_dof_transformations!(Triangle, nedelec, 2);
1956 test_dof_transformations!(Triangle, nedelec, 3);
1957 test_dof_transformations!(Quadrilateral, nedelec, 1);
1958 test_dof_transformations!(Quadrilateral, nedelec, 2);
1959 test_dof_transformations!(Quadrilateral, nedelec, 3);
1960 test_dof_transformations!(Tetrahedron, nedelec, 1);
1961 test_dof_transformations!(Tetrahedron, nedelec, 2);
1962 test_dof_transformations!(Tetrahedron, nedelec, 3);
1963 test_dof_transformations!(Hexahedron, nedelec, 1);
1964 test_dof_transformations!(Hexahedron, nedelec, 2);
1965 test_dof_transformations!(Triangle, raviart_thomas, 1);
1966 test_dof_transformations!(Triangle, raviart_thomas, 2);
1967 test_dof_transformations!(Triangle, raviart_thomas, 3);
1968 test_dof_transformations!(Quadrilateral, raviart_thomas, 1);
1969 test_dof_transformations!(Quadrilateral, raviart_thomas, 2);
1970 test_dof_transformations!(Quadrilateral, raviart_thomas, 3);
1971 test_dof_transformations!(Tetrahedron, raviart_thomas, 1);
1972 test_dof_transformations!(Tetrahedron, raviart_thomas, 2);
1973 test_dof_transformations!(Tetrahedron, raviart_thomas, 3);
1974 test_dof_transformations!(Hexahedron, raviart_thomas, 1);
1975 test_dof_transformations!(Hexahedron, raviart_thomas, 2);
1976
1977 fn assert_dof_transformation_equal<Array2Impl: ValueArrayImpl<f64, 2>>(
1978 p: &[usize],
1979 m: &Array<Array2Impl, 2>,
1980 expected: Vec<Vec<f64>>,
1981 ) {
1982 let ndofs = p.len();
1983 assert_eq!(m.shape()[0], ndofs);
1984 assert_eq!(m.shape()[1], ndofs);
1985 assert_eq!(expected.len(), ndofs);
1986 for i in 0..ndofs {
1987 let mut col = vec![0.0; ndofs];
1988 col[i] = 1.0;
1989 math::apply_perm_and_matrix(m, p, &mut col);
1990 for (j, c) in col.iter().enumerate() {
1991 assert_relative_eq!(expected[j][i], *c, epsilon = 1e-10);
1992 }
1993 }
1994 }
1995
1996 #[test]
1997 fn test_nedelec1_triangle_dof_transformations() {
1998 let e = nedelec::create::<f64, f64>(ReferenceCellType::Triangle, 1, Continuity::Standard);
1999 if let DofTransformation::Transformation(m, p) = e
2000 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2001 .unwrap()
2002 {
2003 assert_eq!(p.len(), 1);
2004 assert_eq!(m.shape()[0], 1);
2005 assert_eq!(m.shape()[1], 1);
2006 assert_dof_transformation_equal(p, m, vec![vec![-1.0]]);
2007 } else {
2008 panic!("Should be a linear transformation");
2009 }
2010 }
2011
2012 #[test]
2013 fn test_nedelec2_triangle_dof_transformations() {
2014 let e = nedelec::create::<f64, f64>(ReferenceCellType::Triangle, 2, Continuity::Standard);
2015 if let DofTransformation::Transformation(m, p) = e
2016 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2017 .unwrap()
2018 {
2019 assert_eq!(p.len(), 2);
2020 assert_eq!(m.shape()[0], 2);
2021 assert_eq!(m.shape()[1], 2);
2022 assert_dof_transformation_equal(p, m, vec![vec![-1.0, 0.0], vec![0.0, 1.0]]);
2023 } else {
2024 panic!("Should be a linear transformation");
2025 }
2026 }
2027
2028 #[test]
2029 fn test_nedelec1_tetrahedron_dof_transformations() {
2030 let e =
2031 nedelec::create::<f64, f64>(ReferenceCellType::Tetrahedron, 1, Continuity::Standard);
2032 if let DofTransformation::Transformation(m, p) = e
2033 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2034 .unwrap()
2035 {
2036 assert_eq!(p.len(), 1);
2037 assert_eq!(m.shape()[0], 1);
2038 assert_eq!(m.shape()[1], 1);
2039 assert_dof_transformation_equal(p, m, vec![vec![-1.0]]);
2040 } else {
2041 panic!("Should be a linear transformation");
2042 }
2043 if let DofTransformation::Identity = e
2044 .dof_transformation(ReferenceCellType::Triangle, Transformation::Reflection)
2045 .unwrap()
2046 {
2047 } else {
2048 panic!("Should be an identity transformation");
2049 }
2050 if let DofTransformation::Identity = e
2051 .dof_transformation(ReferenceCellType::Triangle, Transformation::Rotation)
2052 .unwrap()
2053 {
2054 } else {
2055 panic!("Should be an identity transformation");
2056 }
2057 }
2058
2059 #[test]
2060 fn test_nedelec2_tetrahedron_dof_transformations() {
2061 let e =
2062 nedelec::create::<f64, f64>(ReferenceCellType::Tetrahedron, 2, Continuity::Standard);
2063 if let DofTransformation::Transformation(m, p) = e
2064 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2065 .unwrap()
2066 {
2067 assert_eq!(p.len(), 2);
2068 assert_eq!(m.shape()[0], 2);
2069 assert_eq!(m.shape()[1], 2);
2070 assert_dof_transformation_equal(p, m, vec![vec![-1.0, 0.0], vec![0.0, 1.0]]);
2071 } else {
2072 panic!("Should be a linear transformation");
2073 }
2074 if let DofTransformation::Permutation(p) = e
2075 .dof_transformation(ReferenceCellType::Triangle, Transformation::Reflection)
2076 .unwrap()
2077 {
2078 assert_eq!(p.len(), 2);
2079 let mut indices = vec![0, 1];
2080 math::apply_permutation(p, &mut indices);
2081 assert_eq!(indices[0], 1);
2082 assert_eq!(indices[1], 0);
2083 } else {
2084 panic!("Should be a permutation");
2085 }
2086 if let DofTransformation::Transformation(m, p) = e
2087 .dof_transformation(ReferenceCellType::Triangle, Transformation::Rotation)
2088 .unwrap()
2089 {
2090 assert_eq!(p.len(), 2);
2091 assert_eq!(m.shape()[0], 2);
2092 assert_eq!(m.shape()[1], 2);
2093 assert_dof_transformation_equal(p, m, vec![vec![-1.0, -1.0], vec![1.0, 0.0]]);
2094 } else {
2095 panic!("Should be a linear transformation");
2096 }
2097 }
2098
2099 #[test]
2100 fn test_nedelec2_quadrilateral_dof_transformations() {
2101 let e = nedelec::create::<f64, f64>(ReferenceCellType::Hexahedron, 2, Continuity::Standard);
2102 if let DofTransformation::Transformation(m, p) = e
2103 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2104 .unwrap()
2105 {
2106 assert_eq!(p.len(), 2);
2107 assert_eq!(m.shape()[0], 2);
2108 assert_eq!(m.shape()[1], 2);
2109 assert_dof_transformation_equal(p, m, vec![vec![-1.0, 0.0], vec![0.0, 1.0]]);
2110 } else {
2111 panic!("Should be a linear transformation");
2112 }
2113 }
2114
2115 #[test]
2116 fn test_nedelec2_hexahedron_dof_transformations() {
2117 let e = nedelec::create::<f64, f64>(ReferenceCellType::Hexahedron, 2, Continuity::Standard);
2118 if let DofTransformation::Transformation(m, p) = e
2119 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2120 .unwrap()
2121 {
2122 assert_eq!(p.len(), 2);
2123 assert_eq!(m.shape()[0], 2);
2124 assert_eq!(m.shape()[1], 2);
2125 assert_dof_transformation_equal(p, m, vec![vec![-1.0, 0.0], vec![0.0, 1.0]]);
2126 } else {
2127 panic!("Should be a linear transformation");
2128 }
2129 if let DofTransformation::Permutation(p) = e
2130 .dof_transformation(ReferenceCellType::Quadrilateral, Transformation::Reflection)
2131 .unwrap()
2132 {
2133 assert_eq!(p.len(), 4);
2134 let mut indices = vec![0, 1, 2, 3];
2135 math::apply_permutation(p, &mut indices);
2136 assert_eq!(indices[0], 1);
2137 assert_eq!(indices[1], 0);
2138 assert_eq!(indices[2], 3);
2139 assert_eq!(indices[3], 2);
2140 } else {
2141 panic!("Should be a permutation");
2142 }
2143 if let DofTransformation::Transformation(m, p) = e
2144 .dof_transformation(ReferenceCellType::Quadrilateral, Transformation::Rotation)
2145 .unwrap()
2146 {
2147 assert_eq!(p.len(), 4);
2148 assert_eq!(m.shape()[0], 4);
2149 assert_eq!(m.shape()[1], 4);
2150 assert_dof_transformation_equal(
2151 p,
2152 m,
2153 vec![
2154 vec![0.0, -1.0, 0.0, 0.0],
2155 vec![1.0, 0.0, 0.0, 0.0],
2156 vec![0.0, 0.0, 0.0, 1.0],
2157 vec![0.0, 0.0, 1.0, 0.0],
2158 ],
2159 );
2160 } else {
2161 panic!("Should be a linear transformation");
2162 }
2163 }
2164
2165 #[test]
2166 fn test_lagrange4_tetrahedron_dof_transformations() {
2167 let e =
2168 lagrange::create::<f64, f64>(ReferenceCellType::Tetrahedron, 4, Continuity::Standard);
2169 if let DofTransformation::Permutation(p) = e
2170 .dof_transformation(ReferenceCellType::Interval, Transformation::Reflection)
2171 .unwrap()
2172 {
2173 assert_eq!(p.len(), 3);
2174 let mut indices = vec![0, 1, 2];
2175 math::apply_permutation(p, &mut indices);
2176 assert_eq!(indices[0], 2);
2177 assert_eq!(indices[1], 1);
2178 assert_eq!(indices[2], 0);
2179 } else {
2180 panic!("Should be a permutation");
2181 }
2182 if let DofTransformation::Permutation(p) = e
2183 .dof_transformation(ReferenceCellType::Triangle, Transformation::Reflection)
2184 .unwrap()
2185 {
2186 assert_eq!(p.len(), 3);
2187 let mut indices = vec![0, 1, 2];
2188 math::apply_permutation(p, &mut indices);
2189 assert_eq!(indices[0], 0);
2190 assert_eq!(indices[1], 2);
2191 assert_eq!(indices[2], 1);
2192 } else {
2193 panic!("Should be a permutation");
2194 }
2195 if let DofTransformation::Permutation(p) = e
2196 .dof_transformation(ReferenceCellType::Triangle, Transformation::Rotation)
2197 .unwrap()
2198 {
2199 assert_eq!(p.len(), 3);
2200 let mut indices = vec![0, 1, 2];
2201 math::apply_permutation(p, &mut indices);
2202 assert_eq!(indices[0], 1);
2203 assert_eq!(indices[1], 2);
2204 assert_eq!(indices[2], 0);
2205 } else {
2206 panic!("Should be a permutation");
2207 }
2208 }
2209
2210 #[test]
2211 fn test_dof_permuting_triangle() {
2212 let e = lagrange::create::<f64, f64>(ReferenceCellType::Triangle, 3, Continuity::Standard);
2213
2214 let mut n = (0..10).collect::<Vec<_>>();
2215 e.apply_dof_permutations(&mut n, 7);
2216 for (i, j) in izip!(&n, [0, 1, 2, 4, 3, 6, 5, 8, 7, 9]) {
2217 assert_eq!(*i, j);
2218 }
2219
2220 let mut n = (0..20).collect::<Vec<_>>();
2221 e.apply_dof_permutations(&mut n, 7);
2222 for (i, j) in izip!(
2223 &n,
2224 [
2225 0, 1, 2, 3, 4, 5, 8, 9, 6, 7, 12, 13, 10, 11, 16, 17, 14, 15, 18, 19
2226 ]
2227 ) {
2228 assert_eq!(*i, j);
2229 }
2230 }
2231
2232 #[test]
2233 fn test_dof_permuting_tetrahedron() {
2234 let e =
2235 lagrange::create::<f64, f64>(ReferenceCellType::Tetrahedron, 3, Continuity::Standard);
2236
2237 let mut n = (0..20).collect::<Vec<_>>();
2238 e.apply_dof_permutations(&mut n, 63);
2239 for (i, j) in izip!(
2240 &n,
2241 [
2242 0, 1, 2, 3, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 16, 17, 18, 19
2243 ]
2244 ) {
2245 assert_eq!(*i, j);
2246 }
2247 }
2248}