ndelement/traits.rs
1//! Traits.
2use crate::types::DofTransformation;
3use rlst::{Array, MutableArrayImpl, RlstScalar, ValueArrayImpl};
4use std::fmt::Debug;
5use std::hash::Hash;
6
7/// A finite element.
8pub trait FiniteElement {
9 /// The scalar type
10 type T: RlstScalar;
11
12 /// Cell type
13 ///
14 /// The cell type is typically defined through [ReferenceCellType](crate::types::ReferenceCellType).
15 type CellType: Debug + PartialEq + Eq + Clone + Copy + Hash;
16
17 /// The reference cell type, eg one of `Point`, `Interval`, `Triangle`, etc.
18 fn cell_type(&self) -> Self::CellType;
19
20 /// The number of basis functions.
21 fn dim(&self) -> usize;
22
23 /// The shape of the values returned by functions in $\mathcal{V}$.
24 ///
25 /// If the values are scalar an empty slice is returned.
26 fn value_shape(&self) -> &[usize];
27
28 /// The number of values returned.
29 ///
30 /// If (for example) `value_shape` is `[3, 4]` then `value_size` is $3\times4 = 12$.
31 /// If `value_shape` returns an empty array (ie the shape functions are scalar) the
32 // convention is used that the product of the elements of an empty array is 1.
33 fn value_size(&self) -> usize;
34
35 /// Tabulate the values of the basis functions and their derivatives at a set of points
36 ///
37 /// - `points` is a two-dimensional array where each column contains the coordinates of one point.
38 /// - `nderivs` is the desired number of derivatives (0 for no derivatives, 1 for all first order derivatives, etc.).
39 /// - `data` is the 4-dimensional output array. The first dimension is the total number of partial derivatives,
40 /// the second dimension is the number of evaluation points, the third dimension is the number of
41 /// basis functions of the element, and the fourth dimension is the value size of the basis function output.
42 /// For example, `data[3, 2, 1, 0]` returns the 0th value of the third partial derivative on the point with index 2 for the
43 /// basis function with index 1.
44 ///
45 /// ## Remark
46 /// Let $d^{i + k} = dx^{i}dy^{j}$ be a derivative with respect to $x$, $y$ in two dimensions and
47 /// $d^{i + k + j} = dx^{i}dy^{j}dz^{k}$ be a derivative with respect to $x$, $y$, and $z$ in three dimensions.
48 /// Then the corresponding index $\ell$ in the first dimension of the `data` array is computed as follows.
49 ///
50 /// - Triangle: $l = (i + j + 1) * (i + j) / 2 + j$
51 /// - Quadrilateral: $l = i * (n + 1) + j$
52 /// - Tetrahedron: $l = (i + j + k) * (i + j + k + 1) * (i + j + k + 2) / 6 + (j + k) * (j + k + 1) / 2 + k$
53 /// - Hexahedron $l = i * (n + 1) * (n + 1) + j * (n + 1) + k$.
54 ///
55 /// For the quadrilaterals and hexahedra, the parameter $n$ denotes the Lagrange superdegree.
56 fn tabulate<
57 TGeo: RlstScalar,
58 Array2Impl: ValueArrayImpl<TGeo, 2>,
59 Array4MutImpl: MutableArrayImpl<Self::T, 4>,
60 >(
61 &self,
62 points: &Array<Array2Impl, 2>,
63 nderivs: usize,
64 data: &mut Array<Array4MutImpl, 4>,
65 );
66
67 /// Get the required shape for a tabulation array.
68 fn tabulate_array_shape(&self, nderivs: usize, npoints: usize) -> [usize; 4];
69
70 /// Return the dof indices that are associated with the subentity with index `entity_number` and dimension `entity_dim`.
71 ///
72 /// - For `entity_dim = 0` this returns the degrees of freedom (dofs) associated with the corresponding point.
73 /// - For `entity_dim = 1` this returns the dofs associated with the corresponding edge.
74 /// - For `entity_dim = 2` this returns the dofs associated with the corresponding face.
75 ///
76 /// Note that this does not return dofs on the boundary of an entity, that means that (for example)
77 /// for an edge the dofs associated with the two vertices at the boundary of the edge are not returned.
78 /// To return also the boundary dofs use [FiniteElement::entity_closure_dofs].
79 fn entity_dofs(&self, entity_dim: usize, entity_number: usize) -> Option<&[usize]>;
80
81 /// The DOFs that are associated with a closure of a subentity of the reference cell.
82 ///
83 /// This method is similar to [FiniteElement::entity_dofs], but it includes the dofs
84 /// associated with the boundary of an entity. For an edge (for example) it returns the dofs associated
85 /// with the vertices at the boundary of the edge (as well as the dofs associated with the edge itself).
86 fn entity_closure_dofs(&self, entity_dim: usize, entity_number: usize) -> Option<&[usize]>;
87}
88
89/// A finite element that is mapped from a reference cell.
90pub trait MappedFiniteElement: FiniteElement {
91 /// Transformation type
92 ///
93 /// The Transformation type specifies possible transformations of the dofs on the reference element.
94 /// In most cases these will be rotations and reflections as defined in [Transformation](crate::types::Transformation).
95 type TransformationType: Debug + PartialEq + Eq + Clone + Copy + Hash;
96
97 /// The smallest degree Lagrange space that contains all possible polynomials of the finite element's polynomial space.
98 ///
99 /// Details on the definition of the degree of Lagrange spaces of finite elements are
100 /// given [here](https://defelement.org/ciarlet.html#The+degree+of+a+finite+element).
101 fn lagrange_superdegree(&self) -> usize;
102
103 /// Push function values forward to a physical cell.
104 ///
105 /// For Lagrange elements, this is an identity map. For many other element types, the function values
106 /// on the reference cell differ from those on the physical cell: for example Nedlec elements use a covariant
107 /// Piola transform. This method implements the appropriate transformation for the element.
108 ///
109 /// - `reference_values`: The values on the reference cell. The shape of this input is the same as the `data` input to the function
110 /// [[FiniteElement::tabulate].
111 /// - `nderivs`: The number of derivatives.
112 /// - `jacobians:` A three-dimensional array of jacobians of the map from reference to physical cell.
113 /// The first dimension is the reference point, the second dimension is the geometric dimension of the physical space, and
114 /// the third dimension is the topological dimension of the reference element. For example,
115 /// for the map of 5 points from the reference triangle to a physical surface triangle embedded in 3d space the dimension
116 /// of `jacobians` is `[5, 3, 2]`.
117 /// - `jacobian_determinants`: The determinant of the jacobian at each point. If the jacobian $J$ is not square, then the
118 /// determinant is computed using $d=\sqrt{\det(J^TJ)}$.
119 /// - `inverse_jacobians`: A three dimensional array that stores the inverse jacobian for the point with index j at position
120 /// `inverse_jacobians[j, :, :]`. The first dimension of `inverse_jacobians` is the point index, the second dimension
121 /// is the topological dimension, and the third dimension is the geometric dimension. If the Jacobian is rectangular then the
122 /// inverse Jacobian is the pseudo-inverse of the Jacobian, ie the matrix $J^\dagger$ such that $J^\dagger J = I$.
123 /// - `physical_values`: The output array of the push operation. This shape of this array is the same as the `reference_values`
124 /// input, with the [MappedFiniteElement::physical_value_size] used instead of the reference value size.
125 fn push_forward<
126 TGeo: RlstScalar,
127 Array3GeoImpl: ValueArrayImpl<TGeo, 3>,
128 Array4Impl: ValueArrayImpl<Self::T, 4>,
129 Array4MutImpl: MutableArrayImpl<Self::T, 4>,
130 >(
131 &self,
132 reference_values: &Array<Array4Impl, 4>,
133 nderivs: usize,
134 jacobians: &Array<Array3GeoImpl, 3>,
135 jacobian_determinants: &[TGeo],
136 inverse_jacobians: &Array<Array3GeoImpl, 3>,
137 physical_values: &mut Array<Array4MutImpl, 4>,
138 );
139
140 /// Pull function values back to the reference cell.
141 ///
142 /// This is the inverse operation to [MappedFiniteElement::push_forward].
143 fn pull_back<
144 TGeo: RlstScalar,
145 Array3GeoImpl: ValueArrayImpl<TGeo, 3>,
146 Array4Impl: ValueArrayImpl<Self::T, 4>,
147 Array4MutImpl: MutableArrayImpl<Self::T, 4>,
148 >(
149 &self,
150 physical_values: &Array<Array4Impl, 4>,
151 nderivs: usize,
152 jacobians: &Array<Array3GeoImpl, 3>,
153 jacobian_determinants: &[TGeo],
154 inverse_jacobians: &Array<Array3GeoImpl, 3>,
155 reference_values: &mut Array<Array4MutImpl, 4>,
156 );
157
158 /// The value shape on a physical cell
159 fn physical_value_shape(&self, gdim: usize) -> Vec<usize>;
160
161 /// The value size on a physical cell
162 fn physical_value_size(&self, gdim: usize) -> usize {
163 let mut vs = 1;
164 for i in self.physical_value_shape(gdim) {
165 vs *= i;
166 }
167 vs
168 }
169
170 /// The DOF transformation for a sub-entity.
171 fn dof_transformation(
172 &self,
173 entity: Self::CellType,
174 transformation: Self::TransformationType,
175 ) -> Option<&DofTransformation<Self::T>>;
176
177 /// Apply permutation parts of DOF transformations.
178 fn apply_dof_permutations<T>(&self, data: &mut [T], cell_orientation: i32);
179
180 /// Apply non-permutation parts of DOF transformations.
181 fn apply_dof_transformations(&self, data: &mut [Self::T], cell_orientation: i32);
182
183 /// Apply DOF transformations.
184 fn apply_dof_permutations_and_transformations(
185 &self,
186 data: &mut [Self::T],
187 cell_orientation: i32,
188 ) {
189 self.apply_dof_permutations(data, cell_orientation);
190 self.apply_dof_transformations(data, cell_orientation);
191 }
192}
193
194/// A family of finite elements defined on various cell types, with appropriate continuity
195/// between different cell types.
196pub trait ElementFamily {
197 /// The scalar type
198 type T: RlstScalar;
199 /// Cell type
200 type CellType: Debug + PartialEq + Eq + Clone + Copy + Hash;
201 /// The finite element type
202 type FiniteElement: FiniteElement<T = Self::T, CellType = Self::CellType> + 'static;
203
204 /// Create an element for the given cell type.
205 fn element(&self, cell_type: Self::CellType) -> Self::FiniteElement;
206}
207
208/// A map from the reference cell to physical cells.
209pub trait Map {
210 /// Push values from the reference cell to physical cells.
211 fn push_forward<
212 T: RlstScalar,
213 TGeo: RlstScalar,
214 Array3GeoImpl: ValueArrayImpl<TGeo, 3>,
215 Array4Impl: ValueArrayImpl<T, 4>,
216 Array4MutImpl: MutableArrayImpl<T, 4>,
217 >(
218 &self,
219 reference_values: &Array<Array4Impl, 4>,
220 nderivs: usize,
221 jacobians: &Array<Array3GeoImpl, 3>,
222 jacobian_determinants: &[TGeo],
223 inverse_jacobians: &Array<Array3GeoImpl, 3>,
224 physical_values: &mut Array<Array4MutImpl, 4>,
225 );
226
227 /// Pull values back to the reference cell.
228 fn pull_back<
229 T: RlstScalar,
230 TGeo: RlstScalar,
231 Array3GeoImpl: ValueArrayImpl<TGeo, 3>,
232 Array4Impl: ValueArrayImpl<T, 4>,
233 Array4MutImpl: MutableArrayImpl<T, 4>,
234 >(
235 &self,
236 physical_values: &Array<Array4Impl, 4>,
237 nderivs: usize,
238 jacobians: &Array<Array3GeoImpl, 3>,
239 jacobian_determinants: &[TGeo],
240 inverse_jacobians: &Array<Array3GeoImpl, 3>,
241 reference_values: &mut Array<Array4MutImpl, 4>,
242 );
243
244 /// The value shape on a physical cell.
245 fn physical_value_shape(&self, gdim: usize) -> Vec<usize>;
246}