DOLFINx 0.8.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
FiniteElement.h
1// Copyright (C) 2020-2021 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 <span>
18#include <utility>
19#include <vector>
20
21struct ufcx_finite_element;
22
23namespace dolfinx::fem
24{
26enum class doftransform
27{
28 standard = 0,
29 transpose = 1,
30 inverse = 2,
32};
33
38template <std::floating_point T>
40{
41public:
43 using geometry_type = T;
44
47 explicit FiniteElement(const ufcx_finite_element& e);
48
54 const std::size_t block_size, const bool symmetric = false);
55
57 FiniteElement(const FiniteElement& element) = delete;
58
60 FiniteElement(FiniteElement&& element) = default;
61
63 ~FiniteElement() = default;
64
66 FiniteElement& operator=(const FiniteElement& element) = delete;
67
69 FiniteElement& operator=(FiniteElement&& element) = default;
70
75 bool operator==(const FiniteElement& e) const;
76
81 bool operator!=(const FiniteElement& e) const;
82
89 std::string signature() const noexcept;
90
93 mesh::CellType cell_shape() const noexcept;
94
98 int space_dimension() const noexcept;
99
104 int block_size() const noexcept;
105
109 int reference_value_size() const;
110
112 std::span<const std::size_t> reference_value_shape() const;
113
115 bool symmetric() const;
116
128 void tabulate(std::span<geometry_type> values,
129 std::span<const geometry_type> X,
130 std::array<std::size_t, 2> shape, int order) const;
131
141 std::pair<std::vector<geometry_type>, std::array<std::size_t, 4>>
142 tabulate(std::span<const geometry_type> X, std::array<std::size_t, 2> shape,
143 int order) const;
144
147 int num_sub_elements() const noexcept;
148
156 bool is_mixed() const noexcept;
157
159 const std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>&
160 sub_elements() const noexcept;
161
163 std::shared_ptr<const FiniteElement<geometry_type>>
164 extract_sub_element(const std::vector<int>& component) const;
165
168 const basix::FiniteElement<geometry_type>& basix_element() const;
169
171 basix::maps::type map_type() const;
172
179 bool interpolation_ident() const noexcept;
180
185 bool map_ident() const noexcept;
186
197 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
198 interpolation_points() const;
199
209 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
211
224 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>>
226
240 bool needs_dof_transformations() const noexcept;
241
256 bool needs_dof_permutations() const noexcept;
257
297 template <typename U>
298 std::function<void(std::span<U>, std::span<const std::uint32_t>, std::int32_t,
299 int)>
300 dof_transformation_fn(doftransform ttype, bool scalar_element = false) const
301 {
303 {
304 // If no permutation needed, return function that does nothing
305 return [](std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)
306 {
307 // Do nothing
308 };
309 }
310
311 if (!_sub_elements.empty())
312 {
313 if (_is_mixed)
314 {
315 // Mixed element
316 std::vector<std::function<void(
317 std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)>>
318 sub_element_functions;
319 std::vector<int> dims;
320 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
321 {
322 sub_element_functions.push_back(
323 _sub_elements[i]->template dof_transformation_fn<U>(ttype));
324 dims.push_back(_sub_elements[i]->space_dimension());
325 }
326
327 return [dims, sub_element_functions](
328 std::span<U> data, std::span<const std::uint32_t> cell_info,
329 std::int32_t cell, int block_size)
330 {
331 std::size_t offset = 0;
332 for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
333 {
334 const std::size_t width = dims[e] * block_size;
335 sub_element_functions[e](data.subspan(offset, width), cell_info,
337 offset += width;
338 }
339 };
340 }
341 else if (!scalar_element)
342 {
343 // Blocked element
344 std::function<void(std::span<U>, std::span<const std::uint32_t>,
345 std::int32_t, int)>
346 sub_function
347 = _sub_elements[0]->template dof_transformation_fn<U>(ttype);
348 const int ebs = _bs;
349 return [ebs, sub_function](std::span<U> data,
350 std::span<const std::uint32_t> cell_info,
351 std::int32_t cell, int data_block_size)
352 { sub_function(data, cell_info, cell, ebs * data_block_size); };
353 }
354 }
355
356 switch (ttype)
357 {
359 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
360 std::int32_t cell, int block_size)
361 { Tt_inv_apply(data, cell_info[cell], block_size); };
363 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
364 std::int32_t cell, int block_size)
365 { Tt_apply(data, cell_info[cell], block_size); };
367 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
368 std::int32_t cell, int block_size)
369 { Tinv_apply(data, cell_info[cell], block_size); };
371 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
372 std::int32_t cell, int block_size)
373 { T_apply(data, cell_info[cell], block_size); };
374 default:
375 throw std::runtime_error("Unknown transformation type");
376 }
377 }
378
402 template <typename U>
403 std::function<void(std::span<U>, std::span<const std::uint32_t>, std::int32_t,
404 int)>
406 bool scalar_element = false) const
407 {
409 {
410 // If no permutation needed, return function that does nothing
411 return [](std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)
412 {
413 // Do nothing
414 };
415 }
416 else if (_sub_elements.size() != 0)
417 {
418 if (_is_mixed)
419 {
420 // Mixed element
421 std::vector<std::function<void(
422 std::span<U>, std::span<const std::uint32_t>, std::int32_t, int)>>
423 sub_element_functions;
424 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
425 {
426 sub_element_functions.push_back(
427 _sub_elements[i]->template dof_transformation_right_fn<U>(ttype));
428 }
429
430 return [this, sub_element_functions](
431 std::span<U> data, std::span<const std::uint32_t> cell_info,
432 std::int32_t cell, int block_size)
433 {
434 std::size_t offset = 0;
435 for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
436 {
437 sub_element_functions[e](data.subspan(offset, data.size() - offset),
438 cell_info, cell, block_size);
439 offset += _sub_elements[e]->space_dimension();
440 }
441 };
442 }
443 else if (!scalar_element)
444 {
445 // Blocked element
446 // The transformation from the left can be used here as blocked
447 // elements use xyzxyzxyz ordering, and so applying the DOF
448 // transformation from the right is equivalent to applying the DOF
449 // transformation from the left to data using xxxyyyzzz ordering
450 std::function<void(std::span<U>, std::span<const std::uint32_t>,
451 std::int32_t, int)>
452 sub_function
453 = _sub_elements[0]->template dof_transformation_fn<U>(ttype);
454 return [this, sub_function](std::span<U> data,
455 std::span<const std::uint32_t> cell_info,
456 std::int32_t cell, int data_block_size)
457 {
458 const int ebs = block_size();
459 const std::size_t dof_count = data.size() / data_block_size;
460 for (int block = 0; block < data_block_size; ++block)
461 {
462 sub_function(data.subspan(block * dof_count, dof_count), cell_info,
463 cell, ebs);
464 }
465 };
466 }
467 }
468
469 switch (ttype)
470 {
472 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
473 std::int32_t cell, int n)
474 { Tt_inv_apply_right(data, cell_info[cell], n); };
476 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
477 std::int32_t cell, int n)
478 { Tt_apply_right(data, cell_info[cell], n); };
480 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
481 std::int32_t cell, int n)
482 { Tinv_apply_right(data, cell_info[cell], n); };
484 return [this](std::span<U> data, std::span<const std::uint32_t> cell_info,
485 std::int32_t cell, int n)
486 { T_apply_right(data, cell_info[cell], n); };
487 default:
488 throw std::runtime_error("Unknown transformation type");
489 }
490 }
491
528 template <typename U>
529 void T_apply(std::span<U> data, std::uint32_t cell_permutation, int n) const
530 {
531 assert(_element);
532 _element->T_apply(data, n, cell_permutation);
533 }
534
544 template <typename U>
545 void Tt_inv_apply(std::span<U> data, std::uint32_t cell_permutation,
546 int n) const
547 {
548 assert(_element);
549 _element->Tt_inv_apply(data, n, cell_permutation);
550 }
551
561 template <typename U>
562 void Tt_apply(std::span<U> data, std::uint32_t cell_permutation, int n) const
563 {
564 assert(_element);
565 _element->Tt_apply(data, n, cell_permutation);
566 }
567
576 template <typename U>
577 void Tinv_apply(std::span<U> data, std::uint32_t cell_permutation,
578 int n) const
579 {
580 assert(_element);
581 _element->Tinv_apply(data, n, cell_permutation);
582 }
583
592 template <typename U>
593 void T_apply_right(std::span<U> data, std::uint32_t cell_permutation,
594 int n) const
595 {
596 assert(_element);
597 _element->T_apply_right(data, n, cell_permutation);
598 }
599
609 template <typename U>
610 void Tinv_apply_right(std::span<U> data, std::uint32_t cell_permutation,
611 int n) const
612 {
613 assert(_element);
614 _element->Tinv_apply_right(data, n, cell_permutation);
615 }
616
626 template <typename U>
627 void Tt_apply_right(std::span<U> data, std::uint32_t cell_permutation,
628 int n) const
629 {
630 assert(_element);
631 _element->Tt_apply_right(data, n, cell_permutation);
632 }
633
643 template <typename U>
644 void Tt_inv_apply_right(std::span<U> data, std::uint32_t cell_permutation,
645 int n) const
646 {
647 assert(_element);
648 _element->Tt_inv_apply_right(data, n, cell_permutation);
649 }
650
667 void permute(std::span<std::int32_t> doflist,
668 std::uint32_t cell_permutation) const;
669
686 void permute_inv(std::span<std::int32_t> doflist,
687 std::uint32_t cell_permutation) const;
688
703 std::function<void(std::span<std::int32_t>, std::uint32_t)>
704 dof_permutation_fn(bool inverse = false, bool scalar_element = false) const;
705
706private:
707 std::string _signature;
708
709 mesh::CellType _cell_shape;
710
711 int _space_dim;
712
713 // List of sub-elements (if any)
714 std::vector<std::shared_ptr<const FiniteElement<geometry_type>>>
715 _sub_elements;
716
717 // Dimension of each value space
718 std::vector<std::size_t> _reference_value_shape;
719
720 // Block size for BlockedElements. This gives the number of DOFs
721 // co-located at each dof 'point'.
722 int _bs;
723
724 // Indicate whether this is a mixed element
725 bool _is_mixed;
726
727 // Indicate whether this element represents a symmetric 2-tensor
728 bool _symmetric;
729
730 // Indicate whether the element needs permutations or transformations
731 bool _needs_dof_permutations;
732 bool _needs_dof_transformations;
733
734 // Basix Element (nullptr for mixed elements)
735 std::unique_ptr<basix::FiniteElement<geometry_type>> _element;
736
737 // Quadrature points of a quadrature element (0 dimensional array for
738 // all elements except quadrature elements)
739 std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>> _points;
740};
741} // namespace dolfinx::fem
Definition CoordinateElement.h:26
Model of a finite element.
Definition FiniteElement.h:40
bool symmetric() const
Does the element represent a symmetric 2-tensor?
Definition FiniteElement.cpp:382
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:432
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:577
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:522
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:529
basix::maps::type map_type() const
Get the map type used by the element.
Definition FiniteElement.cpp:461
int space_dimension() const noexcept
Definition FiniteElement.cpp:370
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:401
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:644
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:565
FiniteElement(const FiniteElement &element)=delete
Copy constructor.
FiniteElement(const ufcx_finite_element &e)
Create finite element from UFC finite element.
Definition FiniteElement.cpp:124
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:545
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:493
void permute_inv(std::span< std::int32_t > doflist, std::uint32_t cell_permutation) const
Perform the inverse of the operation applied by permute().
Definition FiniteElement.cpp:584
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:439
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:593
std::string signature() const noexcept
Definition FiniteElement.cpp:358
bool needs_dof_permutations() const noexcept
Check if DOF permutations are needed for this element.
Definition FiniteElement.cpp:571
bool is_mixed() const noexcept
Check if element is a mixed element.
Definition FiniteElement.cpp:425
int reference_value_size() const
Definition FiniteElement.cpp:388
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:300
bool operator!=(const FiniteElement &e) const
Definition FiniteElement.cpp:352
~FiniteElement()=default
Destructor.
T geometry_type
Geometry type of the Mesh that the FunctionSpace is defined on.
Definition FiniteElement.h:43
const basix::FiniteElement< geometry_type > & basix_element() const
Return underlying Basix element (if it exists).
Definition FiniteElement.cpp:449
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:419
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:562
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > interpolation_operator() const
Definition FiniteElement.cpp:509
int block_size() const noexcept
Definition FiniteElement.cpp:395
std::span< const std::size_t > reference_value_shape() const
The reference value shape.
Definition FiniteElement.cpp:376
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:627
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:405
void permute(std::span< std::int32_t > doflist, std::uint32_t cell_permutation) const
Permute indices associated with degree-of-freedoms on the reference element ordering to the globally ...
Definition FiniteElement.cpp:577
bool interpolation_ident() const noexcept
Definition FiniteElement.cpp:483
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:610
bool operator==(const FiniteElement &e) const
Definition FiniteElement.cpp:340
mesh::CellType cell_shape() const noexcept
Definition FiniteElement.cpp:364
bool map_ident() const noexcept
Definition FiniteElement.cpp:473
Finite element method functionality.
Definition assemble_matrix_impl.h:26
doftransform
DOF transformation type.
Definition FiniteElement.h:27
@ inverse_transpose
Transpose inverse.
CellType
Cell type identifier.
Definition cell_types.h:22