DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
FiniteElement.h
1// Copyright (C) 2020-2026 Garth N. Wells and Matthew W. Scroggs
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include "traits.h"
10#include <array>
11#include <basix/finite-element.h>
12#include <cassert>
13#include <concepts>
14#include <cstdint>
15#include <dolfinx/mesh/cell_types.h>
16#include <functional>
17#include <memory>
18#include <optional>
19#include <span>
20#include <stdexcept>
21#include <utility>
22#include <vector>
23
24namespace dolfinx::fem
25{
27enum class doftransform : std::uint8_t
28{
31 inverse = 2,
33};
34
35template <std::floating_point T>
36class FiniteElement;
37
40template <std::floating_point T>
42{
43 std::reference_wrapper<const basix::FiniteElement<T>>
45 std::optional<std::vector<std::size_t>> value_shape
46 = std::nullopt;
47 bool symmetry = false;
49};
50
52template <typename U, typename V, typename W>
53BasixElementData(U element, V bs, W symmetry)
55
60template <std::floating_point T>
62{
63public:
65 using geometry_type = T;
66
76 const std::optional<std::vector<std::size_t>>& value_shape
77 = std::nullopt,
78 bool symmetric = false);
79
89
108 const std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>&
109 elements);
110
117 FiniteElement(mesh::CellType cell_type, std::span<const geometry_type> points,
118 std::array<std::size_t, 2> pshape,
119 std::vector<std::size_t> value_shape = {},
120 bool symmetric = false);
121
123 FiniteElement(const FiniteElement& element) = delete;
124
126 FiniteElement(FiniteElement&& element) = default;
127
129 ~FiniteElement() = default;
130
132 FiniteElement& operator=(const FiniteElement& element) = delete;
133
135 FiniteElement& operator=(FiniteElement&& element) = default;
136
141 bool operator==(const FiniteElement& e) const;
142
147 bool operator!=(const FiniteElement& e) const;
148
150 mesh::CellType cell_type() const noexcept;
151
158 const std::string& signature() const noexcept;
159
167 int space_dimension() const noexcept;
168
179 int block_size() const noexcept;
180
200 int value_size() const;
201
211 std::span<const std::size_t> value_shape() const;
212
228 int reference_value_size() const;
229
241 std::span<const std::size_t> reference_value_shape() const;
242
244 const std::vector<std::vector<std::vector<int>>>&
245 entity_dofs() const noexcept;
246
249 const std::vector<std::vector<std::vector<int>>>&
250 entity_closure_dofs() const noexcept;
251
253 bool symmetric() const;
254
267 void tabulate(std::span<geometry_type> values,
268 std::span<const geometry_type> X,
269 std::array<std::size_t, 2> shape, int order) const;
270
281 std::pair<std::vector<geometry_type>, std::array<std::size_t, 4>>
282 tabulate(std::span<const geometry_type> X, std::array<std::size_t, 2> shape,
283 int order) const;
284
287 int num_sub_elements() const noexcept;
288
296 bool is_mixed() const noexcept;
297
299 const std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>&
300 sub_elements() const noexcept;
301
303 std::shared_ptr<const FiniteElement<geometry_type>>
304 extract_sub_element(const std::vector<int>& component) const;
305
308 const basix::FiniteElement<geometry_type>& basix_element() const;
309
311 basix::maps::type map_type() const;
312
319 bool interpolation_ident() const noexcept;
320
325 bool map_ident() const noexcept;
326
337 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
338 interpolation_points() const;
339
349 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
351
364 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
366
380 bool needs_dof_transformations() const noexcept;
381
396 bool needs_dof_permutations() const noexcept;
397
437 template <typename U>
438 std::function<void(std::span<U>, std::span<const std::uint32_t>, std::int32_t,
439 int)>
440 dof_transformation_fn(doftransform ttype, bool scalar_element = false) const
441 {
443 return nullptr;
444
445 if (!_sub_elements.empty())
446 {
447 if (!_reference_value_shape) // Mixed element
448 {
449 std::vector<std::function<void(
450 std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)>>
451 sub_element_fns;
452 std::vector<int> dims;
453 sub_element_fns.reserve(_sub_elements.size());
454 dims.reserve(_sub_elements.size());
455 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
456 {
457 sub_element_fns.push_back(
458 _sub_elements[i]->template dof_transformation_fn<U>(ttype));
459 dims.push_back(_sub_elements[i]->space_dimension());
460 }
461
462 return [dims = std::move(dims),
463 sub_element_fns = std::move(sub_element_fns)](
464 std::span<U> data, std::span<const std::uint32_t> cell_info,
465 std::int32_t cell, int block_size)
466 {
467 std::size_t offset = 0;
468 for (std::size_t e = 0; e < sub_element_fns.size(); ++e)
469 {
470 const std::size_t width = dims[e] * block_size;
471 if (sub_element_fns[e])
472 {
473 sub_element_fns[e](data.subspan(offset, width), cell_info, cell,
474 block_size);
475 }
476 offset += width;
477 }
478 };
479 }
480 else if (!scalar_element)
481 {
482 // Blocked element
483 std::function<void(std::span<U>, std::span<const std::uint32_t>,
484 std::int32_t, int)>
485 sub_fn
486 = _sub_elements.front()->template dof_transformation_fn<U>(ttype);
487 assert(sub_fn); // Consistent with needs_dof_transformations() above
488 const int ebs = _bs;
489 return [ebs, sub_fn = std::move(sub_fn)](
490 std::span<U> data, std::span<const std::uint32_t> cell_info,
491 std::int32_t cell, int data_block_size)
492 { sub_fn(data, cell_info, cell, ebs * data_block_size); };
493 }
494 }
495
496 switch (ttype)
497 {
499 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
500 std::int32_t cell, int block_size)
501 { Tt_inv_apply(data, cell_info[cell], block_size); };
503 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
504 std::int32_t cell, int block_size)
505 { Tt_apply(data, cell_info[cell], block_size); };
507 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
508 std::int32_t cell, int block_size)
509 { Tinv_apply(data, cell_info[cell], block_size); };
511 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
512 std::int32_t cell, int block_size)
513 { T_apply(data, cell_info[cell], block_size); };
514 default:
515 throw std::invalid_argument("Unknown transformation type");
516 }
517 }
518
542 template <typename U>
543 std::function<void(std::span<U>, std::span<const std::uint32_t>, std::int32_t,
544 int)>
546 bool scalar_element = false) const
547 {
549 return nullptr;
550 else if (!_sub_elements.empty())
551 {
552 if (!_reference_value_shape) // Mixed element
553 {
554 std::vector<std::function<void(
555 std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)>>
556 sub_element_fns;
557 std::vector<int> dims;
558 sub_element_fns.reserve(_sub_elements.size());
559 dims.reserve(_sub_elements.size());
560 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
561 {
562 sub_element_fns.push_back(
563 _sub_elements[i]->template dof_transformation_right_fn<U>(ttype));
564 dims.push_back(_sub_elements[i]->space_dimension());
565 }
566
567 return [dims = std::move(dims),
568 sub_element_fns = std::move(sub_element_fns)](
569 std::span<U> data, std::span<const std::uint32_t> cell_info,
570 std::int32_t cell, int block_size)
571 {
572 std::size_t offset = 0;
573 for (std::size_t e = 0; e < sub_element_fns.size(); ++e)
574 {
575 if (sub_element_fns[e])
576 {
577 sub_element_fns[e](data.subspan(offset, data.size() - offset),
578 cell_info, cell, block_size);
579 }
580 offset += dims[e];
581 }
582 };
583 }
584 else if (!scalar_element)
585 {
586 // Blocked element
587 // The transformation from the left can be used here as blocked
588 // elements use xyzxyzxyz ordering, and so applying the DOF
589 // transformation from the right is equivalent to applying the DOF
590 // transformation from the left to data using xxxyyyzzz ordering
591 std::function<void(std::span<U>, std::span<const std::uint32_t>,
592 std::int32_t, int)>
593 sub_fn
594 = _sub_elements.front()->template dof_transformation_fn<U>(ttype);
595 assert(sub_fn); // Consistent with needs_dof_transformations() above
596 return [this, sub_fn = std::move(sub_fn)](
597 std::span<U> data, std::span<const std::uint32_t> cell_info,
598 std::int32_t cell, int data_block_size)
599 {
600 const int ebs = block_size();
601 const std::size_t dof_count = data.size() / data_block_size;
602 for (int block = 0; block < data_block_size; ++block)
603 {
604 sub_fn(data.subspan(block * dof_count, dof_count), cell_info, cell,
605 ebs);
606 }
607 };
608 }
609 }
610
611 switch (ttype)
612 {
614 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
615 std::int32_t cell, int n)
616 { Tt_inv_apply_right(data, cell_info[cell], n); };
618 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
619 std::int32_t cell, int n)
620 { Tt_apply_right(data, cell_info[cell], n); };
622 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
623 std::int32_t cell, int n)
624 { Tinv_apply_right(data, cell_info[cell], n); };
626 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
627 std::int32_t cell, int n)
628 { T_apply_right(data, cell_info[cell], n); };
629 default:
630 throw std::invalid_argument("Unknown transformation type");
631 }
632 }
633
670 template <typename U>
671 void T_apply(std::span<U> data, std::uint32_t cell_permutation, int n) const
672 {
673 assert(_element);
674 _element->T_apply(data, n, cell_permutation);
675 }
676
686 template <typename U>
687 void Tt_inv_apply(std::span<U> data, std::uint32_t cell_permutation,
688 int n) const
689 {
690 assert(_element);
691 _element->Tt_inv_apply(data, n, cell_permutation);
692 }
693
703 template <typename U>
704 void Tt_apply(std::span<U> data, std::uint32_t cell_permutation, int n) const
705 {
706 assert(_element);
707 _element->Tt_apply(data, n, cell_permutation);
708 }
709
718 template <typename U>
719 void Tinv_apply(std::span<U> data, std::uint32_t cell_permutation,
720 int n) const
721 {
722 assert(_element);
723 _element->Tinv_apply(data, n, cell_permutation);
724 }
725
734 template <typename U>
735 void T_apply_right(std::span<U> data, std::uint32_t cell_permutation,
736 int n) const
737 {
738 assert(_element);
739 _element->T_apply_right(data, n, cell_permutation);
740 }
741
751 template <typename U>
752 void Tinv_apply_right(std::span<U> data, std::uint32_t cell_permutation,
753 int n) const
754 {
755 assert(_element);
756 _element->Tinv_apply_right(data, n, cell_permutation);
757 }
758
768 template <typename U>
769 void Tt_apply_right(std::span<U> data, std::uint32_t cell_permutation,
770 int n) const
771 {
772 assert(_element);
773 _element->Tt_apply_right(data, n, cell_permutation);
774 }
775
785 template <typename U>
786 void Tt_inv_apply_right(std::span<U> data, std::uint32_t cell_permutation,
787 int n) const
788 {
789 assert(_element);
790 _element->Tt_inv_apply_right(data, n, cell_permutation);
791 }
792
809 void permute(std::span<std::int32_t> doflist,
810 std::uint32_t cell_permutation) const;
811
828 void permute_inv(std::span<std::int32_t> doflist,
829 std::uint32_t cell_permutation) const;
830
845 std::function<void(std::span<std::int32_t>, std::uint32_t)>
846 dof_permutation_fn(bool inverse = false, bool scalar_element = false) const;
847
848private:
849 // Value shape. For blocked elements this is larger than
850 // _reference_value_shape. For non-blocked 'primal' elements it is
851 // equal to _reference_value_shape. For mixed elements, it is
852 // std::nullopt.
853 std::optional<std::vector<std::size_t>> _value_shape;
854
855 // Block size for BlockedElements. This gives the number of DOFs
856 // co-located at each dof 'point'.
857 int _bs;
858
859 // Element cell shape
860 mesh::CellType _cell_type;
861
862 // Element signature
863 std::string _signature;
864
865 // Dimension of the finite element space (accounting for any blocking)
866 int _space_dim;
867
868 // List of sub-elements (if any)
869 std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>
870 _sub_elements;
871
872 // Value space shape, e.g. {} for a scalar, {3, 3} for a tensor in 3D.
873 // For a mixed element it is std::nullopt.
874 std::optional<std::vector<std::size_t>> _reference_value_shape;
875
876 // Basix Element (nullptr for mixed elements)
877 std::unique_ptr<basix::FiniteElement<geometry_type>> _element;
878
879 // Indicate whether this element represents a symmetric 2-tensor
880 bool _symmetric;
881
882 // Indicate whether the element needs permutations or transformations
883 bool _needs_dof_permutations;
884 bool _needs_dof_transformations;
885
886 std::vector<std::vector<std::vector<int>>> _entity_dofs;
887 std::vector<std::vector<std::vector<int>>> _entity_closure_dofs;
888
889 // Quadrature points of a quadrature element (0 dimensional array for
890 // all elements except quadrature elements)
891 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>> _points;
892};
893
894} // namespace dolfinx::fem
Definition CoordinateElement.h:26
FiniteElement(const basix::FiniteElement< geometry_type > &element, const std::optional< std::vector< std::size_t > > &value_shape=std::nullopt, bool symmetric=false)
Create a finite element from a Basix finite element.
Definition FiniteElement.cpp:115
bool symmetric() const
Does the element represent a symmetric 2-tensor?
Definition FiniteElement.cpp:357
FiniteElement & operator=(const FiniteElement &element)=delete
Copy assignment.
const std::vector< std::shared_ptr< const FiniteElement< geometry_type > > > & sub_elements() const noexcept
Get subelements (if any).
Definition FiniteElement.cpp:400
void Tinv_apply(std::span< U > data, std::uint32_t cell_permutation, int n) const
Apply the inverse of the operator applied by T_apply().
Definition FiniteElement.h:719
std::span< const std::size_t > value_shape() const
Value shape of the finite element field.
Definition FiniteElement.cpp:313
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > create_interpolation_operator(const FiniteElement &from) const
Create a matrix that maps degrees of freedom from one element to this element (interpolation).
Definition FiniteElement.cpp:500
void T_apply(std::span< U > data, std::uint32_t cell_permutation, int n) const
Transform basis functions from the reference element ordering and orientation to the globally consist...
Definition FiniteElement.h:671
basix::maps::type map_type() const
Get the map type used by the element.
Definition FiniteElement.cpp:429
int space_dimension() const noexcept
Dimension of the finite element function space (the number of degrees-of-freedom for the element).
Definition FiniteElement.cpp:295
void tabulate(std::span< geometry_type > values, std::span< const geometry_type > X, std::array< std::size_t, 2 > shape, int order) const
Evaluate derivatives of the basis functions up to given order at points in the reference cell.
Definition FiniteElement.cpp:369
void Tt_inv_apply_right(std::span< U > data, std::uint32_t cell_permutation, int n) const
Right(post)-apply the transpose inverse of the operator applied by T_apply().
Definition FiniteElement.h:786
FiniteElement & operator=(FiniteElement &&element)=default
Move assignment.
bool needs_dof_transformations() const noexcept
Check if DOF transformations are needed for this element.
Definition FiniteElement.cpp:543
FiniteElement(const FiniteElement &element)=delete
Copy constructor.
void Tt_inv_apply(std::span< U > data, std::uint32_t cell_permutation, int n) const
Apply the inverse transpose of the operator applied by T_apply().
Definition FiniteElement.h:687
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > interpolation_points() const
Points on the reference cell at which an expression needs to be evaluated in order to interpolate the...
Definition FiniteElement.cpp:468
std::shared_ptr< const FiniteElement< geometry_type > > extract_sub_element(const std::vector< int > &component) const
Extract sub finite element for component.
Definition FiniteElement.cpp:407
void T_apply_right(std::span< U > data, std::uint32_t cell_permutation, int n) const
Right(post)-apply the operator applied by T_apply().
Definition FiniteElement.h:735
bool needs_dof_permutations() const noexcept
Check if DOF permutations are needed for this element.
Definition FiniteElement.cpp:549
const std::string & signature() const noexcept
String identifying the finite element.
Definition FiniteElement.cpp:289
const std::vector< std::vector< std::vector< int > > > & entity_dofs() const noexcept
Local DOFs associated with each sub-entity of the cell.
Definition FiniteElement.cpp:344
bool is_mixed() const noexcept
Check if element is a mixed element.
Definition FiniteElement.cpp:393
int reference_value_size() const
Value size of the base (non-blocked) finite element field.
Definition FiniteElement.cpp:322
int value_size() const
Value size of the finite element field.
Definition FiniteElement.cpp:301
std::function< void(std::span< U >, std::span< const std::uint32_t >, std::int32_t, int)> dof_transformation_fn(doftransform ttype, bool scalar_element=false) const
Return a function that applies a DOF transformation operator to some data (see T_apply()).
Definition FiniteElement.h:440
bool operator!=(const FiniteElement &e) const
Check if two elements are not equivalent.
Definition FiniteElement.cpp:277
~FiniteElement()=default
Destructor.
T geometry_type
Geometry type of the Mesh that the FunctionSpace is defined on.
Definition FiniteElement.h:65
const basix::FiniteElement< geometry_type > & basix_element() const
Return underlying Basix element (if it exists).
Definition FiniteElement.cpp:417
std::function< void(std::span< std::int32_t >, std::uint32_t)> dof_permutation_fn(bool inverse=false, bool scalar_element=false) const
Return a function that applies a degree-of-freedom permutation to some data.
FiniteElement(FiniteElement &&element)=default
Move constructor.
int num_sub_elements() const noexcept
Number of sub elements (for a mixed or blocked element).
Definition FiniteElement.cpp:387
void Tt_apply(std::span< U > data, std::uint32_t cell_permutation, int n) const
Apply the transpose of the operator applied by T_apply().
Definition FiniteElement.h:704
const std::vector< std::vector< std::vector< int > > > & entity_closure_dofs() const noexcept
Local DOFs associated with the closure of each sub-entity of the cell.
Definition FiniteElement.cpp:351
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > interpolation_operator() const
Definition FiniteElement.cpp:487
int block_size() const noexcept
Block size of the finite element function space.
Definition FiniteElement.cpp:363
std::span< const std::size_t > reference_value_shape() const
Value shape of the base (non-blocked) finite element field.
Definition FiniteElement.cpp:334
void Tt_apply_right(std::span< U > data, std::uint32_t cell_permutation, int n) const
Right(post)-apply the transpose of the operator applied by T_apply().
Definition FiniteElement.h:769
std::function< void(std::span< U >, std::span< const std::uint32_t >, std::int32_t, int)> dof_transformation_right_fn(doftransform ttype, bool scalar_element=false) const
Return a function that applies DOF transformation to some transposed data (see T_apply_right()).
Definition FiniteElement.h:545
mesh::CellType cell_type() const noexcept
Cell shape that the element is defined on.
Definition FiniteElement.cpp:283
bool interpolation_ident() const noexcept
Definition FiniteElement.cpp:455
void Tinv_apply_right(std::span< U > data, std::uint32_t cell_permutation, int n) const
Right(post)-apply the inverse of the operator applied by T_apply().
Definition FiniteElement.h:752
bool operator==(const FiniteElement &e) const
Check if two elements are equivalent.
Definition FiniteElement.cpp:265
bool map_ident() const noexcept
Definition FiniteElement.cpp:441
Finite element method functionality.
Definition assemble_expression_impl.h:24
BasixElementData(U element, V bs, W symmetry) -> BasixElementData< typename std::remove_cvref< U >::type::scalar_type >
Type deduction helper.
doftransform
DOF transformation type.
Definition FiniteElement.h:28
@ transpose
Transpose.
Definition FiniteElement.h:30
@ inverse_transpose
Transpose inverse.
Definition FiniteElement.h:32
@ inverse
Inverse.
Definition FiniteElement.h:31
@ standard
Standard.
Definition FiniteElement.h:29
@ cell
Cell.
Definition Form.h:42
CellType
Cell type identifier.
Definition cell_types.h:22
Basix element holder.
Definition FiniteElement.h:42
std::optional< std::vector< std::size_t > > value_shape
Value shape. Can only be set for scalar element.
Definition FiniteElement.h:46
bool symmetry
Definition FiniteElement.h:47
std::reference_wrapper< const basix::FiniteElement< T > > element
Finite element.
Definition FiniteElement.h:44