Basix 0.12.0.dev0
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
320 const std::vector<std::size_t>& value_shape,
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,
329 std::vector<int> dof_ordering = {});
330
332 FiniteElement(const FiniteElement& element) = default;
333
335 FiniteElement(FiniteElement&& element) = default;
336
338 ~FiniteElement() = default;
339
341 FiniteElement& operator=(const FiniteElement& element) = default;
342
344 FiniteElement& operator=(FiniteElement&& element) = default;
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 std::size_t{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
592 std::pair<std::vector<F>, std::array<std::size_t, 3>>
593 pull_back(impl::mdspan_t<const F, 3> u, impl::mdspan_t<const F, 3> J,
594 std::span<const F> detJ, impl::mdspan_t<const F, 3> K) const;
595
627 template <typename O, typename P, typename Q, typename R>
628 std::function<void(O&, const P&, const Q&, F, const R&)> map_fn() const
629 {
630 switch (_map_type)
631 {
632 case maps::type::identity:
633 return [](O& u, const P& U, const Q&, F, const R&)
634 {
635 assert(U.extent(0) == u.extent(0));
636 assert(U.extent(1) == u.extent(1));
637 for (std::size_t i = 0; i < U.extent(0); ++i)
638 for (std::size_t j = 0; j < U.extent(1); ++j)
639 u(i, j) = U(i, j);
640 };
641 case maps::type::covariantPiola:
642 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
643 { maps::covariant_piola(u, U, J, detJ, K); };
644 case maps::type::contravariantPiola:
645 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
647 case maps::type::doubleCovariantPiola:
648 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
650 case maps::type::doubleContravariantPiola:
651 return [](O& u, const P& U, const Q& J, F detJ, const R& K)
653 default:
654 throw std::runtime_error("Map not implemented");
655 }
656 }
657
665 const std::vector<std::vector<std::vector<int>>>& entity_dofs() const
666 {
667 return _edofs;
668 }
669
679 const std::vector<std::vector<std::vector<int>>>& entity_closure_dofs() const
680 {
681 return _e_closure_dofs;
682 }
683
765 std::pair<std::vector<F>, std::array<std::size_t, 3>>
766 base_transformations() const;
767
772 const std::map<cell::type, std::pair<std::vector<F>, std::array<std::size_t, 3>>>&
774 {
775 return _entity_transformations;
776 }
777
800 void permute(std::span<std::int32_t> d, std::uint32_t cell_info) const
801 {
802 if (!_dof_transformations_are_permutations)
803 {
804 throw std::runtime_error(
805 "The DOF transformations for this element are not permutations");
806 }
807
808 if (_dof_transformations_are_identity)
809 return;
810 else
812 }
813
831 void permute_inv(std::span<std::int32_t> d, std::uint32_t cell_info) const
832 {
833 if (!_dof_transformations_are_permutations)
834 {
835 throw std::runtime_error(
836 "The DOF transformations for this element are not permutations");
837 }
838
839 if (_dof_transformations_are_identity)
840 return;
841 else
843 }
844
860 void permute_subentity_closure(std::span<std::int32_t> d,
861 std::uint32_t cell_info,
863 {
865
866 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
867
868 std::uint32_t entity_info = 0;
869 switch (entity_dim)
870 {
871 case 0:
872 return;
873 case 1:
875 break;
876 case 2:
877 entity_info = cell_info >> (3 * entity_index) & 7;
878 break;
879 default:
880 throw std::runtime_error("Unsupported cell dimension");
881 }
883 }
884
897 void permute_subentity_closure_inv(std::span<std::int32_t> d,
898 std::uint32_t cell_info,
900 int entity_index) const
901 {
903
904 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
905
906 std::uint32_t entity_info;
907 switch (entity_dim)
908 {
909 case 0:
910 return;
911 case 1:
913 break;
914 case 2:
915 entity_info = cell_info >> (3 * entity_index) & 7;
916 break;
917 default:
918 throw std::runtime_error("Unsupported cell dimension");
919 }
921 }
922
937
938 void permute_subentity_closure(std::span<std::int32_t> d,
939 std::uint32_t entity_info,
941 {
942 if (!_dof_transformations_are_permutations)
943 {
944 throw std::runtime_error(
945 "The DOF transformations for this element are not permutations");
946 }
947
949
950 if (entity_dim == 0)
951 return;
952
953 auto& perm = _subentity_closure_perm.at(entity_type);
954 if (entity_dim == 1)
955 {
956 if (entity_info & 1)
957 {
959 }
960 }
961 else if (entity_dim == 2)
962 {
963 // Rotate a face
964 for (std::uint32_t r = 0; r < (entity_info >> 1 & 3); ++r)
965 {
967 }
968
969 // Reflect a face (post rotate)
970 if (entity_info & 1)
971 {
973 }
974 }
975 else
976 {
977 throw std::runtime_error(
978 "Invalid dimension for permute_subentity_closure");
979 }
980 }
981
993 void permute_subentity_closure_inv(std::span<std::int32_t> d,
994 std::uint32_t entity_info,
996 {
997 if (!_dof_transformations_are_permutations)
998 {
999 throw std::runtime_error(
1000 "The DOF transformations for this element are not permutations");
1001 }
1002
1004
1005 if (entity_dim == 0)
1006 return;
1007
1008 auto& perm = _subentity_closure_perm_inv.at(entity_type);
1009 if (entity_dim == 1)
1010 {
1011 if (entity_info & 1)
1012 {
1014 }
1015 }
1016 else if (entity_dim == 2)
1017 {
1018 // Reflect a face (pre rotate)
1019 if (entity_info & 1)
1020 {
1022 }
1023
1024 // Rotate a face
1025 for (std::uint32_t r = 0; r < (entity_info >> 1 & 3); ++r)
1026 {
1028 }
1029 }
1030 else
1031 {
1032 throw std::runtime_error(
1033 "Invalid dimension for permute_subentity_closure");
1034 }
1035 }
1036
1067 template <typename T>
1068 void T_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1069
1080 template <typename T>
1081 void Tt_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1082
1094 template <typename T>
1095 void Tt_inv_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1096
1107 template <typename T>
1108 void Tinv_apply(std::span<T> u, int n, std::uint32_t cell_info) const;
1109
1120 template <typename T>
1121 void Tt_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1122
1132 template <typename T>
1133 void T_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1134
1145 template <typename T>
1146 void Tinv_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1147
1158 template <typename T>
1159 void Tt_inv_apply_right(std::span<T> u, int n, std::uint32_t cell_info) const;
1160
1167 const std::pair<std::vector<F>, std::array<std::size_t, 2>>& points() const
1168 {
1169 return _points;
1170 }
1171
1223 const std::pair<std::vector<F>, std::array<std::size_t, 2>>&
1225 {
1226 return _matM;
1227 }
1228
1234 const std::pair<std::vector<F>, std::array<std::size_t, 2>>&
1236 {
1237 return _dual_matrix;
1238 }
1239
1276 const std::pair<std::vector<F>, std::array<std::size_t, 2>>& wcoeffs() const
1277 {
1278 return _wcoeffs;
1279 }
1280
1285 const std::array<
1286 std::vector<std::pair<std::vector<F>, std::array<std::size_t, 2>>>, 4>&
1287 x() const
1288 {
1289 return _x;
1290 }
1291
1328 const std::array<
1329 std::vector<std::pair<std::vector<F>, std::array<std::size_t, 4>>>, 4>&
1330 M() const
1331 {
1332 return _M;
1333 }
1334
1342 const std::pair<std::vector<F>, std::array<std::size_t, 2>>&
1344 {
1345 return _coeffs;
1346 }
1347
1359 {
1360 return !_tensor_factors.empty();
1361 }
1362
1375 std::vector<std::vector<FiniteElement<F>>>
1377 {
1379 throw std::runtime_error("Element has no tensor product representation.");
1380 return _tensor_factors;
1381 }
1382
1387 bool interpolation_is_identity() const { return _interpolation_is_identity; }
1388
1390 int interpolation_nderivs() const { return _interpolation_nderivs; }
1391
1397 const std::vector<int>& dof_ordering() const { return _dof_ordering; }
1398
1399private:
1406 template <typename T, bool post>
1407 void permute_data(
1408 std::span<T> data, int block_size, std::uint32_t cell_info,
1409 const std::map<cell::type, std::vector<std::vector<std::size_t>>>& eperm)
1410 const;
1411
1412 using array2_t = std::pair<std::vector<F>, std::array<std::size_t, 2>>;
1413 using array3_t = std::pair<std::vector<F>, std::array<std::size_t, 3>>;
1414 using trans_data_t
1415 = std::vector<std::pair<std::vector<std::size_t>, array2_t>>;
1416
1423 template <typename T, bool post, typename OP>
1424 void
1425 transform_data(std::span<T> data, int block_size, std::uint32_t cell_info,
1426 const std::map<cell::type, trans_data_t>& etrans, OP op) const;
1427
1428 // Cell type
1429 cell::type _cell_type;
1430
1431 // Polyset type
1432 polyset::type _poly_type;
1433
1434 // Topological dimension of the cell
1435 std::size_t _cell_tdim;
1436
1437 // Topological dimension of the cell
1438 std::vector<std::vector<cell::type>> _cell_subentity_types;
1439
1440 // Finite element family
1441 element::family _family;
1442
1443 // Lagrange variant
1444 element::lagrange_variant _lagrange_variant;
1445
1446 // DPC variant
1447 element::dpc_variant _dpc_variant;
1448
1449 // Degree that was input when creating the element
1450 int _degree;
1451
1452 // Degree
1453 int _interpolation_nderivs;
1454
1455 // Highest degree polynomial in element's polyset
1456 int _embedded_superdegree;
1457
1458 // Highest degree space that is a subspace of element's polyset
1459 int _embedded_subdegree;
1460
1461 // Value shape
1462 std::vector<std::size_t> _value_shape;
1463
1465 maps::type _map_type;
1466
1468 sobolev::space _sobolev_space;
1469
1470 // Shape function coefficient of expansion sets on cell. If shape
1471 // function is given by @f$\psi_i = \sum_{k} \phi_{k}
1472 // \alpha^{i}_{k}@f$, then _coeffs(i, j) = @f$\alpha^i_k@f$. ie
1473 // _coeffs.row(i) are the expansion coefficients for shape function i
1474 // (@f$\psi_{i}@f$).
1475 std::pair<std::vector<F>, std::array<std::size_t, 2>> _coeffs;
1476
1477 // Dofs associated with each cell (sub-)entity
1478 std::vector<std::vector<std::vector<int>>> _edofs;
1479
1480 // Dofs associated with the closdure of each cell (sub-)entity
1481 std::vector<std::vector<std::vector<int>>> _e_closure_dofs;
1482
1483 // Entity transformations
1484 std::map<cell::type, array3_t> _entity_transformations;
1485
1486 // Set of points used for point evaluation
1487 // Experimental - currently used for an implementation of
1488 // "tabulate_dof_coordinates" Most useful for Lagrange. This may change or go
1489 // away. For non-Lagrange elements, these points will be used in combination
1490 // with _interpolation_matrix to perform interpolation
1491 std::pair<std::vector<F>, std::array<std::size_t, 2>> _points;
1492
1493 // Interpolation points on the cell. The shape is (entity_dim, num
1494 // entities of given dimension, num_points, tdim)
1495 std::array<std::vector<std::pair<std::vector<F>, std::array<std::size_t, 2>>>,
1496 4>
1497 _x;
1498
1500 std::pair<std::vector<F>, std::array<std::size_t, 2>> _matM;
1501
1502 // Indicates whether or not the DOF transformations are all
1503 // permutations
1504 bool _dof_transformations_are_permutations;
1505
1506 // Indicates whether or not the DOF transformations are all identity
1507 bool _dof_transformations_are_identity;
1508
1509 // The entity permutations (factorised). This will only be set if
1510 // _dof_transformations_are_permutations is True and
1511 // _dof_transformations_are_identity is False
1512 std::map<cell::type, std::vector<std::vector<std::size_t>>> _eperm;
1513
1514 // The reverse entity permutations (factorised). This will only be set
1515 // if _dof_transformations_are_permutations is True and
1516 // _dof_transformations_are_identity is False
1517 std::map<cell::type, std::vector<std::vector<std::size_t>>> _eperm_inv;
1518
1519 // The entity transformations in precomputed form
1520 std::map<cell::type, trans_data_t> _etrans;
1521
1522 // The transposed entity transformations in precomputed form
1523 std::map<cell::type, trans_data_t> _etransT;
1524
1525 // The inverse entity transformations in precomputed form
1526 std::map<cell::type, trans_data_t> _etrans_inv;
1527
1528 // The inverse transpose entity transformations in precomputed form
1529 std::map<cell::type, trans_data_t> _etrans_invT;
1530
1531 // The subentity closure permutations (factorised). This will only be set if
1532 // _dof_transformations_are_permutations is True
1533 std::map<cell::type, std::vector<std::vector<std::size_t>>>
1534 _subentity_closure_perm;
1535
1536 // The inverse subentity closure permutations (factorised). This will only be
1537 // set if _dof_transformations_are_permutations is True
1538 std::map<cell::type, std::vector<std::vector<std::size_t>>>
1539 _subentity_closure_perm_inv;
1540
1541 // Indicates whether or not this is the discontinuous version of the
1542 // element
1543 bool _discontinuous;
1544
1545 // The dual matrix
1546 std::pair<std::vector<F>, std::array<std::size_t, 2>> _dual_matrix;
1547
1548 // Dof reordering for different element dof layout compatibility.
1549 // The reference basix layout is ordered by entity, i.e. dofs on
1550 // vertices, followed by edges, faces, then internal dofs.
1551 // _dof_ordering stores the map to the new order required, e.g.
1552 // for a P2 triangle, _dof_ordering=[0 3 5 1 2 4] will place
1553 // dofs 0, 3, 5 on the vertices and 1, 2, 4, on the edges.
1554 std::vector<int> _dof_ordering;
1555
1556 // Tensor product representation
1557 // Entries of tuple are (list of elements on an interval, permutation
1558 // of DOF numbers)
1559 // @todo: For vector-valued elements, a tensor product type and a
1560 // scaling factor may additionally be needed.
1561 std::vector<std::vector<FiniteElement>> _tensor_factors;
1562
1563 // Is the interpolation matrix an identity?
1564 bool _interpolation_is_identity;
1565
1566 // The coefficients that define the polynomial set in terms of the
1567 // orthonormal polynomials
1568 std::pair<std::vector<F>, std::array<std::size_t, 2>> _wcoeffs;
1569
1570 // Interpolation matrices for each entity
1571 using array4_t
1572 = std::vector<std::pair<std::vector<F>, std::array<std::size_t, 4>>>;
1573 std::array<array4_t, 4> _M;
1574};
1575
1602template <std::floating_point T>
1603FiniteElement<T> create_custom_element(
1604 cell::type cell_type, const std::vector<std::size_t>& value_shape,
1605 impl::mdspan_t<const T, 2> wcoeffs,
1606 const std::array<std::vector<impl::mdspan_t<const T, 2>>, 4>& x,
1607 const std::array<std::vector<impl::mdspan_t<const T, 4>>, 4>& M,
1608 int interpolation_nderivs, maps::type map_type,
1609 sobolev::space sobolev_space, bool discontinuous, int embedded_subdegree,
1610 int embedded_superdegree, polyset::type poly_type);
1611
1623template <std::floating_point T>
1624FiniteElement<T> create_element(element::family family, cell::type cell,
1625 int degree, element::lagrange_variant lvariant,
1626 element::dpc_variant dvariant,
1627 bool discontinuous,
1628 std::vector<int> dof_ordering = {});
1629
1642std::optional<std::vector<int>>
1643tp_dof_ordering(element::family family, cell::type cell, int degree,
1645 element::dpc_variant dvariant, bool discontinuous);
1646
1657std::vector<int> lex_dof_ordering(element::family family, cell::type cell,
1658 int degree, element::lagrange_variant lvariant,
1659 element::dpc_variant dvariant,
1660 bool discontinuous);
1661
1675template <std::floating_point T>
1676std::optional<std::vector<std::vector<FiniteElement<T>>>>
1677tp_factors(element::family family, cell::type cell, int degree,
1679 bool discontinuous, const std::vector<int>& dof_ordering);
1680
1692template <std::floating_point T>
1693FiniteElement<T>
1694create_tp_element(element::family family, cell::type cell, int degree,
1696 element::dpc_variant dvariant, bool discontinuous);
1697
1700std::string version();
1701
1702//-----------------------------------------------------------------------------
1703template <std::floating_point F>
1704template <typename T, bool post>
1705void FiniteElement<F>::permute_data(
1706 std::span<T> data, int block_size, std::uint32_t cell_info,
1707 const std::map<cell::type, std::vector<std::vector<std::size_t>>>& eperm)
1708 const
1709{
1710 if (_cell_tdim >= 2)
1711 {
1712 // This assumes 3 bits are used per face. This will need updating if 3D
1713 // cells with faces with more than 4 sides are implemented
1714 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
1715
1716 // Permute DOFs on edges
1717 {
1718 auto& trans = eperm.at(cell::type::interval)[0];
1719 for (std::size_t e = 0; e < _edofs[1].size(); ++e)
1720 {
1721 // Reverse an edge
1722 if (cell_info >> (face_start + e) & 1)
1723 {
1724 precompute::apply_permutation_mapped(trans, data, _edofs[1][e],
1725 block_size);
1726 }
1727 }
1728 }
1729
1730 if (_cell_tdim == 3)
1731 {
1732 // Permute DOFs on faces
1733 for (std::size_t f = 0; f < _edofs[2].size(); ++f)
1734 {
1735 auto& trans = eperm.at(_cell_subentity_types[2][f]);
1736
1737 // Reflect a face (pre rotate)
1738 if (!post and cell_info >> (3 * f) & 1)
1739 {
1740 precompute::apply_permutation_mapped(trans[1], data, _edofs[2][f],
1741 block_size);
1742 }
1743
1744 // Rotate a face
1745 for (std::uint32_t r = 0; r < (cell_info >> (3 * f + 1) & 3); ++r)
1746 {
1747 precompute::apply_permutation_mapped(trans[0], data, _edofs[2][f],
1748 block_size);
1749 }
1750
1751 // Reflect a face (post rotate)
1752 if (post and cell_info >> (3 * f) & 1)
1753 {
1754 precompute::apply_permutation_mapped(trans[1], data, _edofs[2][f],
1755 block_size);
1756 }
1757 }
1758 }
1759 }
1760}
1761//-----------------------------------------------------------------------------
1762template <std::floating_point F>
1763template <typename T, bool post, typename OP>
1764void FiniteElement<F>::transform_data(
1765 std::span<T> data, int block_size, std::uint32_t cell_info,
1766 const std::map<cell::type, trans_data_t>& etrans, OP op) const
1767{
1768 if (_cell_tdim >= 2)
1769 {
1770 // This assumes 3 bits are used per face. This will need updating if
1771 // 3D cells with faces with more than 4 sides are implemented
1772 int face_start = _cell_tdim == 3 ? 3 * _edofs[2].size() : 0;
1773 int dofstart = 0;
1774 for (auto& edofs0 : _edofs[0])
1775 dofstart += edofs0.size();
1776
1777 // Transform DOFs on edges
1778 {
1779 auto& [v_size_t, matrix] = etrans.at(cell::type::interval)[0];
1780 for (std::size_t e = 0; e < _edofs[1].size(); ++e)
1781 {
1782 // Reverse an edge
1783 if (cell_info >> (face_start + e) & 1)
1784 {
1785 op(std::span(v_size_t),
1786 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1787 dofstart, block_size);
1788 }
1789 dofstart += _edofs[1][e].size();
1790 }
1791 }
1792
1793 if (_cell_tdim == 3)
1794 {
1795 // Permute DOFs on faces
1796 for (std::size_t f = 0; f < _edofs[2].size(); ++f)
1797 {
1798 auto& trans = etrans.at(_cell_subentity_types[2][f]);
1799
1800 // Reflect a face (pre rotation)
1801 if (!post and cell_info >> (3 * f) & 1)
1802 {
1803 const auto& m = trans[1];
1804 const auto& v_size_t = std::get<0>(m);
1805 const auto& matrix = std::get<1>(m);
1806 op(std::span(v_size_t),
1807 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1808 dofstart, block_size);
1809 }
1810
1811 // Rotate a face
1812 for (std::uint32_t r = 0; r < (cell_info >> (3 * f + 1) & 3); ++r)
1813 {
1814 const auto& m = trans[0];
1815 const auto& v_size_t = std::get<0>(m);
1816 const auto& matrix = std::get<1>(m);
1817 op(std::span(v_size_t),
1818 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1819 dofstart, block_size);
1820 }
1821
1822 // Reflect a face (post rotation)
1823 if (post and cell_info >> (3 * f) & 1)
1824 {
1825 const auto& m = trans[1];
1826 const auto& v_size_t = std::get<0>(m);
1827 const auto& matrix = std::get<1>(m);
1828 op(std::span(v_size_t),
1829 mdspan_t<const F, 2>(matrix.first.data(), matrix.second), data,
1830 dofstart, block_size);
1831 }
1832
1833 dofstart += _edofs[2][f].size();
1834 }
1835 }
1836 }
1837}
1838//-----------------------------------------------------------------------------
1839template <std::floating_point F>
1840template <typename T>
1841void FiniteElement<F>::T_apply(std::span<T> u, int n,
1842 std::uint32_t cell_info) const
1843{
1844 if (_dof_transformations_are_identity)
1845 return;
1846
1847 if (_dof_transformations_are_permutations)
1849 else
1850 {
1852 precompute::apply_matrix<F, T>);
1853 }
1854}
1855//-----------------------------------------------------------------------------
1856template <std::floating_point F>
1857template <typename T>
1858void FiniteElement<F>::Tt_apply(std::span<T> u, int n,
1859 std::uint32_t cell_info) const
1860{
1861 if (_dof_transformations_are_identity)
1862 return;
1863 else if (_dof_transformations_are_permutations)
1864 permute_data<T, true>(u, n, cell_info, _eperm_inv);
1865 else
1866 {
1868 precompute::apply_matrix<F, T>);
1869 }
1870}
1871//-----------------------------------------------------------------------------
1872template <std::floating_point F>
1873template <typename T>
1874void FiniteElement<F>::Tt_inv_apply(std::span<T> u, int n,
1875 std::uint32_t cell_info) const
1876{
1877 if (_dof_transformations_are_identity)
1878 return;
1879 else if (_dof_transformations_are_permutations)
1881 else
1882 {
1883 transform_data<T, false>(u, n, cell_info, _etrans_invT,
1884 precompute::apply_matrix<F, T>);
1885 }
1886}
1887//-----------------------------------------------------------------------------
1888template <std::floating_point F>
1889template <typename T>
1890void FiniteElement<F>::Tinv_apply(std::span<T> u, int n,
1891 std::uint32_t cell_info) const
1892{
1893 if (_dof_transformations_are_identity)
1894 return;
1895 else if (_dof_transformations_are_permutations)
1896 permute_data<T, true>(u, n, cell_info, _eperm_inv);
1897 else
1898 {
1899 transform_data<T, true>(u, n, cell_info, _etrans_inv,
1900 precompute::apply_matrix<F, T>);
1901 }
1902}
1903//-----------------------------------------------------------------------------
1904template <std::floating_point F>
1905template <typename T>
1906void FiniteElement<F>::Tt_apply_right(std::span<T> u, int n,
1907 std::uint32_t cell_info) const
1908{
1909 if (_dof_transformations_are_identity)
1910 return;
1911 else if (_dof_transformations_are_permutations)
1912 {
1913 assert(u.size() % n == 0);
1914 const int step = u.size() / n;
1915 for (int i = 0; i < n; ++i)
1916 {
1917 std::span<T> dblock(u.data() + i * step, step);
1919 }
1920 }
1921 else
1922 {
1924 precompute::apply_tranpose_matrix_right<F, T>);
1925 }
1926}
1927//-----------------------------------------------------------------------------
1928template <std::floating_point F>
1929template <typename T>
1931 std::uint32_t cell_info) const
1932{
1933 if (_dof_transformations_are_identity)
1934 return;
1935 else if (_dof_transformations_are_permutations)
1936 {
1937 assert(u.size() % n == 0);
1938 const int step = u.size() / n;
1939 for (int i = 0; i < n; ++i)
1940 {
1941 std::span<T> dblock(u.data() + i * step, step);
1943 }
1944 }
1945 else
1946 {
1947 transform_data<T, false>(u, n, cell_info, _etrans_invT,
1948 precompute::apply_tranpose_matrix_right<F, T>);
1949 }
1950}
1951//-----------------------------------------------------------------------------
1952template <std::floating_point F>
1953template <typename T>
1954void FiniteElement<F>::T_apply_right(std::span<T> u, int n,
1955 std::uint32_t cell_info) const
1956{
1957 if (_dof_transformations_are_identity)
1958 return;
1959 else if (_dof_transformations_are_permutations)
1960 {
1961 assert(u.size() % n == 0);
1962 const int step = u.size() / n;
1963 for (int i = 0; i < n; ++i)
1964 {
1965 std::span<T> dblock(u.data() + i * step, step);
1966 permute_data<T, true>(dblock, 1, cell_info, _eperm_inv);
1967 }
1968 }
1969 else
1970 {
1972 precompute::apply_tranpose_matrix_right<F, T>);
1973 }
1974}
1975//-----------------------------------------------------------------------------
1976template <std::floating_point F>
1977template <typename T>
1979 std::uint32_t cell_info) const
1980{
1981 if (_dof_transformations_are_identity)
1982 return;
1983 else if (_dof_transformations_are_permutations)
1984 {
1985 assert(u.size() % n == 0);
1986 const int step = u.size() / n;
1987 for (int i = 0; i < n; ++i)
1988 {
1989 std::span<T> dblock(u.data() + i * step, step);
1990 permute_data<T, true>(dblock, 1, cell_info, _eperm_inv);
1991 }
1992 }
1993 else
1994 {
1995 transform_data<T, true>(u, n, cell_info, _etrans_inv,
1996 precompute::apply_tranpose_matrix_right<F, T>);
1997 }
1998}
1999//-----------------------------------------------------------------------------
2000
2001} // 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:1330
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:1930
std::pair< std::vector< F >, std::array< std::size_t, 3 > > base_transformations() const
Get the base transformations.
Definition finite-element.cpp:1904
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:1841
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:1858
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:897
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:1728
const std::vector< int > & dof_ordering() const
Get the mapping from the reference-element DOF ordering to the custom DOF ordering supplied at constr...
Definition finite-element.h:1397
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:993
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:665
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:1954
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:1358
int interpolation_nderivs() const
The number of derivatives needed when interpolating.
Definition finite-element.h:1390
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:1814
int embedded_superdegree() const
Lowest degree n such that this element's polynomial set is a subspace of a Lagrange (or vector Lagran...
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:800
std::size_t hash() const
Get a unique hash of this element.
Definition finite-element.cpp:1767
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:831
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:1906
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:1874
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:860
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:1978
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:1287
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:938
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:1890
const std::pair< std::vector< F >, std::array< std::size_t, 2 > > & points() const
Return the interpolation points.
Definition finite-element.h:1167
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:679
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::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:773
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:1224
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:1276
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:2009
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:1973
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:1387
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:1376
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:1235
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:1343
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:628
type
Cell type.
Definition cell.h:21
int topological_dimension(cell::type celltype)
Definition cell.cpp:294
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
impl::mdspan_t< T, d > mdspan_t
Typedef for mdspan.
Definition finite-element.h:103
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:74
void contravariant_piola(O &&r, const P &U, const Q &J, double detJ, const R &)
Contravariant Piola map.
Definition maps.h:101
void double_contravariant_piola(O &&r, const P &U, const Q &J, double detJ, const R &)
Double contravariant Piola map.
Definition maps.h:164
void double_covariant_piola(O &&r, const P &U, const Q &, double, const R &K)
Double covariant Piola map.
Definition maps.h:129
type
Map type.
Definition maps.h:40
type
Polyset (polynomial set) 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:153
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:2044
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