Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/de/d83/FiniteElement_8h_source.html
DOLFINx  0.5.1
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 <array>
10 #include <basix/finite-element.h>
11 #include <dolfinx/mesh/cell_types.h>
12 #include <functional>
13 #include <memory>
14 #include <span>
15 #include <utility>
16 #include <vector>
17 
18 struct ufcx_finite_element;
19 
20 namespace dolfinx::fem
21 {
25 {
26 public:
29  explicit FiniteElement(const ufcx_finite_element& e);
30 
34  FiniteElement(const basix::FiniteElement& element, int bs);
35 
37  FiniteElement(const FiniteElement& element) = delete;
38 
40  FiniteElement(FiniteElement&& element) = default;
41 
43  virtual ~FiniteElement() = default;
44 
46  FiniteElement& operator=(const FiniteElement& element) = delete;
47 
49  FiniteElement& operator=(FiniteElement&& element) = default;
50 
55  bool operator==(const FiniteElement& e) const;
56 
61  bool operator!=(const FiniteElement& e) const;
62 
69  std::string signature() const noexcept;
70 
73  mesh::CellType cell_shape() const noexcept;
74 
78  int space_dimension() const noexcept;
79 
84  int block_size() const noexcept;
85 
92  int value_size() const;
93 
97  int reference_value_size() const;
98 
101  std::span<const std::size_t> value_shape() const noexcept;
102 
105  std::string family() const noexcept;
106 
118  void tabulate(std::span<double> values, std::span<const double> X,
119  std::array<std::size_t, 2> shape, int order) const;
120 
130  std::pair<std::vector<double>, std::array<std::size_t, 4>>
131  tabulate(std::span<const double> X, std::array<std::size_t, 2> shape,
132  int order) const;
133 
136  int num_sub_elements() const noexcept;
137 
142  bool is_mixed() const noexcept;
143 
145  const std::vector<std::shared_ptr<const FiniteElement>>&
146  sub_elements() const noexcept;
147 
149  std::shared_ptr<const FiniteElement>
150  extract_sub_element(const std::vector<int>& component) const;
151 
153  const basix::FiniteElement& basix_element() const;
154 
156  basix::maps::type map_type() const;
157 
164  bool interpolation_ident() const noexcept;
165 
169  bool map_ident() const noexcept;
170 
181  std::pair<std::vector<double>, std::array<std::size_t, 2>>
182  interpolation_points() const;
183 
193  std::pair<std::vector<double>, std::array<std::size_t, 2>>
194  interpolation_operator() const;
195 
208  std::pair<std::vector<double>, std::array<std::size_t, 2>>
209  create_interpolation_operator(const FiniteElement& from) const;
210 
224  bool needs_dof_transformations() const noexcept;
225 
240  bool needs_dof_permutations() const noexcept;
241 
259  template <typename T>
260  std::function<void(const std::span<T>&, const std::span<const std::uint32_t>&,
261  std::int32_t, int)>
262  get_dof_transformation_function(bool inverse = false, bool transpose = false,
263  bool scalar_element = false) const
264  {
266  {
267  // If no permutation needed, return function that does nothing
268  return [](const std::span<T>&, const std::span<const std::uint32_t>&,
269  std::int32_t, int)
270  {
271  // Do nothing
272  };
273  }
274 
275  if (_sub_elements.size() != 0)
276  {
277  if (_bs == 1)
278  {
279  // Mixed element
280  std::vector<std::function<void(const std::span<T>&,
281  const std::span<const std::uint32_t>&,
282  std::int32_t, int)>>
283  sub_element_functions;
284  std::vector<int> dims;
285  for (std::size_t i = 0; i < _sub_elements.size(); ++i)
286  {
287  sub_element_functions.push_back(
288  _sub_elements[i]->get_dof_transformation_function<T>(inverse,
289  transpose));
290  dims.push_back(_sub_elements[i]->space_dimension());
291  }
292 
293  return [dims, sub_element_functions](
294  const std::span<T>& data,
295  const std::span<const std::uint32_t>& cell_info,
296  std::int32_t cell, int block_size)
297  {
298  std::size_t offset = 0;
299  for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
300  {
301  const std::size_t width = dims[e] * block_size;
302  sub_element_functions[e](data.subspan(offset, width), cell_info,
303  cell, block_size);
304  offset += width;
305  }
306  };
307  }
308  else if (!scalar_element)
309  {
310  // Vector element
311  const std::function<void(const std::span<T>&,
312  const std::span<const std::uint32_t>&,
313  std::int32_t, int)>
314  sub_function = _sub_elements[0]->get_dof_transformation_function<T>(
315  inverse, transpose);
316  const int ebs = _bs;
317  return
318  [ebs, sub_function](const std::span<T>& data,
319  const std::span<const std::uint32_t>& cell_info,
320  std::int32_t cell, int data_block_size)
321  { sub_function(data, cell_info, cell, ebs * data_block_size); };
322  }
323  }
324  if (transpose)
325  {
326  if (inverse)
327  {
328  return [this](const std::span<T>& data,
329  const std::span<const std::uint32_t>& cell_info,
330  std::int32_t cell, int block_size)
331  {
333  block_size);
334  };
335  }
336  else
337  {
338  return [this](const std::span<T>& data,
339  const std::span<const std::uint32_t>& cell_info,
340  std::int32_t cell, int block_size) {
342  };
343  }
344  }
345  else
346  {
347  if (inverse)
348  {
349  return [this](const std::span<T>& data,
350  const std::span<const std::uint32_t>& cell_info,
351  std::int32_t cell, int block_size) {
353  };
354  }
355  else
356  {
357  return [this](const std::span<T>& data,
358  const std::span<const std::uint32_t>& cell_info,
359  std::int32_t cell, int block_size)
360  { apply_dof_transformation(data, cell_info[cell], block_size); };
361  }
362  }
363  }
364 
383  template <typename T>
384  std::function<void(const std::span<T>&, const std::span<const std::uint32_t>&,
385  std::int32_t, int)>
387  bool transpose = false,
388  bool scalar_element
389  = false) const
390  {
392  {
393  // If no permutation needed, return function that does nothing
394  return [](const std::span<T>&, const std::span<const std::uint32_t>&,
395  std::int32_t, int)
396  {
397  // Do nothing
398  };
399  }
400  else if (_sub_elements.size() != 0)
401  {
402  if (_bs == 1)
403  {
404  // Mixed element
405  std::vector<std::function<void(const std::span<T>&,
406  const std::span<const std::uint32_t>&,
407  std::int32_t, int)>>
408  sub_element_functions;
409  for (std::size_t i = 0; i < _sub_elements.size(); ++i)
410  {
411  sub_element_functions.push_back(
412  _sub_elements[i]->get_dof_transformation_to_transpose_function<T>(
413  inverse, transpose));
414  }
415 
416  return [this, sub_element_functions](
417  const std::span<T>& data,
418  const std::span<const std::uint32_t>& cell_info,
419  std::int32_t cell, int block_size)
420  {
421  std::size_t offset = 0;
422  for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
423  {
424  sub_element_functions[e](data.subspan(offset, data.size() - offset),
425  cell_info, cell, block_size);
426  offset += _sub_elements[e]->space_dimension();
427  }
428  };
429  }
430  else if (!scalar_element)
431  {
432  // Vector element
433  const std::function<void(const std::span<T>&,
434  const std::span<const std::uint32_t>&,
435  std::int32_t, int)>
436  sub_function = _sub_elements[0]->get_dof_transformation_function<T>(
437  inverse, transpose);
438  return [this,
439  sub_function](const std::span<T>& data,
440  const std::span<const std::uint32_t>& cell_info,
441  std::int32_t cell, int data_block_size)
442  {
443  const int ebs = block_size();
444  const std::size_t dof_count = data.size() / data_block_size;
445  for (int block = 0; block < data_block_size; ++block)
446  {
447  sub_function(data.subspan(block * dof_count, dof_count), cell_info,
448  cell, ebs);
449  }
450  };
451  }
452  }
453 
454  if (transpose)
455  {
456  if (inverse)
457  {
458  return [this](const std::span<T>& data,
459  const std::span<const std::uint32_t>& cell_info,
460  std::int32_t cell, int block_size)
461  {
463  data, cell_info[cell], block_size);
464  };
465  }
466  else
467  {
468  return [this](const std::span<T>& data,
469  const std::span<const std::uint32_t>& cell_info,
470  std::int32_t cell, int block_size)
471  {
473  block_size);
474  };
475  }
476  }
477  else
478  {
479  if (inverse)
480  {
481  return [this](const std::span<T>& data,
482  const std::span<const std::uint32_t>& cell_info,
483  std::int32_t cell, int block_size)
484  {
486  block_size);
487  };
488  }
489  else
490  {
491  return [this](const std::span<T>& data,
492  const std::span<const std::uint32_t>& cell_info,
493  std::int32_t cell, int block_size) {
495  block_size);
496  };
497  }
498  }
499  }
500 
507  template <typename T>
508  void apply_dof_transformation(const std::span<T>& data,
509  std::uint32_t cell_permutation,
510  int block_size) const
511  {
512  assert(_element);
513  _element->apply_dof_transformation(data, block_size, cell_permutation);
514  }
515 
524  template <typename T>
525  void
527  std::uint32_t cell_permutation,
528  int block_size) const
529  {
530  assert(_element);
531  _element->apply_inverse_transpose_dof_transformation(data, block_size,
532  cell_permutation);
533  }
534 
542  template <typename T>
543  void apply_transpose_dof_transformation(const std::span<T>& data,
544  std::uint32_t cell_permutation,
545  int block_size) const
546  {
547  assert(_element);
548  _element->apply_transpose_dof_transformation(data, block_size,
549  cell_permutation);
550  }
551 
559  template <typename T>
560  void apply_inverse_dof_transformation(const std::span<T>& data,
561  std::uint32_t cell_permutation,
562  int block_size) const
563  {
564  assert(_element);
565  _element->apply_inverse_dof_transformation(data, block_size,
566  cell_permutation);
567  }
568 
575  template <typename T>
576  void apply_dof_transformation_to_transpose(const std::span<T>& data,
577  std::uint32_t cell_permutation,
578  int block_size) const
579  {
580  assert(_element);
581  _element->apply_dof_transformation_to_transpose(data, block_size,
582  cell_permutation);
583  }
584 
591  template <typename T>
592  void
594  std::uint32_t cell_permutation,
595  int block_size) const
596  {
597  assert(_element);
598  _element->apply_inverse_dof_transformation_to_transpose(data, block_size,
599  cell_permutation);
600  }
601 
608  template <typename T>
610  const std::span<T>& data, std::uint32_t cell_permutation,
611  int block_size) const
612  {
613  assert(_element);
614  _element->apply_transpose_dof_transformation_to_transpose(data, block_size,
615  cell_permutation);
616  }
617 
624  template <typename T>
626  const std::span<T>& data, std::uint32_t cell_permutation,
627  int block_size) const
628  {
629  assert(_element);
630  _element->apply_inverse_transpose_dof_transformation_to_transpose(
631  data, block_size, cell_permutation);
632  }
633 
638  void permute_dofs(const std::span<std::int32_t>& doflist,
639  std::uint32_t cell_permutation) const;
640 
645  void unpermute_dofs(const std::span<std::int32_t>& doflist,
646  std::uint32_t cell_permutation) const;
647 
659  std::function<void(const std::span<std::int32_t>&, std::uint32_t)>
660  get_dof_permutation_function(bool inverse = false,
661  bool scalar_element = false) const;
662 
663 private:
664  std::string _signature, _family;
665 
666  mesh::CellType _cell_shape;
667 
668  int _space_dim;
669 
670  // List of sub-elements (if any)
671  std::vector<std::shared_ptr<const FiniteElement>> _sub_elements;
672 
673  // Dimension of each value space
674  std::vector<std::size_t> _value_shape;
675 
676  // Block size for VectorElements and TensorElements. This gives the
677  // number of DOFs co-located at each dof 'point'.
678  int _bs;
679 
680  // Indicate whether the element needs permutations or transformations
681  bool _needs_dof_permutations;
682  bool _needs_dof_transformations;
683 
684  // Basix Element (nullptr for mixed elements)
685  std::unique_ptr<basix::FiniteElement> _element;
686 };
687 } // namespace dolfinx::fem
Finite Element, containing the dof layout on a reference element, and various methods for evaluating ...
Definition: FiniteElement.h:25
void apply_inverse_dof_transformation(const std::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:560
std::string family() const noexcept
The finite element family.
Definition: FiniteElement.cpp:345
std::pair< std::vector< double >, 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:450
void permute_dofs(const std::span< std::int32_t > &doflist, std::uint32_t cell_permutation) const
Permute the DOFs of the element.
Definition: FiniteElement.cpp:502
void apply_inverse_dof_transformation_to_transpose(const std::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply inverse of DOF transformation to some transposed data.
Definition: FiniteElement.h:593
basix::maps::type map_type() const
Get the map type used by the element.
Definition: FiniteElement.cpp:401
int space_dimension() const noexcept
Dimension of the finite element function space (the number of degrees-of-freedom for the element)
Definition: FiniteElement.cpp:324
void apply_transpose_dof_transformation(const std::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:543
bool needs_dof_transformations() const noexcept
Check if DOF transformations are needed for this element.
Definition: FiniteElement.cpp:492
FiniteElement(const FiniteElement &element)=delete
Copy constructor.
FiniteElement(const ufcx_finite_element &e)
Create finite element from UFC finite element.
Definition: FiniteElement.cpp:104
void unpermute_dofs(const std::span< std::int32_t > &doflist, std::uint32_t cell_permutation) const
Unpermute the DOFs of the element.
Definition: FiniteElement.cpp:508
void apply_transpose_dof_transformation_to_transpose(const std::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply transpose of transformation to some transposed data.
Definition: FiniteElement.h:609
std::string signature() const noexcept
String identifying the finite element.
Definition: FiniteElement.cpp:317
bool needs_dof_permutations() const noexcept
Check if DOF permutations are needed for this element.
Definition: FiniteElement.cpp:497
void apply_dof_transformation_to_transpose(const std::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply DOF transformation to some transposed data.
Definition: FiniteElement.h:576
void apply_dof_transformation(const std::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply DOF transformation to some data.
Definition: FiniteElement.h:508
std::pair< std::vector< double >, std::array< std::size_t, 2 > > interpolation_operator() const
Interpolation operator (matrix) Pi that maps a function evaluated at the points provided by FiniteEle...
Definition: FiniteElement.cpp:438
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:368
std::pair< std::vector< double >, std::array< std::size_t, 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:425
std::shared_ptr< const FiniteElement > extract_sub_element(const std::vector< int > &component) const
Extract sub finite element for component.
Definition: FiniteElement.cpp:380
FiniteElement & operator=(FiniteElement &&element)=default
Move assignment.
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:332
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:326
virtual ~FiniteElement()=default
Destructor.
bool operator!=(const FiniteElement &e) const
Check if two elements are not equivalent.
Definition: FiniteElement.cpp:312
void tabulate(std::span< double > values, std::span< const double > 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:347
std::span< const std::size_t > value_shape() const noexcept
Shape of the value space. The rank is the size of the value_shape.
Definition: FiniteElement.cpp:340
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:363
FiniteElement & operator=(const FiniteElement &element)=delete
Copy assignment.
const basix::FiniteElement & basix_element() const
Return underlying basix element (if it exists)
Definition: FiniteElement.cpp:390
int block_size() const noexcept
Block size of the finite element function space. For VectorElements and TensorElements,...
Definition: FiniteElement.cpp:338
std::function< void(const std::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:515
const std::vector< std::shared_ptr< const FiniteElement > > & sub_elements() const noexcept
Subelements (if any)
Definition: FiniteElement.cpp:374
bool interpolation_ident() const noexcept
Check if interpolation into the finite element space is an identity operation given the evaluation on...
Definition: FiniteElement.cpp:418
std::function< void(const std::span< T > &, const std::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:262
void apply_inverse_transpose_dof_transformation_to_transpose(const std::span< T > &data, std::uint32_t cell_permutation, int block_size) const
Apply inverse transpose transformation to some transposed data.
Definition: FiniteElement.h:625
void apply_inverse_transpose_dof_transformation(const std::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:526
std::function< void(const std::span< T > &, const std::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:386
bool operator==(const FiniteElement &e) const
Check if two elements are equivalent.
Definition: FiniteElement.cpp:302
mesh::CellType cell_shape() const noexcept
Cell shape.
Definition: FiniteElement.cpp:319
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:412
Finite element method functionality.
Definition: assemble_matrix_impl.h:25
CellType
Cell type identifier.
Definition: cell_types.h:22