Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/v0.2.0a0/v0.9.0/cpp
DOLFINx  0.2.0
DOLFINx C++ interface
FiniteElement.h
1 // Copyright (C) 2008-2020 Anders Logg and Garth N. Wells
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/common/types.h>
11 #include <dolfinx/mesh/cell_types.h>
12 #include <functional>
13 #include <memory>
14 #include <numeric>
15 #include <vector>
16 #include <xtl/xspan.hpp>
17 
18 struct ufc_finite_element;
19 
20 namespace dolfinx::fem
21 {
25 {
26 public:
29  explicit FiniteElement(const ufc_finite_element& ufc_element);
30 
32  FiniteElement(const FiniteElement& element) = delete;
33 
35  FiniteElement(FiniteElement&& element) = default;
36 
38  virtual ~FiniteElement() = default;
39 
41  FiniteElement& operator=(const FiniteElement& element) = delete;
42 
44  FiniteElement& operator=(FiniteElement&& element) = default;
45 
48  std::string signature() const noexcept;
49 
52  mesh::CellType cell_shape() const noexcept;
53 
56  int space_dimension() const noexcept;
57 
62  int block_size() const noexcept;
63 
66  int value_size() const noexcept;
67 
71  int reference_value_size() const noexcept;
72 
75  int value_rank() const noexcept;
76 
78  int value_dimension(int i) const;
79 
82  std::string family() const noexcept;
83 
93  void tabulate(xt::xtensor<double, 4>& values, const xt::xtensor<double, 2>& X,
94  int order) const;
95 
97  void transform_reference_basis(xt::xtensor<double, 3>& values,
98  const xt::xtensor<double, 3>& reference_values,
99  const xt::xtensor<double, 3>& J,
100  const xtl::span<const double>& detJ,
101  const xt::xtensor<double, 3>& K) const;
102 
105  int num_sub_elements() const noexcept;
106 
108  const std::vector<std::shared_ptr<const FiniteElement>>&
109  sub_elements() const noexcept;
110 
112  std::size_t hash() const noexcept;
113 
115  std::shared_ptr<const FiniteElement>
116  extract_sub_element(const std::vector<int>& component) const;
117 
124  bool interpolation_ident() const noexcept;
125 
132  const xt::xtensor<double, 2>& interpolation_points() const;
133 
151  template <typename T>
152  constexpr void interpolate(const xt::xtensor<T, 2>& values,
153  xtl::span<T> dofs) const
154  {
155  if (!_element)
156  {
157  throw std::runtime_error("No underlying element for interpolation. "
158  "Cannot interpolate mixed elements directly.");
159  }
160 
161  const std::size_t rows = _space_dim / _bs;
162  assert(_space_dim % _bs == 0);
163  assert(dofs.size() == rows);
164 
165  // Compute dofs = Pi * x (matrix-vector multiply)
166  const xt::xtensor<double, 2>& Pi = _element->interpolation_matrix();
167  assert(Pi.size() % rows == 0);
168  const std::size_t cols = Pi.size() / rows;
169  for (std::size_t i = 0; i < rows; ++i)
170  {
171  // Can be replaced with std::transform_reduce once GCC 8 series dies.
172  // Dot product between row i of the matrix and 'values'
173  dofs[i] = std::inner_product(std::next(Pi.data(), i * cols),
174  std::next(Pi.data(), i * cols + cols),
175  values.data(), T(0.0));
176  }
177  }
178 
192  bool needs_dof_transformations() const noexcept;
193 
207  bool needs_dof_permutations() const noexcept;
208 
223  template <typename T>
224  std::function<void(const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
225  std::int32_t, int)>
226  get_dof_transformation_function(bool inverse = false, bool transpose = false,
227  bool scalar_element = false) const
228  {
230  {
231  // If no permutation needed, return function that does nothing
232  return [](const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
233  std::int32_t, int)
234  {
235  // Do nothing
236  };
237  }
238 
239  if (_sub_elements.size() != 0)
240  {
241  if (_bs == 1)
242  {
243  // Mixed element
244  std::vector<std::function<void(const xtl::span<T>&,
245  const xtl::span<const std::uint32_t>&,
246  std::int32_t, int)>>
247  sub_element_functions;
248  std::vector<int> dims;
249  for (std::size_t i = 0; i < _sub_elements.size(); ++i)
250  {
251  sub_element_functions.push_back(
252  _sub_elements[i]->get_dof_transformation_function<T>(inverse,
253  transpose));
254  dims.push_back(_sub_elements[i]->space_dimension());
255  }
256 
257  return [dims, sub_element_functions](
258  const xtl::span<T>& data,
259  const xtl::span<const std::uint32_t>& cell_info,
260  std::int32_t cell, int block_size)
261  {
262  std::size_t start = 0;
263  for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
264  {
265  const std::size_t width = dims[e] * block_size;
266  sub_element_functions[e](data.subspan(start, width), cell_info,
267  cell, block_size);
268  start += width;
269  }
270  };
271  }
272  else if (!scalar_element)
273  {
274  // Vector element
275  const std::function<void(const xtl::span<T>&,
276  const xtl::span<const std::uint32_t>&,
277  std::int32_t, int)>
278  sub_function = _sub_elements[0]->get_dof_transformation_function<T>(
279  inverse, transpose);
280  const int ebs = _bs;
281  return
282  [ebs, sub_function](const xtl::span<T>& data,
283  const xtl::span<const std::uint32_t>& cell_info,
284  std::int32_t cell, int data_block_size)
285  { sub_function(data, cell_info, cell, ebs * data_block_size); };
286  }
287  }
288  if (transpose)
289  {
290  if (inverse)
291  {
292  return [this](const xtl::span<T>& data,
293  const xtl::span<const std::uint32_t>& cell_info,
294  std::int32_t cell, int block_size)
295  {
296  apply_inverse_transpose_dof_transformation(data, cell_info[cell],
297  block_size);
298  };
299  }
300  else
301  {
302  return [this](const xtl::span<T>& data,
303  const xtl::span<const std::uint32_t>& cell_info,
304  std::int32_t cell, int block_size) {
305  apply_transpose_dof_transformation(data, cell_info[cell], block_size);
306  };
307  }
308  }
309  else
310  {
311  if (inverse)
312  {
313  return [this](const xtl::span<T>& data,
314  const xtl::span<const std::uint32_t>& cell_info,
315  std::int32_t cell, int block_size) {
316  apply_inverse_dof_transformation(data, cell_info[cell], block_size);
317  };
318  }
319  else
320  {
321  return [this](const xtl::span<T>& data,
322  const xtl::span<const std::uint32_t>& cell_info,
323  std::int32_t cell, int block_size)
324  { apply_dof_transformation(data, cell_info[cell], block_size); };
325  }
326  }
327  }
328 
344  template <typename T>
345  std::function<void(const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
346  std::int32_t, int)>
348  bool transpose = false,
349  bool scalar_element
350  = false) const
351  {
353  {
354  // If no permutation needed, return function that does nothing
355  return [](const xtl::span<T>&, const xtl::span<const std::uint32_t>&,
356  std::int32_t, int)
357  {
358  // Do nothing
359  };
360  }
361  else if (_sub_elements.size() != 0)
362  {
363  if (_bs == 1)
364  {
365  // Mixed element
366  std::vector<std::function<void(const xtl::span<T>&,
367  const xtl::span<const std::uint32_t>&,
368  std::int32_t, int)>>
369  sub_element_functions;
370  for (std::size_t i = 0; i < _sub_elements.size(); ++i)
371  {
372  sub_element_functions.push_back(
373  _sub_elements[i]->get_dof_transformation_to_transpose_function<T>(
374  inverse, transpose));
375  }
376 
377  return [this, sub_element_functions](
378  const xtl::span<T>& data,
379  const xtl::span<const std::uint32_t>& cell_info,
380  std::int32_t cell, int block_size)
381  {
382  std::size_t start = 0;
383  for (std::size_t e = 0; e < sub_element_functions.size(); ++e)
384  {
385  const std::size_t width
386  = _sub_elements[e]->space_dimension() * block_size;
387  sub_element_functions[e](data.subspan(start, width), cell_info,
388  cell, block_size);
389  start += width;
390  }
391  };
392  }
393  else if (!scalar_element)
394  {
395  // Vector element
396  const std::function<void(const xtl::span<T>&,
397  const xtl::span<const std::uint32_t>&,
398  std::int32_t, int)>
399  sub_function = _sub_elements[0]->get_dof_transformation_function<T>(
400  inverse, transpose);
401  return [this,
402  sub_function](const xtl::span<T>& data,
403  const xtl::span<const std::uint32_t>& cell_info,
404  std::int32_t cell, int data_block_size)
405  {
406  const int ebs = block_size();
407  const std::size_t dof_count = data.size() / data_block_size;
408  for (int block = 0; block < data_block_size; ++block)
409  {
410  sub_function(data.subspan(block * dof_count, dof_count), cell_info,
411  cell, ebs);
412  }
413  };
414  }
415  }
416 
417  if (transpose)
418  {
419  if (inverse)
420  {
421  return [this](const xtl::span<T>& data,
422  const xtl::span<const std::uint32_t>& cell_info,
423  std::int32_t cell, int block_size)
424  {
426  data, cell_info[cell], block_size);
427  };
428  }
429  else
430  {
431  return [this](const xtl::span<T>& data,
432  const xtl::span<const std::uint32_t>& cell_info,
433  std::int32_t cell, int block_size)
434  {
436  block_size);
437  };
438  }
439  }
440  else
441  {
442  if (inverse)
443  {
444  return [this](const xtl::span<T>& data,
445  const xtl::span<const std::uint32_t>& cell_info,
446  std::int32_t cell, int block_size)
447  {
448  apply_inverse_dof_transformation_to_transpose(data, cell_info[cell],
449  block_size);
450  };
451  }
452  else
453  {
454  return [this](const xtl::span<T>& data,
455  const xtl::span<const std::uint32_t>& cell_info,
456  std::int32_t cell, int block_size) {
457  apply_dof_transformation_to_transpose(data, cell_info[cell],
458  block_size);
459  };
460  }
461  }
462  }
463 
469  template <typename T>
470  void apply_dof_transformation(const xtl::span<T>& data,
471  std::uint32_t cell_permutation,
472  int block_size) const
473  {
474  assert(_element);
475  _element->apply_dof_transformation(data, block_size, cell_permutation);
476  }
477 
485  template <typename T>
486  void
488  std::uint32_t cell_permutation,
489  int block_size) const
490  {
491  assert(_element);
492  _element->apply_inverse_transpose_dof_transformation(data, block_size,
493  cell_permutation);
494  }
495 
502  template <typename T>
503  void apply_transpose_dof_transformation(const xtl::span<T>& data,
504  std::uint32_t cell_permutation,
505  int block_size) const
506  {
507  assert(_element);
508  _element->apply_transpose_dof_transformation(data, block_size,
509  cell_permutation);
510  }
511 
518  template <typename T>
519  void apply_inverse_dof_transformation(const xtl::span<T>& data,
520  std::uint32_t cell_permutation,
521  int block_size) const
522  {
523  assert(_element);
524  _element->apply_inverse_dof_transformation(data, block_size,
525  cell_permutation);
526  }
527 
533  template <typename T>
534  void apply_dof_transformation_to_transpose(const xtl::span<T>& data,
535  std::uint32_t cell_permutation,
536  int block_size) const
537  {
538  assert(_element);
539  _element->apply_dof_transformation_to_transpose(data, block_size,
540  cell_permutation);
541  }
542 
548  template <typename T>
549  void
551  std::uint32_t cell_permutation,
552  int block_size) const
553  {
554  assert(_element);
555  _element->apply_inverse_dof_transformation_to_transpose(data, block_size,
556  cell_permutation);
557  }
558 
564  template <typename T>
566  const xtl::span<T>& data, std::uint32_t cell_permutation,
567  int block_size) const
568  {
569  assert(_element);
570  _element->apply_transpose_dof_transformation_to_transpose(data, block_size,
571  cell_permutation);
572  }
573 
579  template <typename T>
581  const xtl::span<T>& data, std::uint32_t cell_permutation,
582  int block_size) const
583  {
584  assert(_element);
585  _element->apply_inverse_transpose_dof_transformation_to_transpose(
586  data, block_size, cell_permutation);
587  }
588 
607  template <typename O, typename P, typename Q, typename T, typename S>
608  void map_pull_back(const O& u, const P& J, const Q& detJ, const T& K,
609  S&& U) const
610  {
611  assert(_element);
612  _element->map_pull_back_m(u, J, detJ, K, U);
613  }
614 
619  void permute_dofs(const xtl::span<std::int32_t>& doflist,
620  std::uint32_t cell_permutation) const;
621 
626  void unpermute_dofs(const xtl::span<std::int32_t>& doflist,
627  std::uint32_t cell_permutation) const;
628 
640  std::function<void(const xtl::span<std::int32_t>&, std::uint32_t)>
641  get_dof_permutation_function(bool inverse = false,
642  bool scalar_element = false) const;
643 
644 private:
645  std::string _signature, _family;
646 
647  mesh::CellType _cell_shape;
648 
649  int _tdim, _space_dim, _value_size, _reference_value_size;
650 
651  // List of sub-elements (if any)
652  std::vector<std::shared_ptr<const FiniteElement>> _sub_elements;
653 
654  // Simple hash of the signature string
655  std::size_t _hash;
656 
657  // Dimension of each value space
658  std::vector<int> _value_dimension;
659 
660  // Block size for VectorElements and TensorElements. This gives the
661  // number of DOFs colocated at each point.
662  int _bs;
663 
664  // Indicate whether the element needs permutations or transformations
665  bool _needs_dof_permutations;
666  bool _needs_dof_transformations;
667 
668  // Basix Element (nullptr for mixed elements)
669  std::unique_ptr<basix::FiniteElement> _element;
670 };
671 } // namespace dolfinx::fem
dolfinx::fem::FiniteElement::permute_dofs
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:263
dolfinx::fem::FiniteElement::FiniteElement
FiniteElement(const ufc_finite_element &ufc_element)
Create finite element from UFC finite element.
Definition: FiniteElement.cpp:80
dolfinx::fem::FiniteElement::block_size
int block_size() const noexcept
Block size of the finite element function space. For VectorElements and TensorElements,...
Definition: FiniteElement.cpp:181
dolfinx::fem::FiniteElement::interpolation_ident
bool interpolation_ident() const noexcept
Check if interpolation into the finite element space is an identity operation given the evaluation on...
Definition: FiniteElement.cpp:235
dolfinx::fem::FiniteElement::extract_sub_element
std::shared_ptr< const FiniteElement > extract_sub_element(const std::vector< int > &component) const
Extract sub finite element for component.
Definition: FiniteElement.cpp:225
dolfinx::fem::FiniteElement::unpermute_dofs
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:269
dolfinx::fem::FiniteElement::value_dimension
int value_dimension(int i) const
Return the dimension of the value space for axis i.
Definition: FiniteElement.cpp:183
dolfinx::fem::FiniteElement::apply_inverse_transpose_dof_transformation_to_transpose
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:580
dolfinx::fem::FiniteElement::interpolation_points
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:241
dolfinx::fem::FiniteElement::transform_reference_basis
void transform_reference_basis(xt::xtensor< double, 3 > &values, const xt::xtensor< double, 3 > &reference_values, const xt::xtensor< double, 3 > &J, const xtl::span< const double > &detJ, const xt::xtensor< double, 3 > &K) const
Push basis functions forward to physical element.
Definition: FiniteElement.cpp:200
dolfinx::fem::FiniteElement::get_dof_permutation_function
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 transformation to some data.
Definition: FiniteElement.cpp:276
dolfinx::mesh::CellType
CellType
Cell type identifier.
Definition: cell_types.h:21
dolfinx::fem::FiniteElement::reference_value_size
int reference_value_size() const noexcept
The value size, e.g. 1 for a scalar function, 2 for a 2D vector for the reference element.
Definition: FiniteElement.cpp:171
dolfinx::fem::FiniteElement::apply_dof_transformation
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:470
dolfinx::fem::FiniteElement::num_sub_elements
int num_sub_elements() const noexcept
Get the number of sub elements (for a mixed element)
Definition: FiniteElement.cpp:210
dolfinx::fem::FiniteElement
Finite Element, containing the dof layout on a reference element, and various methods for evaluating ...
Definition: FiniteElement.h:24
dolfinx::fem::FiniteElement::apply_transpose_dof_transformation
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:503
dolfinx::fem::FiniteElement::needs_dof_permutations
bool needs_dof_permutations() const noexcept
Check if DOF permutations are needed for this element.
Definition: FiniteElement.cpp:258
dolfinx::fem::FiniteElement::hash
std::size_t hash() const noexcept
Return simple hash of the signature string.
Definition: FiniteElement.cpp:222
dolfinx::fem::FiniteElement::value_size
int value_size() const noexcept
The value size, e.g. 1 for a scalar function, 2 for a 2D vector.
Definition: FiniteElement.cpp:169
dolfinx::fem::FiniteElement::space_dimension
int space_dimension() const noexcept
Dimension of the finite element function space.
Definition: FiniteElement.cpp:167
dolfinx::fem::FiniteElement::family
std::string family() const noexcept
The finite element family.
Definition: FiniteElement.cpp:191
dolfinx::fem::FiniteElement::interpolate
constexpr void interpolate(const xt::xtensor< T, 2 > &values, xtl::span< T > dofs) const
Definition: FiniteElement.h:152
dolfinx::fem::FiniteElement::apply_inverse_dof_transformation_to_transpose
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:550
dolfinx::fem::FiniteElement::operator=
FiniteElement & operator=(const FiniteElement &element)=delete
Copy assignment.
dolfinx::fem::FiniteElement::~FiniteElement
virtual ~FiniteElement()=default
Destructor.
dolfinx::fem::FiniteElement::value_rank
int value_rank() const noexcept
Rank of the value space.
Definition: FiniteElement.cpp:176
dolfinx::fem::FiniteElement::cell_shape
mesh::CellType cell_shape() const noexcept
Cell shape.
Definition: FiniteElement.cpp:162
dolfinx::fem::FiniteElement::apply_inverse_transpose_dof_transformation
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:487
dolfinx::fem::FiniteElement::signature
std::string signature() const noexcept
String identifying the finite element.
Definition: FiniteElement.cpp:160
dolfinx::fem::FiniteElement::tabulate
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:193
dolfinx::fem::FiniteElement::sub_elements
const std::vector< std::shared_ptr< const FiniteElement > > & sub_elements() const noexcept
Subelements (if any)
Definition: FiniteElement.cpp:216
dolfinx::fem::FiniteElement::needs_dof_transformations
bool needs_dof_transformations() const noexcept
Check if DOF transformations are needed for this element.
Definition: FiniteElement.cpp:253
dolfinx::fem
Finite element method functionality.
Definition: assemble_matrix_impl.h:22
dolfinx::fem::FiniteElement::map_pull_back
void map_pull_back(const O &u, const P &J, const Q &detJ, const T &K, S &&U) const
Pull back data from the physical element to the reference element. It can process batches of points t...
Definition: FiniteElement.h:608
dolfinx::fem::FiniteElement::get_dof_transformation_function
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:226
dolfinx::fem::FiniteElement::get_dof_transformation_to_transpose_function
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:347
dolfinx::fem::FiniteElement::apply_transpose_dof_transformation_to_transpose
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:565
dolfinx::fem::FiniteElement::apply_dof_transformation_to_transpose
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 tranposed data.
Definition: FiniteElement.h:534
dolfinx::fem::FiniteElement::apply_inverse_dof_transformation
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:519