Basix
Loading...
Searching...
No Matches
finite-element.h
1// Copyright (c) 2020-2024 Chris Richardson, Matthew Scroggs and Garth . Wells
2// FEniCS Project
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include "cell.h"
8#include "element-families.h"
9#include "maps.h"
10#include "mdspan.hpp"
11#include "polyset.h"
12#include "precompute.h"
13#include "sobolev-spaces.h"
14#include <array>
15#include <concepts>
16#include <cstdint>
17#include <functional>
18#include <map>
19#include <numeric>
20#include <optional>
21#include <span>
22#include <string>
23#include <tuple>
24#include <utility>
25#include <vector>
26
28namespace basix
29{
30namespace impl
31{
32template <typename T, std::size_t d>
33using mdspan_t = md::mdspan<T, md::dextents<std::size_t, d>>;
34template <typename T, std::size_t d>
35using mdarray_t
36 = md::MDSPAN_IMPL_PROPOSED_NAMESPACE::mdarray<T,
37 md::dextents<std::size_t, d>>;
38
41template <typename T>
42std::array<std::vector<mdspan_t<const T, 2>>, 4>
43to_mdspan(std::array<std::vector<mdarray_t<T, 2>>, 4>& x)
44{
45 std::array<std::vector<mdspan_t<const T, 2>>, 4> x1;
46 for (std::size_t i = 0; i < x.size(); ++i)
47 for (std::size_t j = 0; j < x[i].size(); ++j)
48 x1[i].emplace_back(x[i][j].data(), x[i][j].extents());
49
50 return x1;
51}
52
55template <typename T>
56std::array<std::vector<mdspan_t<const T, 4>>, 4>
57to_mdspan(std::array<std::vector<mdarray_t<T, 4>>, 4>& M)
58{
59 std::array<std::vector<mdspan_t<const T, 4>>, 4> M1;
60 for (std::size_t i = 0; i < M.size(); ++i)
61 for (std::size_t j = 0; j < M[i].size(); ++j)
62 M1[i].emplace_back(M[i][j].data(), M[i][j].extents());
63
64 return M1;
65}
66
69template <typename T>
70std::array<std::vector<mdspan_t<const T, 2>>, 4>
71to_mdspan(const std::array<std::vector<std::vector<T>>, 4>& x,
72 const std::array<std::vector<std::array<std::size_t, 2>>, 4>& shape)
73{
74 std::array<std::vector<mdspan_t<const T, 2>>, 4> x1;
75 for (std::size_t i = 0; i < x.size(); ++i)
76 for (std::size_t j = 0; j < x[i].size(); ++j)
77 x1[i].push_back(mdspan_t<const T, 2>(x[i][j].data(), shape[i][j]));
78
79 return x1;
80}
81
84template <typename T>
85std::array<std::vector<mdspan_t<const T, 4>>, 4>
86to_mdspan(const std::array<std::vector<std::vector<T>>, 4>& M,
87 const std::array<std::vector<std::array<std::size_t, 4>>, 4>& shape)
88{
89 std::array<std::vector<mdspan_t<const T, 4>>, 4> M1;
90 for (std::size_t i = 0; i < M.size(); ++i)
91 for (std::size_t j = 0; j < M[i].size(); ++j)
92 M1[i].push_back(mdspan_t<const T, 4>(M[i][j].data(), shape[i][j]));
93
94 return M1;
95}
96
97} // namespace impl
98
99namespace element
100{
102template <typename T, std::size_t d>
103using mdspan_t = impl::mdspan_t<T, d>;
104
120template <std::floating_point T>
121std::tuple<std::array<std::vector<std::vector<T>>, 4>,
122 std::array<std::vector<std::array<std::size_t, 2>>, 4>,
123 std::array<std::vector<std::vector<T>>, 4>,
124 std::array<std::vector<std::array<std::size_t, 4>>, 4>>
125make_discontinuous(const std::array<std::vector<mdspan_t<const T, 2>>, 4>& x,
126 const std::array<std::vector<mdspan_t<const T, 4>>, 4>& M,
127 std::size_t tdim, std::size_t value_size);
128
129} // namespace element
130
136template <std::floating_point F>
138{
139 template <typename T, std::size_t d>
140 using mdspan_t = md::mdspan<T, md::dextents<std::size_t, d>>;
141
142public:
144 using scalar_type = F;
145
319 polyset::type poly_type, int degree,
320 const std::vector<std::size_t>& value_shape,
321 mdspan_t<const F, 2> wcoeffs,
322 const std::array<std::vector<mdspan_t<const F, 2>>, 4>& x,
323 const std::array<std::vector<mdspan_t<const F, 4>>, 4>& M,
328 element::dpc_variant dvariant,
329 std::vector<int> dof_ordering = {});
330
333
336
338 ~FiniteElement() = default;
339
342
345
350 bool operator==(const FiniteElement& e) const;
351
353 std::size_t hash() const;
354
364 std::array<std::size_t, 4> tabulate_shape(std::size_t nd,
365 std::size_t num_points) const
366 {
367 std::size_t ndsize = 1;
368 for (std::size_t i = 1; i <= nd; ++i)
369 ndsize *= (_cell_tdim + i);
370 for (std::size_t i = 1; i <= nd; ++i)
371 ndsize /= i;
372 std::size_t vs = std::accumulate(_value_shape.begin(), _value_shape.end(),
373 1, std::multiplies{});
374 std::size_t ndofs = _coeffs.second[0];
375 return {ndsize, num_points, ndofs, vs};
376 }
377
399 std::pair<std::vector<F>, std::array<std::size_t, 4>>
400 tabulate(int nd, impl::mdspan_t<const F, 2> x) const;
401
425 std::pair<std::vector<F>, std::array<std::size_t, 4>>
426 tabulate(int nd, std::span<const F> x,
427 std::array<std::size_t, 2> shape) const;
428
454 void tabulate(int nd, impl::mdspan_t<const F, 2> x,
455 mdspan_t<F, 4> basis) const;
456
482 void tabulate(int nd, std::span<const F> x, std::array<std::size_t, 2> xshape,
483 std::span<F> basis) const;
484
487 cell::type cell_type() const { return _cell_type; }
488
491 polyset::type polyset_type() const { return _poly_type; }
492
495 int degree() const { return _degree; }
496
501 int embedded_superdegree() const { return _embedded_superdegree; }
502
506 int embedded_subdegree() const { return _embedded_subdegree; }
507
513 const std::vector<std::size_t>& value_shape() const { return _value_shape; }
514
519 int dim() const { return _coeffs.second[0]; }
520
523 element::family family() const { return _family; }
524
528 {
529 return _lagrange_variant;
530 }
531
534 element::dpc_variant dpc_variant() const { return _dpc_variant; }
535
538 maps::type map_type() const { return _map_type; }
539
542 sobolev::space sobolev_space() const { return _sobolev_space; }
543
548 bool discontinuous() const { return _discontinuous; }
549
553 {
554 return _dof_transformations_are_permutations;
555 }
556
559 {
560 return _dof_transformations_are_identity;
561 }
562
577 std::pair<std::vector<F>, std::array<std::size_t, 3>>
578 push_forward(impl::mdspan_t<const F, 3> U, impl::mdspan_t<const F, 3> J,
579 std::span<const F> detJ, impl::mdspan_t<const F, 3> K) const;
580
588 std::pair<std::vector<F>, std::array<std::size_t, 3>>
589 pull_back(impl::mdspan_t<const F, 3> u, impl::mdspan_t<const F, 3> J,
590 std::span<const F> detJ, impl::mdspan_t<const F, 3> K) const;
591
623 template <typename O, typename P, typename Q, typename R>
624 std::function<void(O&, const P&, const Q&, F, const R&)> map_fn() const
625 {
626 switch (_map_type)
627 {
628 case maps::type::identity:
629 return [](O& u, const P& U, const Q&, F, const R&)
630 {
631 assert(U.extent(0) == u.extent(0));
632 assert(U.extent(1) == u.extent(1));
633 for (std::size_t i = 0; i < U.extent(0); ++i)
634 for (std::size_t j = 0; j < U.extent(1); ++j)
635 u(i, j) = U(i, j);
636 };
637 case maps::type::covariantPiola:
638 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
639 { maps::covariant_piola(u, U, J, detJ, K); };
640 case maps::type::contravariantPiola:
641 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
642 { maps::contravariant_piola(u, U, J, detJ, K); };
643 case maps::type::doubleCovariantPiola:
644 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
645 { maps::double_covariant_piola(u, U, J, detJ, K); };
646 case maps::type::doubleContravariantPiola:
647 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
648 { maps::double_contravariant_piola(u, U, J, detJ, K); };
649 default:
650 throw std::runtime_error("Map not implemented");
651 }
652 }
653
661 const std::vector<std::vector<std::vector<int>>>& entity_dofs() const
662 {
663 return _edofs;
664 }
665
675 const std::vector<std::vector<std::vector<int>>>& entity_closure_dofs() const
676 {
677 return _e_closure_dofs;
678 }
679
761 std::pair<std::vector<F>, std::array<std::size_t, 3>>
762 base_transformations() const;
763
768 std::map<cell::type, std::pair<std::vector<F>, std::array<std::size_t, 3>>>
770 {
771 return _entity_transformations;
772 }
773
796 void permute(std::span<std::int32_t> d, std::uint32_t cell_info) const
797 {
798 if (!_dof_transformations_are_permutations)
799 {
800 throw std::runtime_error(
801 "The DOF transformations for this element are not permutations");
802 }
803
804 if (_dof_transformations_are_identity)
805 return;
806 else
807 permute_data<std::int32_t, false>(d, 1, cell_info, _eperm);
808 }
809
827 void permute_inv(std::span<std::int32_t> d, std::uint32_t cell_info) const
828 {
829 if (!_dof_transformations_are_permutations)
830 {
831 throw std::runtime_error(
832 "The DOF transformations for this element are not permutations");
833 }
834
835 if (_dof_transformations_are_identity)
836 return;
837 else
838 permute_data<std::int32_t, true>(d, 1, cell_info, _eperm_inv);
839 }
840
856 void permute_subentity_closure(std::span<std::int32_t> d,
857 std::uint32_t cell_info,
858 cell::type entity_type, int entity_index) const
859 {
860 const int entity_dim = cell::topological_dimension(entity_type);
861
862 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
863
864 std::uint32_t entity_info = 0;
865 switch (entity_dim)
866 {
867 case 0:
868 return;
869 case 1:
870 entity_info = cell_info >> (face_start + entity_index) & 1;
871 break;
872 case 2:
873 entity_info = cell_info >> (3 * entity_index) & 7;
874 break;
875 default:
876 throw std::runtime_error("Unsupported cell dimension");
877 }
878 permute_subentity_closure(d, entity_info, entity_type);
879 }
880
893 void permute_subentity_closure_inv(std::span<std::int32_t> d,
894 std::uint32_t cell_info,
895 cell::type entity_type,
896 int entity_index) const
897 {
898 const int entity_dim = cell::topological_dimension(entity_type);
899
900 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
901
902 std::uint32_t entity_info;
903 switch (entity_dim)
904 {
905 case 0:
906 return;
907 case 1:
908 entity_info = cell_info >> (face_start + entity_index) & 1;
909 break;
910 case 2:
911 entity_info = cell_info >> (3 * entity_index) & 7;
912 break;
913 default:
914 throw std::runtime_error("Unsupported cell dimension");
915 }
916 permute_subentity_closure_inv(d, entity_info, entity_type);
917 }
918
933
934 void permute_subentity_closure(std::span<std::int32_t> d,
935 std::uint32_t entity_info,
936 cell::type entity_type) const
937 {
938 if (!_dof_transformations_are_permutations)
939 {
940 throw std::runtime_error(
941 "The DOF transformations for this element are not permutations");
942 }
943
944 const int entity_dim = cell::topological_dimension(entity_type);
945
946 if (entity_dim == 0)
947 return;
948
949 auto& perm = _subentity_closure_perm.at(entity_type);
950 if (entity_dim == 1)
951 {
952 if (entity_info & 1)
953 {
955 }
956 }
957 else if (entity_dim == 2)
958 {
959 // Rotate a face
960 for (std::uint32_t r = 0; r < (entity_info >> 1 & 3); ++r)
961 {
963 }
964
965 // Reflect a face (post rotate)
966 if (entity_info & 1)
967 {
969 }
970 }
971 else
972 {
973 throw std::runtime_error(
974 "Invalid dimension for permute_subentity_closure");
975 }
976 }
977
989 void permute_subentity_closure_inv(std::span<std::int32_t> d,
990 std::uint32_t entity_info,
991 cell::type entity_type) const
992 {
993 if (!_dof_transformations_are_permutations)
994 {
995 throw std::runtime_error(
996 "The DOF transformations for this element are not permutations");
997 }
998
999 const int entity_dim = cell::topological_dimension(entity_type);
1000
1001 if (entity_dim == 0)
1002 return;
1003
1004 auto& perm = _subentity_closure_perm_inv.at(entity_type);
1005 if (entity_dim == 1)
1006 {
1007 if (entity_info & 1)
1008 {
1010 }
1011 }
1012 else if (entity_dim == 2)
1013 {
1014 // Reflect a face (pre rotate)
1015 if (entity_info & 1)
1016 {
1018 }
1019
1020 // Rotate a face
1021 for (std::uint32_t r = 0; r < (entity_info >> 1 & 3); ++r)
1022 {
1024 }
1025 }
1026 else
1027 {
1028 throw std::runtime_error(
1029 "Invalid dimension for permute_subentity_closure");
1030 }
1031 }
1032
1063 template <typename T>
1064 void T_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1065
1076 template <typename T>
1077 void Tt_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1078
1090 template <typename T>
1091 void Tt_inv_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1092
1103 template <typename T>
1104 void Tinv_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1105
1116 template <typename T>
1117 void Tt_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1118
1128 template <typename T>
1129 void T_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1130
1141 template <typename T>
1142 void Tinv_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1143
1154 template <typename T>
1155 void Tt_inv_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1156
1163 const std::pair<std::vector<F>, std::array<std::size_t, 2>>& points() const
1164 {
1165 return _points;
1166 }
1167
1219 const std::pair<std::vector<F>, std::array<std::size_t, 2>>&
1221 {
1222 return _matM;
1223 }
1224
1230 const std::pair<std::vector<F>, std::array<std::size_t, 2>>&
1232 {
1233 return _dual_matrix;
1234 }
1235
1272 const std::pair<std::vector<F>, std::array<std::size_t, 2>>& wcoeffs() const
1273 {
1274 return _wcoeffs;
1275 }
1276
1281 const std::array<
1282 std::vector<std::pair<std::vector<F>, std::array<std::size_t, 2>>>, 4>&
1283 x() const
1284 {
1285 return _x;
1286 }
1287
1324 const std::array<
1325 std::vector<std::pair<std::vector<F>, std::array<std::size_t, 4>>>, 4>&
1326 M() const
1327 {
1328 return _M;
1329 }
1330
1334 const std::pair<std::vector<F>, std::array<std::size_t, 2>>&
1336 {
1337 return _coeffs;
1338 }
1339
1351 {
1352 return !_tensor_factors.empty();
1353 }
1354
1367 std::vector<std::vector<FiniteElement<F>>>
1369 {
1371 throw std::runtime_error("Element has no tensor product representation.");
1372 return _tensor_factors;
1373 }
1374
1379 bool interpolation_is_identity() const { return _interpolation_is_identity; }
1380
1382 int interpolation_nderivs() const { return _interpolation_nderivs; }
1383
1385 const std::vector<int>& dof_ordering() const { return _dof_ordering; }
1386
1387private:
1394 template <typename T, bool post>
1395 void permute_data(
1396 std::span<T> data, int block_size, std::uint32_t cell_info,
1397 const std::map<cell::type, std::vector<std::vector<std::size_t>>>& eperm)
1398 const;
1399
1400 using array2_t = std::pair<std::vector<F>, std::array<std::size_t, 2>>;
1401 using array3_t = std::pair<std::vector<F>, std::array<std::size_t, 3>>;
1402 using trans_data_t
1403 = std::vector<std::pair<std::vector<std::size_t>, array2_t>>;
1404
1411 template <typename T, bool post, typename OP>
1412 void
1413 transform_data(std::span<T> data, int block_size, std::uint32_t cell_info,
1414 const std::map<cell::type, trans_data_t>& etrans, OP op) const;
1415
1416 // Cell type
1417 cell::type _cell_type;
1418
1419 // Polyset type
1420 polyset::type _poly_type;
1421
1422 // Topological dimension of the cell
1423 std::size_t _cell_tdim;
1424
1425 // Topological dimension of the cell
1426 std::vector<std::vector<cell::type>> _cell_subentity_types;
1427
1428 // Finite element family
1429 element::family _family;
1430
1431 // Lagrange variant
1432 element::lagrange_variant _lagrange_variant;
1433
1434 // DPC variant
1435 element::dpc_variant _dpc_variant;
1436
1437 // Degree that was input when creating the element
1438 int _degree;
1439
1440 // Degree
1441 int _interpolation_nderivs;
1442
1443 // Highest degree polynomial in element's polyset
1444 int _embedded_superdegree;
1445
1446 // Highest degree space that is a subspace of element's polyset
1447 int _embedded_subdegree;
1448
1449 // Value shape
1450 std::vector<std::size_t> _value_shape;
1451
1453 maps::type _map_type;
1454
1456 sobolev::space _sobolev_space;
1457
1458 // Shape function coefficient of expansion sets on cell. If shape
1459 // function is given by @f$\psi_i = \sum_{k} \phi_{k}
1460 // \alpha^{i}_{k}@f$, then _coeffs(i, j) = @f$\alpha^i_k@f$. ie
1461 // _coeffs.row(i) are the expansion coefficients for shape function i
1462 // (@f$\psi_{i}@f$).
1463 std::pair<std::vector<F>, std::array<std::size_t, 2>> _coeffs;
1464
1465 // Dofs associated with each cell (sub-)entity
1466 std::vector<std::vector<std::vector<int>>> _edofs;
1467
1468 // Dofs associated with the closdure of each cell (sub-)entity
1469 std::vector<std::vector<std::vector<int>>> _e_closure_dofs;
1470
1471 // Entity transformations
1472 std::map<cell::type, array3_t> _entity_transformations;
1473
1474 // Set of points used for point evaluation
1475 // Experimental - currently used for an implementation of
1476 // "tabulate_dof_coordinates" Most useful for Lagrange. This may change or go
1477 // away. For non-Lagrange elements, these points will be used in combination
1478 // with _interpolation_matrix to perform interpolation
1479 std::pair<std::vector<F>, std::array<std::size_t, 2>> _points;
1480
1481 // Interpolation points on the cell. The shape is (entity_dim, num
1482 // entities of given dimension, num_points, tdim)
1483 std::array<std::vector<std::pair<std::vector<F>, std::array<std::size_t, 2>>>,
1484 4>
1485 _x;
1486
1488 std::pair<std::vector<F>, std::array<std::size_t, 2>> _matM;
1489
1490 // Indicates whether or not the DOF transformations are all
1491 // permutations
1492 bool _dof_transformations_are_permutations;
1493
1494 // Indicates whether or not the DOF transformations are all identity
1495 bool _dof_transformations_are_identity;
1496
1497 // The entity permutations (factorised). This will only be set if
1498 // _dof_transformations_are_permutations is True and
1499 // _dof_transformations_are_identity is False
1500 std::map<cell::type, std::vector<std::vector<std::size_t>>> _eperm;
1501
1502 // The reverse entity permutations (factorised). This will only be set
1503 // if _dof_transformations_are_permutations is True and
1504 // _dof_transformations_are_identity is False
1505 std::map<cell::type, std::vector<std::vector<std::size_t>>> _eperm_inv;
1506
1507 // The entity transformations in precomputed form
1508 std::map<cell::type, trans_data_t> _etrans;
1509
1510 // The transposed entity transformations in precomputed form
1511 std::map<cell::type, trans_data_t> _etransT;
1512
1513 // The inverse entity transformations in precomputed form
1514 std::map<cell::type, trans_data_t> _etrans_inv;
1515
1516 // The inverse transpose entity transformations in precomputed form
1517 std::map<cell::type, trans_data_t> _etrans_invT;
1518
1519 // The subentity closure permutations (factorised). This will only be set if
1520 // _dof_transformations_are_permutations is True
1521 std::map<cell::type, std::vector<std::vector<std::size_t>>>
1522 _subentity_closure_perm;
1523
1524 // The inverse subentity closure permutations (factorised). This will only be
1525 // set if _dof_transformations_are_permutations is True
1526 std::map<cell::type, std::vector<std::vector<std::size_t>>>
1527 _subentity_closure_perm_inv;
1528
1529 // Indicates whether or not this is the discontinuous version of the
1530 // element
1531 bool _discontinuous;
1532
1533 // The dual matrix
1534 std::pair<std::vector<F>, std::array<std::size_t, 2>> _dual_matrix;
1535
1536 // Dof reordering for different element dof layout compatibility.
1537 // The reference basix layout is ordered by entity, i.e. dofs on
1538 // vertices, followed by edges, faces, then internal dofs.
1539 // _dof_ordering stores the map to the new order required, e.g.
1540 // for a P2 triangle, _dof_ordering=[0 3 5 1 2 4] will place
1541 // dofs 0, 3, 5 on the vertices and 1, 2, 4, on the edges.
1542 std::vector<int> _dof_ordering;
1543
1544 // Tensor product representation
1545 // Entries of tuple are (list of elements on an interval, permutation
1546 // of DOF numbers)
1547 // @todo: For vector-valued elements, a tensor product type and a
1548 // scaling factor may additionally be needed.
1549 std::vector<std::vector<FiniteElement>> _tensor_factors;
1550
1551 // Is the interpolation matrix an identity?
1552 bool _interpolation_is_identity;
1553
1554 // The coefficients that define the polynomial set in terms of the
1555 // orthonormal polynomials
1556 std::pair<std::vector<F>, std::array<std::size_t, 2>> _wcoeffs;
1557
1558 // Interpolation matrices for each entity
1559 using array4_t
1560 = std::vector<std::pair<std::vector<F>, std::array<std::size_t, 4>>>;
1561 std::array<array4_t, 4> _M;
1562};
1563
1589template <std::floating_point T>
1590FiniteElement<T> create_custom_element(
1591 cell::type cell_type, const std::vector<std::size_t>& value_shape,
1592 impl::mdspan_t<const T, 2> wcoeffs,
1593 const std::array<std::vector<impl::mdspan_t<const T, 2>>, 4>& x,
1594 const std::array<std::vector<impl::mdspan_t<const T, 4>>, 4>& M,
1595 int interpolation_nderivs, maps::type map_type,
1596 sobolev::space sobolev_space, bool discontinuous, int embedded_subdegree,
1597 int embedded_superdegree, polyset::type poly_type);
1598
1610template <std::floating_point T>
1611FiniteElement<T> create_element(element::family family, cell::type cell,
1612 int degree, element::lagrange_variant lvariant,
1613 element::dpc_variant dvariant,
1614 bool discontinuous,
1615 std::vector<int> dof_ordering = {});
1616
1629std::optional<std::vector<int>>
1632 element::dpc_variant dvariant, bool discontinuous);
1633
1644std::vector<int> lex_dof_ordering(element::family family, cell::type cell,
1645 int degree, element::lagrange_variant lvariant,
1646 element::dpc_variant dvariant,
1647 bool discontinuous);
1648
1662template <std::floating_point T>
1663std::optional<std::vector<std::vector<FiniteElement<T>>>>
1664tp_factors(element::family family, cell::type cell, int degree,
1666 bool discontinuous, const std::vector<int>& dof_ordering);
1667
1679template <std::floating_point T>
1683 element::dpc_variant dvariant, bool discontinuous);
1684
1687std::string version();
1688
1689//-----------------------------------------------------------------------------
1690template <std::floating_point F>
1691template <typename T, bool post>
1692void FiniteElement<F>::permute_data(
1693 std::span<T> data, int block_size, std::uint32_t cell_info,
1694 const std::map<cell::type, std::vector<std::vector<std::size_t>>>& eperm)
1695 const
1696{
1697 if (_cell_tdim >= 2)
1698 {
1699 // This assumes 3 bits are used per face. This will need updating if 3D
1700 // cells with faces with more than 4 sides are implemented
1701 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
1702
1703 // Permute DOFs on edges
1704 {
1705 auto& trans = eperm.at(cell::type::interval)[0];
1706 for (std::size_t e = 0; e < _edofs[1].size(); ++e)
1707 {
1708 // Reverse an edge
1709 if (cell_info >> (face_start + e) & 1)
1710 {
1711 precompute::apply_permutation_mapped(trans, data, _edofs[1][e],
1712 block_size);
1713 }
1714 }
1715 }
1716
1717 if (_cell_tdim == 3)
1718 {
1719 // Permute DOFs on faces
1720 for (std::size_t f = 0; f < _edofs[2].size(); ++f)
1721 {
1722 auto& trans = eperm.at(_cell_subentity_types[2][f]);
1723
1724 // Reflect a face (pre rotate)
1725 if (!post and cell_info >> (3 * f) & 1)
1726 {
1727 precompute::apply_permutation_mapped(trans[1], data, _edofs[2][f],
1728 block_size);
1729 }
1730
1731 // Rotate a face
1732 for (std::uint32_t r = 0; r < (cell_info >> (3 * f + 1) & 3); ++r)
1733 {
1734 precompute::apply_permutation_mapped(trans[0], data, _edofs[2][f],
1735 block_size);
1736 }
1737
1738 // Reflect a face (post rotate)
1739 if (post and cell_info >> (3 * f) & 1)
1740 {
1741 precompute::apply_permutation_mapped(trans[1], data, _edofs[2][f],
1742 block_size);
1743 }
1744 }
1745 }
1746 }
1747}
1748//-----------------------------------------------------------------------------
1749template <std::floating_point F>
1750template <typename T, bool post, typename OP>
1751void FiniteElement<F>::transform_data(
1752 std::span<T> data, int block_size, std::uint32_t cell_info,
1753 const std::map<cell::type, trans_data_t>& etrans, OP op) const
1754{
1755 if (_cell_tdim >= 2)
1756 {
1757 // This assumes 3 bits are used per face. This will need updating if
1758 // 3D cells with faces with more than 4 sides are implemented
1759 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
1760 int dofstart = 0;
1761 for (auto& edofs0 : _edofs[0])
1762 dofstart += edofs0.size();
1763
1764 // Transform DOFs on edges
1765 {
1766 auto& [v_size_t, matrix] = etrans.at(cell::type::interval)[0];
1767 for (std::size_t e = 0; e < _edofs[1].size(); ++e)
1768 {
1769 // Reverse an edge
1770 if (cell_info >> (face_start + e) & 1)
1771 {
1772 op(std::span(v_size_t),
1773 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1774 dofstart, block_size);
1775 }
1776 dofstart += _edofs[1][e].size();
1777 }
1778 }
1779
1780 if (_cell_tdim == 3)
1781 {
1782 // Permute DOFs on faces
1783 for (std::size_t f = 0; f < _edofs[2].size(); ++f)
1784 {
1785 auto& trans = etrans.at(_cell_subentity_types[2][f]);
1786
1787 // Reflect a face (pre rotation)
1788 if (!post and cell_info >> (3 * f) & 1)
1789 {
1790 const auto& m = trans[1];
1791 const auto& v_size_t = std::get<0>(m);
1792 const auto& matrix = std::get<1>(m);
1793 op(std::span(v_size_t),
1794 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1795 dofstart, block_size);
1796 }
1797
1798 // Rotate a face
1799 for (std::uint32_t r = 0; r < (cell_info >> (3 * f + 1) & 3); ++r)
1800 {
1801 const auto& m = trans[0];
1802 const auto& v_size_t = std::get<0>(m);
1803 const auto& matrix = std::get<1>(m);
1804 op(std::span(v_size_t),
1805 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1806 dofstart, block_size);
1807 }
1808
1809 // Reflect a face (post rotation)
1810 if (post and cell_info >> (3 * f) & 1)
1811 {
1812 const auto& m = trans[1];
1813 const auto& v_size_t = std::get<0>(m);
1814 const auto& matrix = std::get<1>(m);
1815 op(std::span(v_size_t),
1816 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1817 dofstart, block_size);
1818 }
1819
1820 dofstart += _edofs[2][f].size();
1821 }
1822 }
1823 }
1824}
1825//-----------------------------------------------------------------------------
1826template <std::floating_point F>
1827template <typename T>
1828void FiniteElement<F>::T_apply(std::span<T> u, int n,
1829 std::uint32_t cell_info) const
1830{
1831 if (_dof_transformations_are_identity)
1832 return;
1833
1834 if (_dof_transformations_are_permutations)
1835 permute_data<T, false>(u, n, cell_info, _eperm);
1836 else
1837 {
1838 transform_data<T, false>(u, n, cell_info, _etrans,
1840 }
1841}
1842//-----------------------------------------------------------------------------
1843template <std::floating_point F>
1844template <typename T>
1845void FiniteElement<F>::Tt_apply(std::span<T> u, int n,
1846 std::uint32_t cell_info) const
1847{
1848 if (_dof_transformations_are_identity)
1849 return;
1850 else if (_dof_transformations_are_permutations)
1851 permute_data<T, true>(u, n, cell_info, _eperm_inv);
1852 else
1853 {
1854 transform_data<T, true>(u, n, cell_info, _etransT,
1856 }
1857}
1858//-----------------------------------------------------------------------------
1859template <std::floating_point F>
1860template <typename T>
1861void FiniteElement<F>::Tt_inv_apply(std::span<T> u, int n,
1862 std::uint32_t cell_info) const
1863{
1864 if (_dof_transformations_are_identity)
1865 return;
1866 else if (_dof_transformations_are_permutations)
1867 permute_data<T, false>(u, n, cell_info, _eperm);
1868 else
1869 {
1870 transform_data<T, false>(u, n, cell_info, _etrans_invT,
1872 }
1873}
1874//-----------------------------------------------------------------------------
1875template <std::floating_point F>
1876template <typename T>
1877void FiniteElement<F>::Tinv_apply(std::span<T> u, int n,
1878 std::uint32_t cell_info) const
1879{
1880 if (_dof_transformations_are_identity)
1881 return;
1882 else if (_dof_transformations_are_permutations)
1883 permute_data<T, true>(u, n, cell_info, _eperm_inv);
1884 else
1885 {
1886 transform_data<T, true>(u, n, cell_info, _etrans_inv,
1888 }
1889}
1890//-----------------------------------------------------------------------------
1891template <std::floating_point F>
1892template <typename T>
1893void FiniteElement<F>::Tt_apply_right(std::span<T> u, int n,
1894 std::uint32_t cell_info) const
1895{
1896 if (_dof_transformations_are_identity)
1897 return;
1898 else if (_dof_transformations_are_permutations)
1899 {
1900 assert(u.size() % n == 0);
1901 const int step = u.size() / n;
1902 for (int i = 0; i < n; ++i)
1903 {
1904 std::span<T> dblock(u.data() + i * step, step);
1905 permute_data<T, false>(dblock, 1, cell_info, _eperm);
1906 }
1907 }
1908 else
1909 {
1910 transform_data<T, false>(u, n, cell_info, _etrans,
1912 }
1913}
1914//-----------------------------------------------------------------------------
1915template <std::floating_point F>
1916template <typename T>
1917void FiniteElement<F>::Tinv_apply_right(std::span<T> u, int n,
1918 std::uint32_t cell_info) const
1919{
1920 if (_dof_transformations_are_identity)
1921 return;
1922 else if (_dof_transformations_are_permutations)
1923 {
1924 assert(u.size() % n == 0);
1925 const int step = u.size() / n;
1926 for (int i = 0; i < n; ++i)
1927 {
1928 std::span<T> dblock(u.data() + i * step, step);
1929 permute_data<T, false>(dblock, 1, cell_info, _eperm);
1930 }
1931 }
1932 else
1933 {
1934 transform_data<T, false>(u, n, cell_info, _etrans_invT,
1936 }
1937}
1938//-----------------------------------------------------------------------------
1939template <std::floating_point F>
1940template <typename T>
1941void FiniteElement<F>::T_apply_right(std::span<T> u, int n,
1942 std::uint32_t cell_info) const
1943{
1944 if (_dof_transformations_are_identity)
1945 return;
1946 else if (_dof_transformations_are_permutations)
1947 {
1948 assert(u.size() % n == 0);
1949 const int step = u.size() / n;
1950 for (int i = 0; i < n; ++i)
1951 {
1952 std::span<T> dblock(u.data() + i * step, step);
1953 permute_data<T, true>(dblock, 1, cell_info, _eperm_inv);
1954 }
1955 }
1956 else
1957 {
1958 transform_data<T, true>(u, n, cell_info, _etransT,
1960 }
1961}
1962//-----------------------------------------------------------------------------
1963template <std::floating_point F>
1964template <typename T>
1965void FiniteElement<F>::Tt_inv_apply_right(std::span<T> u, int n,
1966 std::uint32_t cell_info) const
1967{
1968 if (_dof_transformations_are_identity)
1969 return;
1970 else if (_dof_transformations_are_permutations)
1971 {
1972 assert(u.size() % n == 0);
1973 const int step = u.size() / n;
1974 for (int i = 0; i < n; ++i)
1975 {
1976 std::span<T> dblock(u.data() + i * step, step);
1977 permute_data<T, true>(dblock, 1, cell_info, _eperm_inv);
1978 }
1979 }
1980 else
1981 {
1982 transform_data<T, true>(u, n, cell_info, _etrans_inv,
1984 }
1985}
1986//-----------------------------------------------------------------------------
1987
1988} // namespace basix
A finite element.
Definition finite-element.h:138
FiniteElement(element::family family, cell::type cell_type, polyset::type poly_type, int degree, const std::vector< std::size_t > &value_shape, mdspan_t< const F, 2 > wcoeffs, const std::array< std::vector< mdspan_t< const F, 2 > >, 4 > &x, const std::array< std::vector< mdspan_t< const F, 4 > >, 4 > &M, int interpolation_nderivs, maps::type map_type, sobolev::space sobolev_space, bool discontinuous, int embedded_subdegree, int embedded_superdegree, element::lagrange_variant lvariant, element::dpc_variant dvariant, std::vector< int > dof_ordering={})
Construct a finite element.
const std::array< std::vector< std::pair< std::vector< F >, std::array< std::size_t, 4 > > >, 4 > & M() const
Get the interpolation matrices for each subentity.
Definition finite-element.h:1326
void Tinv_apply_right(std::span< T > u, int n, std::uint32_t cell_info) const
Right(post)-apply the inverse of the operator applied by T_apply().
Definition finite-element.h:1917
std::pair< std::vector< F >, std::array< std::size_t, 3 > > base_transformations() const
Get the base transformations.
Definition finite-element.cpp:1899
void T_apply(std::span< T > u, int n, std::uint32_t cell_info) const
Transform basis functions from the reference element ordering and orientation to the globally consist...
Definition finite-element.h:1828
void Tt_apply(std::span< T > u, int n, std::uint32_t cell_info) const
Apply the transpose of the operator applied by T_apply().
Definition finite-element.h:1845
void permute_subentity_closure_inv(std::span< std::int32_t > d, std::uint32_t cell_info, cell::type entity_type, int entity_index) const
Perform the inverse of the operation applied by permute_subentity_closure().
Definition finite-element.h:893
bool dof_transformations_are_identity() const
Indicates is the dof transformations are all the identity.
Definition finite-element.h:558
bool operator==(const FiniteElement &e) const
Check if two elements are the same.
Definition finite-element.cpp:1721
std::map< cell::type, std::pair< std::vector< F >, std::array< std::size_t, 3 > > > entity_transformations() const
Return the entity dof transformation matrices.
Definition finite-element.h:769
const std::vector< int > & dof_ordering() const
Get dof layout.
Definition finite-element.h:1385
void permute_subentity_closure_inv(std::span< std::int32_t > d, std::uint32_t entity_info, cell::type entity_type) const
Perform the inverse of the operation applied by permute_subentity_closure().
Definition finite-element.h:989
int embedded_subdegree() const
Highest degree n such that a Lagrange (or vector Lagrange) element of degree n is a subspace of this ...
Definition finite-element.h:506
const std::vector< std::vector< std::vector< int > > > & entity_dofs() const
Get the dofs on each topological entity: (vertices, edges, faces, cell) in that order.
Definition finite-element.h:661
void T_apply_right(std::span< T > u, int n, std::uint32_t cell_info) const
Right(post)-apply the operator applied by T_apply().
Definition finite-element.h:1941
FiniteElement(FiniteElement &&element)=default
Move constructor.
bool has_tensor_product_factorisation() const
Indicates whether or not this element can be represented as a product of elements defined on lower-di...
Definition finite-element.h:1350
int interpolation_nderivs() const
The number of derivatives needed when interpolating.
Definition finite-element.h:1382
std::pair< std::vector< F >, std::array< std::size_t, 4 > > tabulate(int nd, impl::mdspan_t< const F, 2 > x) const
Compute basis values and derivatives at set of points.
Definition finite-element.cpp:1807
int embedded_superdegree() const
Lowest degree n such that the highest degree polynomial in this element is contained in a Lagrange (o...
Definition finite-element.h:501
int dim() const
Dimension of the finite element space.
Definition finite-element.h:519
void permute(std::span< std::int32_t > d, std::uint32_t cell_info) const
Permute indices associated with degree-of-freedoms on the reference element ordering to the globally ...
Definition finite-element.h:796
std::size_t hash() const
Get a unique hash of this element.
Definition finite-element.cpp:1760
F scalar_type
Scalar type.
Definition finite-element.h:144
void permute_inv(std::span< std::int32_t > d, std::uint32_t cell_info) const
Perform the inverse of the operation applied by permute().
Definition finite-element.h:827
void Tt_apply_right(std::span< T > u, int n, std::uint32_t cell_info) const
Right(post)-apply the transpose of the operator applied by T_apply().
Definition finite-element.h:1893
const std::vector< std::size_t > & value_shape() const
Element value tensor shape.
Definition finite-element.h:513
void Tt_inv_apply(std::span< T > u, int n, std::uint32_t cell_info) const
Apply the inverse transpose of the operator applied by T_apply().
Definition finite-element.h:1861
void permute_subentity_closure(std::span< std::int32_t > d, std::uint32_t cell_info, cell::type entity_type, int entity_index) const
Permute indices associated with degree-of-freedoms on the closure of a sub-entity of the reference el...
Definition finite-element.h:856
element::lagrange_variant lagrange_variant() const
Lagrange variant of the element.
Definition finite-element.h:527
void Tt_inv_apply_right(std::span< T > u, int n, std::uint32_t cell_info) const
Right(post)-apply the transpose inverse of the operator applied by T_apply().
Definition finite-element.h:1965
const std::array< std::vector< std::pair< std::vector< F >, std::array< std::size_t, 2 > > >, 4 > & x() const
Get the interpolation points for each subentity.
Definition finite-element.h:1283
int degree() const
Get the element polynomial degree.
Definition finite-element.h:495
void permute_subentity_closure(std::span< std::int32_t > d, std::uint32_t entity_info, cell::type entity_type) const
Permute indices associated with degree-of-freedoms on the closure of a sub-entity of the reference el...
Definition finite-element.h:934
void Tinv_apply(std::span< T > u, int n, std::uint32_t cell_info) const
Apply the inverse of the operator applied by T_apply().
Definition finite-element.h:1877
const std::pair< std::vector< F >, std::array< std::size_t, 2 > > & points() const
Return the interpolation points.
Definition finite-element.h:1163
sobolev::space sobolev_space() const
Underlying Sobolev space for this element.
Definition finite-element.h:542
const std::vector< std::vector< std::vector< int > > > & entity_closure_dofs() const
Get the dofs on the closure of each topological entity: (vertices, edges, faces, cell) in that order.
Definition finite-element.h:675
FiniteElement(const FiniteElement &element)=default
Copy constructor.
std::array< std::size_t, 4 > tabulate_shape(std::size_t nd, std::size_t num_points) const
Array shape for tabulate basis values and derivatives at set of points.
Definition finite-element.h:364
FiniteElement & operator=(FiniteElement &&element)=default
Move assignment operator.
const std::pair< std::vector< F >, std::array< std::size_t, 2 > > & interpolation_matrix() const
Return a matrix of weights interpolation.
Definition finite-element.h:1220
polyset::type polyset_type() const
Get the element polyset type.
Definition finite-element.h:491
const std::pair< std::vector< F >, std::array< std::size_t, 2 > > & wcoeffs() const
Get the coefficients that define the polynomial set in terms of the orthonormal polynomials.
Definition finite-element.h:1272
std::pair< std::vector< F >, std::array< std::size_t, 3 > > pull_back(impl::mdspan_t< const F, 3 > u, impl::mdspan_t< const F, 3 > J, std::span< const F > detJ, impl::mdspan_t< const F, 3 > K) const
Map function values from a physical cell to the reference.
Definition finite-element.cpp:2004
bool dof_transformations_are_permutations() const
Indicates if the degree-of-freedom transformations are all permutations.
Definition finite-element.h:552
std::pair< std::vector< F >, std::array< std::size_t, 3 > > push_forward(impl::mdspan_t< const F, 3 > U, impl::mdspan_t< const F, 3 > J, std::span< const F > detJ, impl::mdspan_t< const F, 3 > K) const
Map function values from the reference to a physical cell.
Definition finite-element.cpp:1968
cell::type cell_type() const
Get the element cell type.
Definition finite-element.h:487
bool interpolation_is_identity() const
Indicates whether or not the interpolation matrix for this element is an identity matrix.
Definition finite-element.h:1379
bool discontinuous() const
Indicates whether this element is the discontinuous variant.
Definition finite-element.h:548
std::vector< std::vector< FiniteElement< F > > > get_tensor_product_representation() const
Get the tensor product representation of this element.
Definition finite-element.h:1368
maps::type map_type() const
Map type for the element.
Definition finite-element.h:538
const std::pair< std::vector< F >, std::array< std::size_t, 2 > > & dual_matrix() const
Get the dual matrix.
Definition finite-element.h:1231
element::dpc_variant dpc_variant() const
DPC variant of the element.
Definition finite-element.h:534
const std::pair< std::vector< F >, std::array< std::size_t, 2 > > & coefficient_matrix() const
Get the matrix of coefficients.
Definition finite-element.h:1335
FiniteElement & operator=(const FiniteElement &element)=default
Assignment operator.
element::family family() const
The finite element family.
Definition finite-element.h:523
~FiniteElement()=default
Destructor.
std::function< void(O &, const P &, const Q &, F, const R &)> map_fn() const
Return a function that performs the appropriate push-forward/pull-back for the element type.
Definition finite-element.h:624
Information about reference cells.
Definition cell.h:17
type
Cell type.
Definition cell.h:21
int topological_dimension(cell::type celltype)
Definition cell.cpp:294
Interfaces for creating finite elements.
Definition e-brezzi-douglas-marini.h:13
impl::mdspan_t< T, d > mdspan_t
Typedef for mdspan.
Definition finite-element.h:103
std::tuple< std::array< std::vector< std::vector< T > >, 4 >, std::array< std::vector< std::array< std::size_t, 2 > >, 4 >, std::array< std::vector< std::vector< T > >, 4 >, std::array< std::vector< std::array< std::size_t, 4 > >, 4 > > make_discontinuous(const std::array< std::vector< mdspan_t< const T, 2 > >, 4 > &x, const std::array< std::vector< mdspan_t< const T, 4 > >, 4 > &M, std::size_t tdim, std::size_t value_size)
Definition finite-element.cpp:816
lagrange_variant
Variants of a Lagrange space that can be created.
Definition element-families.h:12
dpc_variant
Definition element-families.h:32
family
Available element families.
Definition element-families.h:45
void covariant_piola(O &&r, const P &U, const Q &, double, const R &K)
Covariant Piola map.
Definition maps.h:62
void contravariant_piola(O &&r, const P &U, const Q &J, double detJ, const R &)
Contravariant Piola map.
Definition maps.h:82
void double_contravariant_piola(O &&r, const P &U, const Q &J, double detJ, const R &)
Double contravariant Piola map.
Definition maps.h:132
void double_covariant_piola(O &&r, const P &U, const Q &, double, const R &K)
Double covariant Piola map.
Definition maps.h:104
type
Map type.
Definition maps.h:40
type
Cell type.
Definition polyset.h:137
void apply_permutation(std::span< const std::size_t > perm, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) permutation .
Definition precompute.h:137
void apply_permutation_mapped(std::span< const std::size_t > perm, std::span< E > data, std::span< const int > emap, std::size_t n=1)
Permutation of mapped data.
Definition precompute.h:147
void apply_tranpose_matrix_right(std::span< const std::size_t > v_size_t, md::mdspan< const T, md::dextents< std::size_t, 2 > > M, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) matrix to some transposed data.
Definition precompute.h:276
void apply_matrix(std::span< const std::size_t > v_size_t, md::mdspan< const T, md::dextents< std::size_t, 2 > > M, std::span< E > data, std::size_t offset=0, std::size_t n=1)
Apply a (precomputed) matrix.
Definition precompute.h:236
space
Sobolev space type.
Definition sobolev-spaces.h:13
Basix: FEniCS runtime basis evaluation library.
Definition cell.h:17
FiniteElement< T > create_element(element::family family, cell::type cell, int degree, element::lagrange_variant lvariant, element::dpc_variant dvariant, bool discontinuous, std::vector< int > dof_ordering={})
Definition finite-element.cpp:192
std::optional< std::vector< std::vector< FiniteElement< T > > > > tp_factors(element::family family, cell::type cell, int degree, element::lagrange_variant lvariant, element::dpc_variant dvariant, bool discontinuous, const std::vector< int > &dof_ordering)
Definition finite-element.cpp:353
std::string version()
Definition finite-element.cpp:2038
std::vector< int > lex_dof_ordering(element::family family, cell::type cell, int degree, element::lagrange_variant lvariant, element::dpc_variant dvariant, bool discontinuous)
Definition finite-element.cpp:509
std::optional< std::vector< int > > tp_dof_ordering(element::family family, cell::type cell, int degree, element::lagrange_variant lvariant, element::dpc_variant dvariant, bool discontinuous)
Definition finite-element.cpp:398
FiniteElement< T > create_custom_element(cell::type cell_type, const std::vector< std::size_t > &value_shape, impl::mdspan_t< const T, 2 > wcoeffs, const std::array< std::vector< impl::mdspan_t< const T, 2 > >, 4 > &x, const std::array< std::vector< impl::mdspan_t< const T, 4 > >, 4 > &M, int interpolation_nderivs, maps::type map_type, sobolev::space sobolev_space, bool discontinuous, int embedded_subdegree, int embedded_superdegree, polyset::type poly_type)
Definition finite-element.cpp:901
FiniteElement< T > create_tp_element(element::family family, cell::type cell, int degree, element::lagrange_variant lvariant, element::dpc_variant dvariant, bool discontinuous)
Definition finite-element.cpp:329