Dune-Functions 2.12-git
Loading...
Searching...
No Matches
lagrangebasis.hh
Go to the documentation of this file.
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
17#include <dune/common/math.hh>
20
22#include <dune/geometry/type.hh>
23
30
31#include <dune/grid/common/capabilities.hh>
33
37
38#include <dune/grid/common/capabilities.hh>
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
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
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
773
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:
883
884 // Run-time order, only valid if k<0
885 unsigned int order_;
886
889};
890
891
892
893template<typename GV, int k, typename R>
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
949 using Element = typename GV::template Codim<0>::Entity;
950 using FiniteElement = typename FiniteElementCache::FiniteElementType;
951
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
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_;
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
auto lagrange()
Create a pre-basis factory that can create a Lagrange pre-basis.
Definition lagrangebasis.hh:1007
STL namespace.
int size() const
auto transformedRangeView(R &&range, F &&f)
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
static TupleAccessTraits< typenameAtType< N, Tuple >::Type >::NonConstType get(Tuple &t)
size_type dim() const
std::ptrdiff_t index() const
#define DUNE_THROW(E,...)
static constexpr T binomial(const T &n, const T &k) noexcept
constexpr Base power(Base m, Exponent p)
const IndexSet & indexSet() const
constexpr bool isPyramid() const
constexpr bool isPrism() const
constexpr unsigned int dim() const
constexpr bool isCube() const
constexpr bool isSimplex() const
constexpr unsigned int index() const noexcept
constexpr unsigned int codim() const noexcept
constexpr unsigned int subEntity() const noexcept
auto size(GeometryType type) const
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
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
Definition lagrangebasis.hh:896
LagrangeNode(unsigned int order)
Constructor with a run-time order.
Definition lagrangebasis.hh:958
const FiniteElement & finiteElement() const
Return the LocalFiniteElement for the element we are bound to.
Definition lagrangebasis.hh:974
const Element * element_
Definition lagrangebasis.hh:991
const Element & element() const
Return current element, throw if unbound.
Definition lagrangebasis.hh:965
FiniteElementCache cache_
Definition lagrangebasis.hh:989
typename FiniteElementCache::FiniteElementType FiniteElement
Definition lagrangebasis.hh:950
void bind(const Element &e)
Bind to element.
Definition lagrangebasis.hh:980
typename GV::template Codim< 0 >::Entity Element
Definition lagrangebasis.hh:949
const FiniteElement * finiteElement_
Definition lagrangebasis.hh:990
LagrangeNode()
Constructor without order (uses the compile-time value)
Definition lagrangebasis.hh:953
A pre-basis for a PQ-lagrange bases with given order.
Definition lagrangebasis.hh:743
unsigned int order_
Definition lagrangebasis.hh:885
LagrangePreBasis(const GridView &gv, unsigned int runTimeOrder)
Constructor for a given grid view object and run-time order.
Definition lagrangebasis.hh:783
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
GridView gridView_
Definition lagrangebasis.hh:882
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
FaceDOFPermutation faceDOFPermutation_
Definition lagrangebasis.hh:888
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition lagrangebasis.hh:836
It indices(const Node &node, It it) const
Definition lagrangebasis.hh:844
Dune::MultipleCodimMultipleGeomTypeMapper< GridView > mapper_
Definition lagrangebasis.hh:887
A generic MixIn class for PreBasis.
Definition leafprebasismixin.hh:36
Definition nodes.hh:214
T swap(T... args)
T to_ulong(T... args)