DUNE PDELab (unstable)

lagrangebasis.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3
4// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
8#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
9
10#include <array>
11#include <type_traits>
12#include <vector>
13
15#include <dune/common/typelist.hh>
16#include <dune/common/indices.hh>
17#include <dune/common/math.hh>
19#include <dune/common/std/mdarray.hh>
20
21#include <dune/geometry/referenceelements.hh>
22#include <dune/geometry/type.hh>
23
24#include <dune/localfunctions/common/localkey.hh>
25#include <dune/localfunctions/lagrange/lagrangecube.hh>
26#include <dune/localfunctions/lagrange/lagrangeprism.hh>
27#include <dune/localfunctions/lagrange/lagrangepyramid.hh>
28#include <dune/localfunctions/lagrange/lagrangesimplex.hh>
29#include <dune/localfunctions/lagrange/lagrangelfecache.hh>
30
33
34#include <dune/functions/functionspacebases/nodes.hh>
35#include <dune/functions/functionspacebases/defaultglobalbasis.hh>
36#include <dune/functions/functionspacebases/leafprebasismixin.hh>
37
39
40namespace Dune {
41namespace Functions {
42
43
44
45namespace Experimental {
46
207template<std::size_t dim>
209{
210 static constexpr std::size_t maxEdges = 12;
211 static constexpr std::size_t maxFacets = 6;
212 static constexpr std::size_t bitsPerFacet = 4;
213
214 using Data = std::bitset<maxEdges + maxFacets*bitsPerFacet>;
215
216 static constexpr Data singleFacetMask = (1<<bitsPerFacet) - 1;
217
218 // Offset of the 2d facet within the bitfield
219 static constexpr auto facetBitOffset(int subEntity)
220 {
221 return maxEdges + bitsPerFacet*subEntity;
222 }
223
224 template<unsigned int blockSize, class T>
225 static constexpr T getBitBlock(const T& bits, unsigned int i)
226 {
227 constexpr T blockMask = (1 << (blockSize)) - 1;
228 return (bits >> (blockSize*i)) & blockMask;
229 }
230
240 constexpr void computeEdgeOrientation(const auto& vertexIndices, const auto& re, int subEntity)
241 {
242 data_[subEntity] = vertexIndices[0] > vertexIndices[1];
243 }
244
257 constexpr void computeTriangleOrientation(const auto& vertexIndices, const auto& re, int subEntity)
258 {
259 // All possible triangle orientations are stored in a binary encoded lookup table.
260 // We map the orientations of the three adjacent edges to a flat
261 // index in 0,...,7 and use it to access a 4 bit block in the
262 // table encoding the triangle orientation.
263 // The leading bit is always zero to indicate that the face is a triangle.
264 constexpr uint32_t edgeOrientationsToTriangleOrientation = 0b0101'0001'0011'0100'0010'0011'0110'0000;
265 auto edgeOrientations = (data_[re.subEntity(subEntity, 1, 0, 2)] << 0)
266 | (data_[re.subEntity(subEntity, 1, 1, 2)] << 1)
267 | (data_[re.subEntity(subEntity, 1, 2, 2)] << 2);
268 auto faceOrientation = getBitBlock<4>(edgeOrientationsToTriangleOrientation, edgeOrientations);
269 // Set bits associated to this facet.
270 data_ |= (Data(faceOrientation) << facetBitOffset(subEntity));
271 }
272
284 constexpr void computeQuadrilateralOrientation(const auto& vertexIndices, const auto& re, auto subEntity)
285 {
286 // The following computes the local index i_min of the quadrilateral
287 // vertex with smallest index. I.e. it is equivalent to
288 //
289 // std::size_t i_min = 0;
290 // for(auto i: Dune::range(1, 4))
291 // if (vertexIndices[i] < vertexIndices[i_min])
292 // i_min = i;
293 //
294 // This code would always do 3 index comparisons although several of them have
295 // already been done for the edges. Hence we rather want to reuse the latter
296 // to save comparisons (for large index/id types). The following code maps
297 // the 16 possible outcomes of the edge comparisons to the index i which
298 // is then used to lookup i_min from a precomputed index table. Since i_min
299 // is from 0,..,3 we can represent the value by two bits and encode the
300 // lookup table as 16*2 bits. There are two cases (5 and 10), where i_min
301 // cannot be deduced from edge comparisons because the two vertices with the
302 // smallest index are not neighbors. These cases require an additional comparison
303 // of the indices of those two vertices.
304 //
305 // In contrast to the linear search above this reduces the total number of comparisons
306 // for a hexahedron from 36=12+6*4 to a number between 18=12+6 and 24=12+6*2,
307 // depending on the number of required non-neighbor comparisons.
308 //
309 // For index/id types that are cheap to compare like e.g. int, the code does
310 // not make a measurable difference. For larger types it is slightly faster.
311 constexpr uint32_t edgeOrientationsToMinVertex = 0b11'11'01'01'11'00'00'00'10'00'00'01'10'00'10'00;
312 auto edgeOrientations = (data_[re.subEntity(subEntity, 1, 0, 2)] << 0)
313 | (data_[re.subEntity(subEntity, 1, 1, 2)] << 1)
314 | (data_[re.subEntity(subEntity, 1, 2, 2)] << 2)
315 | (data_[re.subEntity(subEntity, 1, 3, 2)] << 3);
316 std::size_t i_min = 0;
317 // In case 5 and 10 we need to do an extra comparison, because
318 // we cannot deduce i_min from edge orientations. In all other
319 // cases, we can lookup i_min by extracting two bits from the table.
320 if (edgeOrientations==5)
321 i_min = (vertexIndices[1] < vertexIndices[2]) ? 1 : 2;
322 else if (edgeOrientations==10)
323 i_min = (vertexIndices[0] < vertexIndices[3]) ? 0 : 3;
324 else
325 i_min = getBitBlock<2>(edgeOrientationsToMinVertex, edgeOrientations);
326 // The lowest two bits of the faceOrientation indicate the number of
327 // counter clockwise rotations needed to map vertex i_min to vertex 0.
328 // The third bit indicates if we need a reflection to revert the order.
329 // The leading bit is always one to indicate that the face is a quadrilateral.
330 unsigned long faceOrientation = 0;
331 if (i_min==0)
332 faceOrientation = 0b1000 | ((vertexIndices[2] < vertexIndices[1]) << 2);
333 else if (i_min==1)
334 faceOrientation = 0b1011 | ((vertexIndices[0] < vertexIndices[3]) << 2);
335 else if (i_min==2)
336 faceOrientation = 0b1001 | ((vertexIndices[3] < vertexIndices[0]) << 2);
337 else if (i_min==3)
338 faceOrientation = 0b1010 | ((vertexIndices[1] < vertexIndices[2]) << 2);
339 // Set bits associated to this facet.
340 data_ |= (Data(faceOrientation) << facetBitOffset(subEntity));
341 }
342
343public:
344
348 FaceOrientations() = default;
349
360 template <class VertexIds, std::size_t... codims>
361 FaceOrientations(const Dune::GeometryType& geometryType, const VertexIds& vertexIds, const Dune::index_constant<codims>&... codimensions)
362 : data_(0)
363 {
364 if constexpr ((dim == 1) or (sizeof...(codims)==0))
365 return;
366
367 // Get reference element
368 const auto& re = Dune::referenceElement<double,dim>(geometryType);
369
370 // Access and store vertex ids only once
371 using Index = std::decay_t<decltype(vertexIds[0])>;
372 auto cachedVertexIds = std::array<Index, Dune::power(2, dim)>{};
373 for(auto k : Dune::range(re.size(dim)))
374 cachedVertexIds[k] = vertexIds[k];
375
376 // Subrange of face vertex ids
377 auto faceVertexIds = [&](auto faceIndex, auto faceCodim) {
378 return Dune::transformedRangeView(re.subEntities(faceIndex, faceCodim, dim), [&](auto localVertexIndex) {
379 return cachedVertexIds[localVertexIndex];
380 });
381 };
382
383 if constexpr ((dim > 1) and ((codims<=(dim-1)) || ...))
384 {
385 for(auto subEntity : Dune::range(re.size(dim-1)))
386 computeEdgeOrientation(faceVertexIds(subEntity, dim-1), re, subEntity);
387 }
388 if constexpr ((dim == 3) and ((codims==(dim-2)) || ...))
389 {
390 for(auto subEntity : Dune::range(re.size(1)))
391 {
392 if (re.type(subEntity, 1).isTriangle())
393 computeTriangleOrientation(faceVertexIds(subEntity, 1), re, subEntity);
394 if (re.type(subEntity, 1).isQuadrilateral())
395 computeQuadrilateralOrientation(faceVertexIds(subEntity, 1), re, subEntity);
396 }
397 }
398 }
399
403 std::size_t faceOrientationIndex(std::size_t subEntity, std::size_t codim) const
404 {
405 if (codim == dim-1)
406 return data_[subEntity];
407 if (codim == 1)
408 return ((data_ >> facetBitOffset(subEntity)) & singleFacetMask).to_ulong();
409 return 0;
410 }
411
412private:
413
414 Data data_;
415};
416
417
418
430template<class IndexIdSet>
432{
433 static constexpr int dim = IndexIdSet::dimension;
434
435 // The following methods pre-compute the tables for renumbering the face DOFs.
436 // The rows of a table correspond to the local orientations which are indexed
437 // using the face orientation index as provided by the FaceOrientations class.
438 // Each row stores the local indices of the face DOF indices wrt the global orientation.
439 // I.e. given the table T, a local face DOF index i with respect to the
440 // local orientation j, the globally unique index of this DOF with respect to
441 // the global face orientation is T[j][i].
442 //
443 // The computation of the table is based on the following observation:
444 // Assume that F_j is the transformation mapping the global orientation
445 // of the face to its local orientation with index j. Now let p_i an
446 // interpolation point in the face with local index i. Then the
447 // globally oriented index of the basis function associated to p_i
448 // is obtained as the local index of the point F_j(p_i). Hence we can
449 // compute the renumbering table T[j][i] as follows:
450 // For given local orientation j and locally oriented DOF index i
451 // we first compute the point p_i, then we apply the transformation
452 // F_j (not its inverse as one might guess at first sight) which
453 // consists of rotations and zero or one reflection and use the index
454 // of the obtained point.
455
456 // Compute table of all possible permuted triangle DOF indices
457 static auto globallyOrientedTriangleDOFTable(int order)
458 {
459 auto dofPermutation = std::array<std::vector<std::size_t>, 8>();
460 // Number of DOFs on the base line
461 std::size_t m = order-2;
462 // Total number of DOFs
463 std::size_t n = m*(m+1)/2;
464 if (order<3)
465 return dofPermutation;
466 // In order to reflect we need to apply the transformation
467 // from global to local orientation as documented in the
468 // FaceOrientations class for each face orientation index.
469 // To do this we first map flat DOF indices to barycentric
470 // multi-indices wrt. the vertices and summing up to m-1.
471 // Then all transformations can be represented by flips
472 // of the components for the barycentric multi-index.
473 using BarycentricIndex = std::array<std::size_t, 3>;
474 auto barycentricIndices = std::vector<BarycentricIndex>();
475 for(auto i : Dune::range(m))
476 for(auto j : Dune::range(m-i))
477 barycentricIndices.push_back(BarycentricIndex{m-1-(i+j), j, i});
478 auto flatToBarycentric = [&](auto i) { return barycentricIndices[i]; };
479 auto barycentricToFlat = [&](auto b) { return b[1] + m*b[2] - b[2]*(b[2]-1)/2; };
480 // Loop of all 8 orientations
481 for(auto j : Dune::range(8))
482 {
483 dofPermutation[j].resize(n);
484 for(auto i : Dune::range(n))
485 {
486 auto b = flatToBarycentric(i);
487 // Bit 0 and 1: Number of counter-clockwise vertex-wise rotations
488 if ((j & 0b011) == 1)
489 {
490 // The counter-clockwise rotation by one vertex can be decomposed
491 // into two reflections.
492 std::swap(b[0], b[1]);
493 std::swap(b[0], b[2]);
494 }
495 if ((j & 0b011) == 2)
496 {
497 // The counter-clockwise rotation by two vertices is the inverse
498 // of the rotation by one vertex and can thus be decomposed into
499 // the same two reflections in opposite order.
500 std::swap(b[0], b[2]);
501 std::swap(b[0], b[1]);
502 }
503 // Bit 2: Reflect across xy-diagonal
504 if (j & 0b100)
505 std::swap(b[1], b[2]);
506 dofPermutation[j][i] = barycentricToFlat(b);
507 }
508 }
509 return dofPermutation;
510 }
511
512 // Compute table of all possible permuted quadrilateral DOF indices
513 static auto globallyOrientedQuadrilateralDOFTable(int order)
514 {
515 auto dofPermutation = std::array<std::vector<std::size_t>, 8>();
516 if (order<2)
517 return dofPermutation;
518 // Number of DOFs on the base line
519 std::size_t m = order-1;
520 // Total number of DOFs
521 std::size_t n = m*m;
522 // In order to reflect we map the flat DOF index into a cartesian
523 // multi-index wrt. the x- and y-axis.
524 using CartesianIndex = std::array<std::size_t, 2>;
525 auto flatToCartesian = [&](auto i) { return CartesianIndex{i % m, i / m}; };
526 auto cartesianToFlat = [&](auto c) { return c[0] + m*c[1]; };
527 for(auto j : Dune::range(8))
528 {
529 dofPermutation[j].resize(n);
530 for(auto i : Dune::range(n))
531 {
532 auto c = flatToCartesian(i);
533 // Bit 0 and 1: Number of counter-clockwise vertex-wise rotations
534 if ((j & 0b011) == 1)
535 {
536 std::swap(c[0], c[1]);
537 c[0] = m-1-c[0];
538 }
539 if ((j & 0b011) == 2)
540 {
541 c[0] = m-1-c[0];
542 c[1] = m-1-c[1];
543 }
544 if ((j & 0b011) == 3)
545 {
546 c[0] = m-1-c[0];
547 std::swap(c[0], c[1]);
548 }
549 // Bit 2: Reflect across xy-diagonal
550 if (j & 0b100)
551 std::swap(c[0], c[1]);
552 dofPermutation[j][i] = cartesianToFlat(c);
553 }
554 }
555 return dofPermutation;
556 }
557
558 std::size_t order() const
559 {
560 return order_;
561 }
562
563 /*
564 * Type used to store local per-face indices.
565 *
566 * Since the maximal number of face DOFs is n=(order-1)*(order-1),
567 * this type must be able to represent the range 0,...,n-1.
568 */
569 using FaceIndexType = unsigned char;
570
571public:
572
579 static constexpr unsigned int maxOrder3d = 17;
580
585 LagrangeFaceDOFPermutation(const IndexIdSet& indexSet, int order)
586 : indexIdSet_(&indexSet)
587 , order_(order)
588 , facetFlipTable_((dim < 3) ? 0 : std::max(0, (order-1)*(order-1)))
589 {
590 if constexpr (dim == 3)
591 {
592 // Fill table with all possible permuted 2d DOF indices.
593 // This is indexed with the faceOrientationIndex which first
594 // enumerates the orientations of triangles and then the ones
595 // of quadrilateral.
596 auto triangleFlipTable = globallyOrientedTriangleDOFTable(order);
597 auto quadrilateralFlipTable = globallyOrientedQuadrilateralDOFTable(order);
598 for(std::size_t k : Dune::range(8))
599 for(std::size_t i : Dune::range(triangleFlipTable[k].size()))
600 facetFlipTable_(k,i) = triangleFlipTable[k][i];
601 for(std::size_t k : Dune::range(8))
602 for(std::size_t i : Dune::range(quadrilateralFlipTable[k].size()))
603 facetFlipTable_(8+k,i) = quadrilateralFlipTable[k][i];
604 }
605 }
606
615 template <class Element>
616 FaceOrientations<dim> computeFaceOrientations(const Element& element) const
617 {
618 const auto& re = Dune::referenceElement<double,dim>(element.type());
619 auto vertexIds = Dune::transformedRangeView(re.subEntities(0,0,dim), [&](auto localVertexIndex) {
620 if constexpr (requires { indexIdSet_->subIndex(element, 0, dim); })
621 return indexIdSet_->subIndex(element, localVertexIndex, dim);
622 else if constexpr (requires { indexIdSet_->subId(element, 0, dim); })
623 return indexIdSet_->subId(element, localVertexIndex, dim);
624 });
625 using namespace Dune::Indices;
626 auto k = order();
627 if ((dim==1) or (k<3))
628 return FaceOrientations<dim>(element.type(), vertexIds);
629 else if ((k==3) and element.type().isTetrahedron())
630 return FaceOrientations<dim>(element.type(), vertexIds, _2);
631 else
632 return FaceOrientations<dim>(element.type(), vertexIds, _2, _1);
633 }
634
649 unsigned int permuteFaceDOF(unsigned int subEntity, unsigned int codim, unsigned int index, const FaceOrientations<dim>& orientations) const
650 {
651 auto k = order();
652 if constexpr(dim == 1)
653 return index;
654 if constexpr(dim == 2)
655 {
656 // Flip edge DOFs if reorientation is needed
657 if ((k>2) and (codim == 1) and orientations.faceOrientationIndex(subEntity, codim))
658 return k-2-index;
659 return index;
660 }
661 if constexpr(dim == 3)
662 {
663 if (k>2)
664 {
665 // Flip edge DOFs if reorientation is needed
666 if ((codim == 2) and orientations.faceOrientationIndex(subEntity, codim))
667 return k-2-index;
668 // Permute 2d facet DOFs according to lookup table
669 if (codim == 1)
670 return facetFlipTable_(orientations.faceOrientationIndex(subEntity, codim), index);
671 }
672 return index;
673 }
674 }
675
688 unsigned int permuteFaceDOF(const Dune::LocalKey& localKey, const FaceOrientations<dim>& orientations) const
689 {
690 return permuteFaceDOF(localKey.subEntity(), localKey.codim(), localKey.index(), orientations);
691 }
692
693private:
694 const IndexIdSet* indexIdSet_;
695 std::size_t order_;
697};
698
699} // namespace Experimental
700
701
702
703// *****************************************************************************
704// This is the reusable part of the LagrangeBasis. It contains
705//
706// LagrangePreBasis
707// LagrangeNode
708//
709// The pre-basis allows to create the others and is the owner of possible shared
710// state. These components do _not_ depend on the global basis and local view
711// and can be used without a global basis.
712// *****************************************************************************
713
714template<typename GV, int k, typename R=double>
715class LagrangeNode;
716
717template<typename GV, int k, typename R=double>
718class LagrangePreBasis;
719
720
721
740template<typename GV, int k, typename R>
742 public LeafPreBasisMixin< LagrangePreBasis<GV,k,R> >
743{
744 static const int dim = GV::dimension;
745 static const bool useDynamicOrder = (k<0);
746
747 static Dune::MCMGLayout dofLayout(unsigned int order)
748 {
749 return [order](Dune::GeometryType type, int dim) -> std::size_t {
750 if (order==0)
751 return type.dim() == dim;
752 if (type.isSimplex())
753 return Dune::binomial(order-1, type.dim());
754 if (type.isCube())
755 return Dune::power(order-1, type.dim());
756 if (type.isPyramid())
757 return 0;
758 if (type.isPrism() and (order>1))
759 return (order-1)*(order-1)*(order-2)/2;
760 return 0;
761 };
762 }
763
765
766public:
767
769 using GridView = GV;
770
772 using size_type = std::size_t;
773
775 using Node = LagrangeNode<GV, k, R>;
776
779 : LagrangePreBasis(gv, std::numeric_limits<unsigned int>::max())
780 {}
781
783 LagrangePreBasis(const GridView& gv, unsigned int runTimeOrder)
784 : gridView_(gv)
785 , order_(runTimeOrder)
786 , mapper_(gridView_, dofLayout(useDynamicOrder ? runTimeOrder : k))
787 , faceDOFPermutation_(gridView_.grid().globalIdSet(), useDynamicOrder ? runTimeOrder : k)
788 {
789 if (!useDynamicOrder && runTimeOrder!=std::numeric_limits<unsigned int>::max())
790 DUNE_THROW(RangeError, "Template argument k has to be -1 when supplying a run-time order!");
791 if ((order() > 2) and (gridView_.indexSet().size(Dune::GeometryTypes::pyramid) > 0))
792 DUNE_THROW(RangeError, "Polynomial order >2 is not supported for grids containing pyramid elements.");
793 if ((order() > 2) and (gridView_.indexSet().size(Dune::GeometryTypes::prism) > 0))
794 DUNE_THROW(RangeError, "Polynomial order >2 is not supported for grids containing prism elements.");
795 if ((dim == 3) and (order() > FaceDOFPermutation::maxOrder3d))
796 DUNE_THROW(RangeError, "Polynomial order >" << FaceDOFPermutation::maxOrder3d << " is not supported in 3d");
797 }
798
801 {}
802
804 const GridView& gridView() const
805 {
806 return gridView_;
807 }
808
810 void update (const GridView& gv)
811 {
812 if ((order() > 2) and (gv.indexSet().size(Dune::GeometryTypes::pyramid) > 0))
813 DUNE_THROW(RangeError, "Polynomial order >2 is not supported for grids containing pyramid elements.");
814 if ((order() > 2) and (gv.indexSet().size(Dune::GeometryTypes::prism) > 0))
815 DUNE_THROW(RangeError, "Polynomial order >2 is not supported for grids containing prism elements.");
816 gridView_ = gv;
817 mapper_.update(gridView_);
818 faceDOFPermutation_ = FaceDOFPermutation(gridView_.grid().globalIdSet(), order());
819 }
820
825 {
826 return Node{order()};
827 }
828
831 {
832 return mapper_.size();
833 }
834
837 {
838 // That cast to unsigned int is necessary because GV::dimension is an enum,
839 // which is not recognized by the power method as an integer type...
840 return power(order()+1, (unsigned int)GV::dimension);
841 }
842
843 template<class Node, class It>
844 It indices(const Node& node, It it) const
845 {
846 const auto& element = node.element();
847 const auto& localCoefficients = node.finiteElement().localCoefficients();
848
849 // Short-cut for order 1 since directly using the IndexSet is cheaper than the Mapper.
850 if (order() == 1)
851 {
852 for(auto localIndex : Dune::range(localCoefficients.size()))
853 {
854 auto localKey = localCoefficients.localKey(localIndex);
855 auto globalIndex = mapper_.gridView().indexSet().subIndex(element, localKey.subEntity(), localKey.codim());
856 *it = {{ (size_type)(globalIndex) }};
857 ++it;
858 }
859 return it;
860 }
861
862 // Precompute orientations of all faces
863 auto faceOrientations = faceDOFPermutation_.computeFaceOrientations(element);
864 for(auto localIndex : Dune::range(localCoefficients.size()))
865 {
866 auto localKey = localCoefficients.localKey(localIndex);
867 auto globalIndex = mapper_.subIndex(element, localKey.subEntity(), localKey.codim());
868 globalIndex += faceDOFPermutation_.permuteFaceDOF(localKey, faceOrientations);
869 *it = {{ (size_type)(globalIndex) }};
870 ++it;
871 }
872 return it;
873 }
874
876 unsigned int order() const
877 {
878 return (useDynamicOrder) ? order_ : k;
879 }
880
881protected:
882 GridView gridView_;
883
884 // Run-time order, only valid if k<0
885 unsigned int order_;
886
888 FaceDOFPermutation faceDOFPermutation_;
889};
890
891
892
893template<typename GV, int k, typename R>
894class LagrangeNode :
895 public LeafBasisNode
896{
897 static constexpr int dim = GV::dimension;
898
899 // A simple cache handing storing exactly one LFE. This can be
900 // used for grids with only a single element type. In contrast to
901 // StaticLagrangeLocalFiniteElementCache this also supports
902 // Lagrange*LocalFiniteElement with run-time order.
903 template <class LFE>
904 class SingleLocalFiniteElementCache
905 {
906 LFE lfe_;
907 public:
908 using FiniteElementType = LFE;
909
910 template<class... Args>
911 SingleLocalFiniteElementCache(Args&&... args)
912 : lfe_(std::forward<Args>(args)...)
913 {}
914
916 const FiniteElementType& get ([[maybe_unused]] Dune::GeometryType type) const
917 {
918 return lfe_;
919 }
920 };
921
922 // Utility function to construct the FiniteElementCache type.
923 // Since the function is just a helper to generate a type,
924 // it hands out a MetaType<T> instead of a raw T.
925 static constexpr auto makeCacheType()
926 {
927 using D = typename GV::ctype;
929 {
931 if constexpr (type.isSimplex())
932 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangeSimplexLocalFiniteElement<D,R,dim,k>>>{};
933 else if constexpr (type.isCube())
934 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangeCubeLocalFiniteElement<D,R,dim,k>>>{};
935 else if constexpr (type.isPrism())
936 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangePrismLocalFiniteElement<D,R,k>>>{};
937 else if constexpr (type.isPyramid())
938 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangePyramidLocalFiniteElement<D,R,k>>>{};
939 }
940 else
942 }
943
944 using FiniteElementCache = typename decltype(makeCacheType())::type;
945
946public:
947
948 using size_type = std::size_t;
949 using Element = typename GV::template Codim<0>::Entity;
950 using FiniteElement = typename FiniteElementCache::FiniteElementType;
951
953 LagrangeNode() :
954 LagrangeNode(k)
955 {}
956
958 LagrangeNode(unsigned int order) :
959 cache_(order),
960 finiteElement_(nullptr),
961 element_(nullptr)
962 {}
963
965 const Element& element() const
966 {
967 return *element_;
968 }
969
974 const FiniteElement& finiteElement() const
975 {
976 return *finiteElement_;
977 }
978
980 void bind(const Element& e)
981 {
982 element_ = &e;
983 finiteElement_ = &(cache_.get(element_->type()));
984 this->setSize(finiteElement_->size());
985 }
986
987protected:
988
989 FiniteElementCache cache_;
990 const FiniteElement* finiteElement_;
991 const Element* element_;
992};
993
994
995
996namespace BasisFactory {
997
1006template<std::size_t k, typename R=double>
1008{
1009 return [](const auto& gridView) {
1010 return LagrangePreBasis<std::decay_t<decltype(gridView)>, k, R>(gridView);
1011 };
1012}
1013
1021template<typename R=double>
1022auto lagrange(int order)
1023{
1024 return [=](const auto& gridView) {
1025 return LagrangePreBasis<std::decay_t<decltype(gridView)>, -1, R>(gridView, order);
1026 };
1027}
1028
1029} // end namespace BasisFactory
1030
1031
1032
1053template<typename GV, int k=-1, typename R=double>
1055
1056
1057
1058
1059
1060} // end namespace Functions
1061} // end namespace Dune
1062
1063
1064#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
Global basis for given pre-basis.
Definition: defaultglobalbasis.hh:53
A class encoding the orientation of the subentities of an entity.
Definition: lagrangebasis.hh:209
FaceOrientations()=default
Default construct FaceOrientations with index 0.
std::size_t faceOrientationIndex(std::size_t subEntity, std::size_t codim) const
Return index of the orientation for the given face.
Definition: lagrangebasis.hh:403
FaceOrientations(const Dune::GeometryType &geometryType, const VertexIds &vertexIds, const Dune::index_constant< codims > &... codimensions)
Construct FaceOrientations for given vertex ids.
Definition: lagrangebasis.hh:361
A class for permuting Lagrange DOFs of arbitrary order for dimensions 1,2,3.
Definition: lagrangebasis.hh:432
static constexpr unsigned int maxOrder3d
Maximal supported polynomial order.
Definition: lagrangebasis.hh:579
LagrangeFaceDOFPermutation(const IndexIdSet &indexSet, int order)
Definition: lagrangebasis.hh:585
unsigned int permuteFaceDOF(unsigned int subEntity, unsigned int codim, unsigned int index, const FaceOrientations< dim > &orientations) const
Compute permuted index of a face DOF.
Definition: lagrangebasis.hh:649
FaceOrientations< dim > computeFaceOrientations(const Element &element) const
Compute FaceOrientations for grid elements.
Definition: lagrangebasis.hh:616
unsigned int permuteFaceDOF(const Dune::LocalKey &localKey, const FaceOrientations< dim > &orientations) const
Compute permuted index of a face DOF.
Definition: lagrangebasis.hh:688
A pre-basis for a PQ-lagrange bases with given order.
Definition: lagrangebasis.hh:743
LagrangePreBasis(const GridView &gv, unsigned int runTimeOrder)
Constructor for a given grid view object and run-time order.
Definition: lagrangebasis.hh:783
LagrangeNode< GV, k, R > Node
Template mapping root tree path to type of created tree node.
Definition: lagrangebasis.hh:775
std::size_t size_type
Type used for indices and size information.
Definition: lagrangebasis.hh:772
void initializeIndices()
Initialize the global indices.
Definition: lagrangebasis.hh:800
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: lagrangebasis.hh:830
LagrangePreBasis(const GridView &gv)
Constructor for a given grid view object with compile-time order.
Definition: lagrangebasis.hh:778
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: lagrangebasis.hh:810
GV GridView
The grid view that the FE basis is defined on.
Definition: lagrangebasis.hh:769
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: lagrangebasis.hh:804
Node makeNode() const
Create tree node.
Definition: lagrangebasis.hh:824
unsigned int order() const
Polynomial order used in the local Lagrange finite-elements.
Definition: lagrangebasis.hh:876
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: lagrangebasis.hh:836
A generic MixIn class for PreBasis.
Definition: leafprebasismixin.hh:36
Unique label for each type of entities that can occur in DUNE grids.
Definition: type.hh:114
constexpr bool isPyramid() const
Return true if entity is a pyramid.
Definition: type.hh:304
constexpr bool isPrism() const
Return true if entity is a prism.
Definition: type.hh:309
constexpr unsigned int dim() const
Return dimension of the type.
Definition: type.hh:360
constexpr bool isCube() const
Return true if entity is a cube of any dimension.
Definition: type.hh:324
constexpr bool isSimplex() const
Return true if entity is a simplex of any dimension.
Definition: type.hh:319
Grid view abstract base class.
Definition: gridview.hh:66
Lagrange finite element for cubes with arbitrary compile-time dimension and polynomial order.
Definition: lagrangecube.hh:805
Lagrange finite element for 3d prisms with arbitrary compile-time polynomial order.
Definition: lagrangeprism.hh:728
Lagrange finite element for 3d pyramids with compile-time polynomial order.
Definition: lagrangepyramid.hh:903
Lagrange finite element for simplices with arbitrary compile-time dimension and static or dynamic pol...
Definition: lagrangesimplex.hh:990
Describe position of one degree of freedom.
Definition: localkey.hh:24
constexpr unsigned int index() const noexcept
Return offset within subentity.
Definition: localkey.hh:70
constexpr unsigned int codim() const noexcept
Return codim of associated entity.
Definition: localkey.hh:63
constexpr unsigned int subEntity() const noexcept
Return number of associated subentity.
Definition: localkey.hh:56
Default exception class for range errors.
Definition: exceptions.hh:348
An owning multi-dimensional array analog of mdspan.
Definition: mdarray.hh:69
A set of traits classes to store static information about grid implementation.
A few common exception classes.
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
auto lagrange()
Create a pre-basis factory that can create a Lagrange pre-basis.
Definition: lagrangebasis.hh:1007
const IndexSet & indexSet() const
obtain the index set
Definition: gridview.hh:177
constexpr GeometryType prism
GeometryType representing a 3D prism.
Definition: type.hh:528
constexpr GeometryType pyramid
GeometryType representing a 3D pyramid.
Definition: type.hh:522
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
std::function< size_t(GeometryType, int)> MCMGLayout
layout function for MultipleCodimMultipleGeomTypeMapper
Definition: mcmgmapper.hh:64
auto transformedRangeView(R &&range, F &&f)
Create a TransformedRangeView.
Definition: rangeutilities.hh:669
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition: rangeutilities.hh:293
Some useful basic math stuff.
Mapper for multiple codim and multiple geometry types.
Namespace with predefined compile time indices for the range [0,19].
Definition: indices.hh:50
Dune namespace
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
static constexpr T binomial(const T &n, const T &k) noexcept
calculate the binomial coefficient n over k as a constexpr
Definition: math.hh:113
constexpr Base power(Base m, Exponent p)
Power method for integer exponents.
Definition: math.hh:75
constexpr auto get(std::integer_sequence< T, II... >, std::integral_constant< std::size_t, pos >={})
Return the entry at position pos of the given sequence.
Definition: integersequence.hh:22
STL namespace.
Utilities for reduction like operations on ranges.
Specialize with 'true' for if the codimension 0 entity of the grid has only one possible geometry typ...
Definition: capabilities.hh:27
Static tag representing a codimension.
Definition: dimension.hh:24
A type that refers to another type.
Definition: typelist.hh:33
A unique label for each type of element that can occur in a grid.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jun 10, 22:32, 2026)