DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
FiniteElement.h
1// Copyright (C) 2020-2024 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 <concepts>
13#include <cstdint>
14#include <dolfinx/mesh/cell_types.h>
15#include <functional>
16#include <memory>
17#include <optional>
18#include <span>
19#include <utility>
20#include <vector>
21
22namespace dolfinx::fem
23{
25enum class doftransform : std::uint8_t
26{
29 inverse = 2,
31};
32
35template <std::floating_point T>
37{
38 std::reference_wrapper<const basix::FiniteElement<T>>
40 std::optional<std::vector<std::size_t>> value_shape
41 = std::nullopt;
42 bool symmetry = false;
44};
45
47template <typename U, typename V, typename W>
48BasixElementData(U element, V bs, W symmetry)
50
55template <std::floating_point T>
57{
58public:
60 using geometry_type = T;
61
71 const std::optional<std::vector<std::size_t>>& value_shape
72 = std::nullopt,
73 bool symmetric = false);
74
84
103 const std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>&
104 elements);
105
112 FiniteElement(mesh::CellType cell_type, std::span<const geometry_type> points,
113 std::array<std::size_t, 2> pshape,
114 std::vector<std::size_t> value_shape = {},
115 bool symmetric = false);
116
118 FiniteElement(const FiniteElement& element) = delete;
119
121 FiniteElement(FiniteElement&& element) = default;
122
124 ~FiniteElement() = default;
125
127 FiniteElement& operator=(const FiniteElement& element) = delete;
128
130 FiniteElement& operator=(FiniteElement&& element) = default;
131
136 bool operator==(const FiniteElement& e) const;
137
142 bool operator!=(const FiniteElement& e) const;
143
145 mesh::CellType cell_type() const noexcept;
146
153 std::string signature() const noexcept;
154
162 int space_dimension() const noexcept;
163
174 int block_size() const noexcept;
175
195 int value_size() const;
196
206 std::span<const std::size_t> value_shape() const;
207
223 int reference_value_size() const;
224
236 std::span<const std::size_t> reference_value_shape() const;
237
239 const std::vector<std::vector<std::vector<int>>>&
240 entity_dofs() const noexcept;
241
244 const std::vector<std::vector<std::vector<int>>>&
245 entity_closure_dofs() const noexcept;
246
248 bool symmetric() const;
249
262 void tabulate(std::span<geometry_type> values,
263 std::span<const geometry_type> X,
264 std::array<std::size_t, 2> shape, int order) const;
265
276 std::pair<std::vector<geometry_type>, std::array<std::size_t, 4>>
277 tabulate(std::span<const geometry_type> X, std::array<std::size_t, 2> shape,
278 int order) const;
279
282 int num_sub_elements() const noexcept;
283
291 bool is_mixed() const noexcept;
292
294 const std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>&
295 sub_elements() const noexcept;
296
298 std::shared_ptr<const FiniteElement<geometry_type>>
299 extract_sub_element(const std::vector<int>& component) const;
300
303 const basix::FiniteElement<geometry_type>& basix_element() const;
304
306 basix::maps::type map_type() const;
307
314 bool interpolation_ident() const noexcept;
315
320 bool map_ident() const noexcept;
321
332 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
333 interpolation_points() const;
334
344 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
346
359 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
361
375 bool needs_dof_transformations() const noexcept;
376
391 bool needs_dof_permutations() const noexcept;
392
432 template <typename U>
433 std::function<void(std::span<U>, std::span<const std::uint32_t>, std::int32_t,
434 int)>
435 dof_transformation_fn(doftransform ttype, bool scalar_element = false) const
436 {
438 {
439 // If no permutation needed, return function that does nothing
440 return [](std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)
441 {
442 // Do nothing
443 };
444 }
445
446 if (!_sub_elements.empty())
447 {
448 if (!_reference_value_shape) // Mixed element
449 {
450 std::vector<std::function<void(
451 std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)>>
452 sub_element_fns;
453 std::vector<int> dims;
454 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
455 {
456 sub_element_fns.push_back(
457 _sub_elements[i]->template dof_transformation_fn<U>(ttype));
458 dims.push_back(_sub_elements[i]->space_dimension());
459 }
460
461 return [dims = std::move(dims),
462 sub_element_fns = std::move(sub_element_fns)](
463 std::span<U> data, std::span<const std::uint32_t> cell_info,
464 std::int32_t cell, int block_size)
465 {
466 std::size_t offset = 0;
467 for (std::size_t e = 0; e < sub_element_fns.size(); ++e)
468 {
469 const std::size_t width = dims[e] * block_size;
470 sub_element_fns[e](data.subspan(offset, width), cell_info, cell,
471 block_size);
472 offset += width;
473 }
474 };
475 }
476 else if (!scalar_element)
477 {
478 // Blocked element
479 std::function<void(std::span<U>, std::span<const std::uint32_t>,
480 std::int32_t, int)>
481 sub_fn
482 = _sub_elements.front()->template dof_transformation_fn<U>(ttype);
483 const int ebs = _bs;
484 return [ebs, sub_fn = std::move(sub_fn)](
485 std::span<U> data, std::span<const std::uint32_t> cell_info,
486 std::int32_t cell, int data_block_size)
487 { sub_fn(data, cell_info, cell, ebs * data_block_size); };
488 }
489 }
490
491 switch (ttype)
492 {
494 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
495 std::int32_t cell, int block_size)
496 { Tt_inv_apply(data, cell_info[cell], block_size); };
498 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
499 std::int32_t cell, int block_size)
500 { Tt_apply(data, cell_info[cell], block_size); };
502 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
503 std::int32_t cell, int block_size)
504 { Tinv_apply(data, cell_info[cell], block_size); };
506 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
507 std::int32_t cell, int block_size)
508 { T_apply(data, cell_info[cell], block_size); };
509 default:
510 throw std::runtime_error("Unknown transformation type");
511 }
512 }
513
537 template <typename U>
538 std::function<void(std::span<U>, std::span<const std::uint32_t>, std::int32_t,
539 int)>
541 bool scalar_element = false) const
542 {
544 {
545 // If no permutation needed, return function that does nothing
546 return [](std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)
547 {
548 // Do nothing
549 };
550 }
551 else if (!_sub_elements.empty())
552 {
553 if (!_reference_value_shape) // Mixed element
554 {
555 std::vector<std::function<void(
556 std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)>>
557 sub_element_fns;
558 std::vector<int> dims;
559 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
560 {
561 sub_element_fns.push_back(
562 _sub_elements[i]->template dof_transformation_right_fn<U>(ttype));
563 dims.push_back(_sub_elements[i]->space_dimension());
564 }
565
566 return [dims = std::move(dims),
567 sub_element_fns = std::move(sub_element_fns)](
568 std::span<U> data, std::span<const std::uint32_t> cell_info,
569 std::int32_t cell, int block_size)
570 {
571 std::size_t offset = 0;
572 for (std::size_t e = 0; e < sub_element_fns.size(); ++e)
573 {
574 sub_element_fns[e](data.subspan(offset, data.size() - offset),
575 cell_info, cell, block_size);
576 offset += dims[e];
577 }
578 };
579 }
580 else if (!scalar_element)
581 {
582 // Blocked element
583 // The transformation from the left can be used here as blocked
584 // elements use xyzxyzxyz ordering, and so applying the DOF
585 // transformation from the right is equivalent to applying the DOF
586 // transformation from the left to data using xxxyyyzzz ordering
587 std::function<void(std::span<U>, std::span<const std::uint32_t>,
588 std::int32_t, int)>
589 sub_fn
590 = _sub_elements.front()->template dof_transformation_fn<U>(ttype);
591 return [this, sub_fn = std::move(sub_fn)](
592 std::span<U> data, std::span<const std::uint32_t> cell_info,
593 std::int32_t cell, int data_block_size)
594 {
595 const int ebs = block_size();
596 const std::size_t dof_count = data.size() / data_block_size;
597 for (int block = 0; block < data_block_size; ++block)
598 {
599 sub_fn(data.subspan(block * dof_count, dof_count), cell_info, cell,
600 ebs);
601 }
602 };
603 }
604 }
605
606 switch (ttype)
607 {
609 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
610 std::int32_t cell, int n)
611 { Tt_inv_apply_right(data, cell_info[cell], n); };
613 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
614 std::int32_t cell, int n)
615 { Tt_apply_right(data, cell_info[cell], n); };
617 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
618 std::int32_t cell, int n)
619 { Tinv_apply_right(data, cell_info[cell], n); };
621 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
622 std::int32_t cell, int n)
623 { T_apply_right(data, cell_info[cell], n); };
624 default:
625 throw std::runtime_error("Unknown transformation type");
626 }
627 }
628
665 template <typename U>
666 void T_apply(std::span<U> data, std::uint32_t cell_permutation, int n) const
667 {
668 assert(_element);
669 _element->T_apply(data, n, cell_permutation);
670 }
671
681 template <typename U>
682 void Tt_inv_apply(std::span<U> data, std::uint32_t cell_permutation,
683 int n) const
684 {
685 assert(_element);
686 _element->Tt_inv_apply(data, n, cell_permutation);
687 }
688
698 template <typename U>
699 void Tt_apply(std::span<U> data, std::uint32_t cell_permutation, int n) const
700 {
701 assert(_element);
702 _element->Tt_apply(data, n, cell_permutation);
703 }
704
713 template <typename U>
714 void Tinv_apply(std::span<U> data, std::uint32_t cell_permutation,
715 int n) const
716 {
717 assert(_element);
718 _element->Tinv_apply(data, n, cell_permutation);
719 }
720
729 template <typename U>
730 void T_apply_right(std::span<U> data, std::uint32_t cell_permutation,
731 int n) const
732 {
733 assert(_element);
734 _element->T_apply_right(data, n, cell_permutation);
735 }
736
746 template <typename U>
747 void Tinv_apply_right(std::span<U> data, std::uint32_t cell_permutation,
748 int n) const
749 {
750 assert(_element);
751 _element->Tinv_apply_right(data, n, cell_permutation);
752 }
753
763 template <typename U>
764 void Tt_apply_right(std::span<U> data, std::uint32_t cell_permutation,
765 int n) const
766 {
767 assert(_element);
768 _element->Tt_apply_right(data, n, cell_permutation);
769 }
770
780 template <typename U>
781 void Tt_inv_apply_right(std::span<U> data, std::uint32_t cell_permutation,
782 int n) const
783 {
784 assert(_element);
785 _element->Tt_inv_apply_right(data, n, cell_permutation);
786 }
787
804 void permute(std::span<std::int32_t> doflist,
805 std::uint32_t cell_permutation) const;
806
823 void permute_inv(std::span<std::int32_t> doflist,
824 std::uint32_t cell_permutation) const;
825
840 std::function<void(std::span<std::int32_t>, std::uint32_t)>
841 dof_permutation_fn(bool inverse = false, bool scalar_element = false) const;
842
843private:
844 // Value shape. For blocked elements this is larger than
845 // _reference_value_shape. For non-blocked 'primal' elements it is
846 // equal to _reference_value_shape. For mixed elements, it is
847 // std::nullopt.
848 std::optional<std::vector<std::size_t>> _value_shape;
849
850 // Block size for BlockedElements. This gives the number of DOFs
851 // co-located at each dof 'point'.
852 int _bs;
853
854 // Element cell shape
855 mesh::CellType _cell_type;
856
857 // Element signature
858 std::string _signature;
859
860 // Dimension of the finite element space (accounting for any blocking)
861 int _space_dim;
862
863 // List of sub-elements (if any)
864 std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>
865 _sub_elements;
866
867 // Value space shape, e.g. {} for a scalar, {3, 3} for a tensor in 3D.
868 // For a mixed element it is std::nullopt.
869 std::optional<std::vector<std::size_t>> _reference_value_shape;
870
871 // Basix Element (nullptr for mixed elements)
872 std::unique_ptr<basix::FiniteElement<geometry_type>> _element;
873
874 // Indicate whether this element represents a symmetric 2-tensor
875 bool _symmetric;
876
877 // Indicate whether the element needs permutations or transformations
878 bool _needs_dof_permutations;
879 bool _needs_dof_transformations;
880
881 std::vector<std::vector<std::vector<int>>> _entity_dofs;
882 std::vector<std::vector<std::vector<int>>> _entity_closure_dofs;
883
884 // Quadrature points of a quadrature element (0 dimensional array for
885 // all elements except quadrature elements)
886 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>> _points;
887};
888
889} // 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:112
bool symmetric() const
Does the element represent a symmetric 2-tensor?
Definition FiniteElement.cpp:353
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:396
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:714
std::span< const std::size_t > value_shape() const
Value shape of the finite element field.
Definition FiniteElement.cpp:309
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:496
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:666
basix::maps::type map_type() const
Get the map type used by the element.
Definition FiniteElement.cpp:425
int space_dimension() const noexcept
Dimension of the finite element function space (the number of degrees-of-freedom for the element).
Definition FiniteElement.cpp:291
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:365
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:781
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:539
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:682
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:464
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:403
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:730
std::string signature() const noexcept
String identifying the finite element.
Definition FiniteElement.cpp:285
bool needs_dof_permutations() const noexcept
Check if DOF permutations are needed for this element.
Definition FiniteElement.cpp:545
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:340
bool is_mixed() const noexcept
Check if element is a mixed element.
Definition FiniteElement.cpp:389
int reference_value_size() const
Value size of the base (non-blocked) finite element field.
Definition FiniteElement.cpp:318
int value_size() const
Value size of the finite element field.
Definition FiniteElement.cpp:297
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:435
bool operator!=(const FiniteElement &e) const
Check if two elements are not equivalent.
Definition FiniteElement.cpp:273
~FiniteElement()=default
Destructor.
T geometry_type
Geometry type of the Mesh that the FunctionSpace is defined on.
Definition FiniteElement.h:60
const basix::FiniteElement< geometry_type > & basix_element() const
Return underlying Basix element (if it exists).
Definition FiniteElement.cpp:413
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:383
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:699
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:347
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > interpolation_operator() const
Definition FiniteElement.cpp:483
int block_size() const noexcept
Block size of the finite element function space.
Definition FiniteElement.cpp:359
std::span< const std::size_t > reference_value_shape() const
Value shape of the base (non-blocked) finite element field.
Definition FiniteElement.cpp:330
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:764
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:540
mesh::CellType cell_type() const noexcept
Cell shape that the element is defined on.
Definition FiniteElement.cpp:279
bool interpolation_ident() const noexcept
Definition FiniteElement.cpp:451
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:747
bool operator==(const FiniteElement &e) const
Check if two elements are equivalent.
Definition FiniteElement.cpp:261
bool map_ident() const noexcept
Definition FiniteElement.cpp:437
Finite element method functionality.
Definition assemble_expression_impl.h:23
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:26
@ transpose
Transpose.
Definition FiniteElement.h:28
@ inverse_transpose
Transpose inverse.
Definition FiniteElement.h:30
@ inverse
Inverse.
Definition FiniteElement.h:29
@ standard
Standard.
Definition FiniteElement.h:27
@ cell
Cell.
Definition Form.h:42
CellType
Cell type identifier.
Definition cell_types.h:22
Basix element holder.
Definition FiniteElement.h:37
std::optional< std::vector< std::size_t > > value_shape
Value shape. Can only be set for scalar element.
Definition FiniteElement.h:41
bool symmetry
Definition FiniteElement.h:42
std::reference_wrapper< const basix::FiniteElement< T > > element
Finite element.
Definition FiniteElement.h:39