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}