DOLFINx
DOLFINx C++ interface
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 <basix/finite-element.h>
10#include <dolfinx/mesh/cell_types.h>
11#include <functional>
12#include <memory>
13#include <vector>
14#include <xtensor/xtensor.hpp>
15#include <xtl/xspan.hpp>
16
17struct ufcx_finite_element;
18
19namespace dolfinx::fem
20{
24{
25public:
28 explicit FiniteElement(const ufcx_finite_element& e);
29
33 FiniteElement(const basix::FiniteElement& element, int bs);
34
36 FiniteElement(const FiniteElement& element) = delete;
37
39 FiniteElement(FiniteElement&& element) = default;
40
42 virtual ~FiniteElement() = default;
43
45 FiniteElement& operator=(const FiniteElement& element) = delete;
46
48 FiniteElement& operator=(FiniteElement&& element) = default;
49
54 bool operator==(const FiniteElement& e) const;
55
60 bool operator!=(const FiniteElement& e) const;
61
68 std::string signature() const noexcept;
69
72 mesh::CellType cell_shape() const noexcept;
73
77 int space_dimension() const noexcept;
78
83 int block_size() const noexcept;
84
91 int value_size() const;
92
96 int reference_value_size() const;
97
100 xtl::span<const int> value_shape() const noexcept;
101
104 std::string family() const noexcept;
105
116 void tabulate(xt::xtensor<double, 4>& values, const xt::xtensor<double, 2>& X,
117 int order) const;
118
153 template <typename O, typename P, typename Q, typename R>
154 std::function<void(O&, const P&, const Q&, double, const R&)> map_fn() const
155 {
156 assert(_element);
157 return _element->map_fn<O, P, Q, R>();
158 }
159
162 int num_sub_elements() const noexcept;
163
168 bool is_mixed() const noexcept;
169
171 const std::vector<std::shared_ptr<const FiniteElement>>&
172 sub_elements() const noexcept;
173
175 std::shared_ptr<const FiniteElement>
176 extract_sub_element(const std::vector<int>& component) const;
177
179 basix::maps::type map_type() const;
180
187 bool interpolation_ident() const noexcept;
188
192 bool map_ident() const noexcept;
193
200 const xt::xtensor<double, 2>& interpolation_points() const;
201
210 const xt::xtensor<double, 2>& interpolation_operator() const;
211
222 xt::xtensor<double, 2>
224
238 bool needs_dof_transformations() const noexcept;
239
254 bool needs_dof_permutations() const noexcept;
255
273 template <typename T>
274 std::function<void(const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
275 std::int32_t, int)>
276 get_dof_transformation_function(bool inverse = false, bool transpose = false,
277 bool scalar_element = false) const
278 {
280 {
281 // If no permutation needed, return function that does nothing
282 return [](const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
283 std::int32_t, int)
284 {
285 // Do nothing
286 };
287 }
288
289 if (_sub_elements.size() != 0)
290 {
291 if (_bs == 1)
292 {
293 // Mixed element
294 std::vector<std::function<void(const xtl::span<T>&,
295 const xtl::span<const std::uint32_t>&,
296 std::int32_t, int)>>
297 sub_element_functions;
298 std::vector<int> dims;
299 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
300 {
301 sub_element_functions.push_back(
302 _sub_elements[i]->get_dof_transformation_function<T>(inverse,
303 transpose));
304 dims.push_back(_sub_elements[i]->space_dimension());
305 }
306
307 return [dims, sub_element_functions](
308 const xtl::span<T>& data,
309 const xtl::span<const std::uint32_t>& cell_info,
310 std::int32_t cell, int block_size)
311 {
312 std::size_t offset = 0;
313 for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
314 {
315 const std::size_t width = dims[e] * block_size;
316 sub_element_functions[e](data.subspan(offset, width), cell_info,
318 offset += width;
319 }
320 };
321 }
322 else if (!scalar_element)
323 {
324 // Vector element
325 const std::function<void(const xtl::span<T>&,
326 const xtl::span<const std::uint32_t>&,
327 std::int32_t, int)>
328 sub_function = _sub_elements[0]->get_dof_transformation_function<T>(
329 inverse, transpose);
330 const int ebs = _bs;
331 return
332 [ebs, sub_function](const xtl::span<T>& data,
333 const xtl::span<const std::uint32_t>& cell_info,
334 std::int32_t cell, int data_block_size)
335 { sub_function(data, cell_info, cell, ebs * data_block_size); };
336 }
337 }
338 if (transpose)
339 {
340 if (inverse)
341 {
342 return [this](const xtl::span<T>& data,
343 const xtl::span<const std::uint32_t>& cell_info,
344 std::int32_t cell, int block_size)
345 {
347 block_size);
348 };
349 }
350 else
351 {
352 return [this](const xtl::span<T>& data,
353 const xtl::span<const std::uint32_t>& cell_info,
354 std::int32_t cell, int block_size) {
356 };
357 }
358 }
359 else
360 {
361 if (inverse)
362 {
363 return [this](const xtl::span<T>& data,
364 const xtl::span<const std::uint32_t>& cell_info,
365 std::int32_t cell, int block_size) {
367 };
368 }
369 else
370 {
371 return [this](const xtl::span<T>& data,
372 const xtl::span<const std::uint32_t>& cell_info,
373 std::int32_t cell, int block_size)
374 { apply_dof_transformation(data, cell_info[cell], block_size); };
375 }
376 }
377 }
378
397 template <typename T>
398 std::function<void(const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
399 std::int32_t, int)>
401 bool transpose = false,
402 bool scalar_element
403 = false) const
404 {
406 {
407 // If no permutation needed, return function that does nothing
408 return [](const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
409 std::int32_t, int)
410 {
411 // Do nothing
412 };
413 }
414 else if (_sub_elements.size() != 0)
415 {
416 if (_bs == 1)
417 {
418 // Mixed element
419 std::vector<std::function<void(const xtl::span<T>&,
420 const xtl::span<const std::uint32_t>&,
421 std::int32_t, int)>>
422 sub_element_functions;
423 for (std::size_t i = 0; i < _sub_elements.size(); ++i)
424 {
425 sub_element_functions.push_back(
426 _sub_elements[i]->get_dof_transformation_to_transpose_function<T>(
427 inverse, transpose));
428 }
429
430 return [this, sub_element_functions](
431 const xtl::span<T>& data,
432 const xtl::span<const std::uint32_t>& cell_info,
433 std::int32_t cell, int block_size)
434 {
435 std::size_t offset = 0;
436 for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
437 {
438 sub_element_functions[e](data.subspan(offset, data.size() - offset),
439 cell_info, cell, block_size);
440 offset += _sub_elements[e]->space_dimension();
441 }
442 };
443 }
444 else if (!scalar_element)
445 {
446 // Vector element
447 const std::function<void(const xtl::span<T>&,
448 const xtl::span<const std::uint32_t>&,
449 std::int32_t, int)>
450 sub_function = _sub_elements[0]->get_dof_transformation_function<T>(
451 inverse, transpose);
452 return [this,
453 sub_function](const xtl::span<T>& data,
454 const xtl::span<const std::uint32_t>& cell_info,
455 std::int32_t cell, int data_block_size)
456 {
457 const int ebs = block_size();
458 const std::size_t dof_count = data.size() / data_block_size;
459 for (int block = 0; block < data_block_size; ++block)
460 {
461 sub_function(data.subspan(block * dof_count, dof_count), cell_info,
462 cell, ebs);
463 }
464 };
465 }
466 }
467
468 if (transpose)
469 {
470 if (inverse)
471 {
472 return [this](const xtl::span<T>& data,
473 const xtl::span<const std::uint32_t>& cell_info,
474 std::int32_t cell, int block_size)
475 {
477 data, cell_info[cell], block_size);
478 };
479 }
480 else
481 {
482 return [this](const xtl::span<T>& data,
483 const xtl::span<const std::uint32_t>& cell_info,
484 std::int32_t cell, int block_size)
485 {
487 block_size);
488 };
489 }
490 }
491 else
492 {
493 if (inverse)
494 {
495 return [this](const xtl::span<T>& data,
496 const xtl::span<const std::uint32_t>& cell_info,
497 std::int32_t cell, int block_size)
498 {
500 block_size);
501 };
502 }
503 else
504 {
505 return [this](const xtl::span<T>& data,
506 const xtl::span<const std::uint32_t>& cell_info,
507 std::int32_t cell, int block_size) {
509 block_size);
510 };
511 }
512 }
513 }
514
521 template <typename T>
522 void apply_dof_transformation(const xtl::span<T>& data,
523 std::uint32_t cell_permutation,
524 int block_size) const
525 {
526 assert(_element);
527 _element->apply_dof_transformation(data, block_size, cell_permutation);
528 }
529
538 template <typename T>
539 void
541 std::uint32_t cell_permutation,
542 int block_size) const
543 {
544 assert(_element);
545 _element->apply_inverse_transpose_dof_transformation(data, block_size,
546 cell_permutation);
547 }
548
556 template <typename T>
557 void apply_transpose_dof_transformation(const xtl::span<T>& data,
558 std::uint32_t cell_permutation,
559 int block_size) const
560 {
561 assert(_element);
562 _element->apply_transpose_dof_transformation(data, block_size,
563 cell_permutation);
564 }
565
573 template <typename T>
574 void apply_inverse_dof_transformation(const xtl::span<T>& data,
575 std::uint32_t cell_permutation,
576 int block_size) const
577 {
578 assert(_element);
579 _element->apply_inverse_dof_transformation(data, block_size,
580 cell_permutation);
581 }
582
589 template <typename T>
590 void apply_dof_transformation_to_transpose(const xtl::span<T>& data,
591 std::uint32_t cell_permutation,
592 int block_size) const
593 {
594 assert(_element);
595 _element->apply_dof_transformation_to_transpose(data, block_size,
596 cell_permutation);
597 }
598
605 template <typename T>
606 void
608 std::uint32_t cell_permutation,
609 int block_size) const
610 {
611 assert(_element);
612 _element->apply_inverse_dof_transformation_to_transpose(data, block_size,
613 cell_permutation);
614 }
615
622 template <typename T>
624 const xtl::span<T>& data, std::uint32_t cell_permutation,
625 int block_size) const
626 {
627 assert(_element);
628 _element->apply_transpose_dof_transformation_to_transpose(data, block_size,
629 cell_permutation);
630 }
631
638 template <typename T>
640 const xtl::span<T>& data, std::uint32_t cell_permutation,
641 int block_size) const
642 {
643 assert(_element);
644 _element->apply_inverse_transpose_dof_transformation_to_transpose(
645 data, block_size, cell_permutation);
646 }
647
652 void permute_dofs(const xtl::span<std::int32_t>& doflist,
653 std::uint32_t cell_permutation) const;
654
659 void unpermute_dofs(const xtl::span<std::int32_t>& doflist,
660 std::uint32_t cell_permutation) const;
661
673 std::function<void(const xtl::span<std::int32_t>&, std::uint32_t)>
674 get_dof_permutation_function(bool inverse = false,
675 bool scalar_element = false) const;
676
677private:
678 std::string _signature, _family;
679
680 mesh::CellType _cell_shape;
681
682 int _space_dim;
683
684 // List of sub-elements (if any)
685 std::vector<std::shared_ptr<const FiniteElement>> _sub_elements;
686
687 // Dimension of each value space
688 std::vector<int> _value_shape;
689
690 // Block size for VectorElements and TensorElements. This gives the
691 // number of DOFs co-located at each dof 'point'.
692 int _bs;
693
694 // Indicate whether the element needs permutations or transformations
695 bool _needs_dof_permutations;
696 bool _needs_dof_transformations;
697
698 // Basix Element (nullptr for mixed elements)
699 std::unique_ptr<basix::FiniteElement> _element;
700};
701} // namespace dolfinx::fem
Finite Element, containing the dof layout on a reference element, and various methods for evaluating ...
Definition: FiniteElement.h:24
const xt::xtensor< double, 2 > & interpolation_points() const
Points on the reference cell at which an expression need to be evaluated in order to interpolate the ...
Definition: FiniteElement.cpp:382
FiniteElement & operator=(const FiniteElement &element)=delete
Copy assignment.
std::string family() const noexcept
The finite element family.
Definition: FiniteElement.cpp:323
basix::maps::type map_type() const
Get the map type used by the element.
Definition: FiniteElement.cpp:359
int space_dimension() const noexcept
Dimension of the finite element function space (the number of degrees-of-freedom for the element)
Definition: FiniteElement.cpp:302
xtl::span< const int > value_shape() const noexcept
Shape of the value space. The rank is the size of the value_shape.
Definition: FiniteElement.cpp:318
void apply_transpose_dof_transformation_to_transpose(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply transpose of transformation to some transposed data.
Definition: FiniteElement.h:623
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:447
FiniteElement(const FiniteElement &element)=delete
Copy constructor.
FiniteElement(const ufcx_finite_element &e)
Create finite element from UFC finite element.
Definition: FiniteElement.cpp:99
std::function< void(const xtl::span< T > &, const xtl::span< const std::uint32_t > &, std::int32_t, int)> get_dof_transformation_to_transpose_function(bool inverse=false, bool transpose=false, bool scalar_element=false) const
Return a function that applies DOF transformation to some transposed data.
Definition: FiniteElement.h:400
void apply_inverse_dof_transformation_to_transpose(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply inverse of DOF transformation to some transposed data.
Definition: FiniteElement.h:607
void apply_inverse_transpose_dof_transformation(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply inverse transpose transformation to some data. For VectorElements, this applies the transformat...
Definition: FiniteElement.h:540
std::string signature() const noexcept
String identifying the finite element.
Definition: FiniteElement.cpp:295
void permute_dofs(const xtl::span< std::int32_t > &doflist, std::uint32_t cell_permutation) const
Permute the DOFs of the element.
Definition: FiniteElement.cpp:457
bool needs_dof_permutations() const noexcept
Check if DOF permutations are needed for this element.
Definition: FiniteElement.cpp:452
const xt::xtensor< double, 2 > & interpolation_operator() const
Interpolation operator (matrix) Pi that maps a function evaluated at the points provided by FiniteEle...
Definition: FiniteElement.cpp:394
void apply_inverse_transpose_dof_transformation_to_transpose(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply inverse transpose transformation to some transposed data.
Definition: FiniteElement.h:639
std::function< void(O &, const P &, const Q &, double, const R &)> map_fn() const
Return a function that performs the appropriate push-forward (pull-back) for the element type.
Definition: FiniteElement.h:154
bool is_mixed() const noexcept
Check if element is a mixed element, i.e. composed of two or more elements of different types....
Definition: FiniteElement.cpp:337
void apply_dof_transformation(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply DOF transformation to some data.
Definition: FiniteElement.h:522
std::shared_ptr< const FiniteElement > extract_sub_element(const std::vector< int > &component) const
Extract sub finite element for component.
Definition: FiniteElement.cpp:349
int reference_value_size() const
The value size, e.g. 1 for a scalar function, 2 for a 2D vector, 9 for a second-order tensor in 3D,...
Definition: FiniteElement.cpp:310
int value_size() const
The value size, e.g. 1 for a scalar function, 2 for a 2D vector, 9 for a second-order tensor in 3D.
Definition: FiniteElement.cpp:304
virtual ~FiniteElement()=default
Destructor.
void apply_dof_transformation_to_transpose(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply DOF transformation to some transposed data.
Definition: FiniteElement.h:590
bool operator!=(const FiniteElement &e) const
Check if two elements are not equivalent.
Definition: FiniteElement.cpp:290
xt::xtensor< double, 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:406
void apply_inverse_dof_transformation(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply inverse transformation to some data. For VectorElements, this applies the transformations for t...
Definition: FiniteElement.h:574
std::function< void(const xtl::span< std::int32_t > &, std::uint32_t)> get_dof_permutation_function(bool inverse=false, bool scalar_element=false) const
Return a function that applies DOF permutation to some data.
Definition: FiniteElement.cpp:470
FiniteElement(FiniteElement &&element)=default
Move constructor.
int num_sub_elements() const noexcept
Get the number of sub elements (for a mixed or blocked element)
Definition: FiniteElement.cpp:332
void apply_transpose_dof_transformation(const xtl::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply transpose transformation to some data. For VectorElements, this applies the transformations for...
Definition: FiniteElement.h:557
void unpermute_dofs(const xtl::span< std::int32_t > &doflist, std::uint32_t cell_permutation) const
Unpermute the DOFs of the element.
Definition: FiniteElement.cpp:463
int block_size() const noexcept
Block size of the finite element function space. For VectorElements and TensorElements,...
Definition: FiniteElement.cpp:316
std::function< void(const xtl::span< T > &, const xtl::span< const std::uint32_t > &, std::int32_t, int)> get_dof_transformation_function(bool inverse=false, bool transpose=false, bool scalar_element=false) const
Return a function that applies DOF transformation to some data.
Definition: FiniteElement.h:276
const std::vector< std::shared_ptr< const FiniteElement > > & sub_elements() const noexcept
Subelements (if any)
Definition: FiniteElement.cpp:343
void tabulate(xt::xtensor< double, 4 > &values, const xt::xtensor< double, 2 > &X, int order) const
Evaluate all derivatives of the basis functions up to given order at given points in reference cell.
Definition: FiniteElement.cpp:325
bool interpolation_ident() const noexcept
Check if interpolation into the finite element space is an identity operation given the evaluation on...
Definition: FiniteElement.cpp:376
bool operator==(const FiniteElement &e) const
Check if two elements are equivalent.
Definition: FiniteElement.cpp:280
mesh::CellType cell_shape() const noexcept
Cell shape.
Definition: FiniteElement.cpp:297
bool map_ident() const noexcept
Check if the push forward/pull back map from the values on reference to the values on a physical cell...
Definition: FiniteElement.cpp:370
Finite element method functionality.
Definition: assemble_matrix_impl.h:24
CellType
Cell type identifier.
Definition: cell_types.h:22