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.4.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 <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 
17 struct ufcx_finite_element;
18 
19 namespace dolfinx::fem
20 {
24 {
25 public:
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>
223  create_interpolation_operator(const FiniteElement& from) const;
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,
317  cell, block_size);
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 
677 private:
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
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
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
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
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
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(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
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
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: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
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
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
FiniteElement & operator=(const FiniteElement &element)=delete
Copy assignment.
int block_size() const noexcept
Block size of the finite element function space. For VectorElements and TensorElements,...
Definition: FiniteElement.cpp:316
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