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
721namespace Impl {
722
723template<int dim, class IndexSet>
724void checkLagrangePreBasisOrder(const IndexSet& indexSet, unsigned int order)
725{
726 if constexpr (dim == 3)
727 {
728 if ((order > 2) and (indexSet.size(Dune::GeometryTypes::pyramid) > 0))
729 DUNE_THROW(RangeError, "Polynomial order >2 is not supported for grids containing pyramid elements.");
730 if ((order > 2) and (indexSet.size(Dune::GeometryTypes::prism) > 0))
731 DUNE_THROW(RangeError, "Polynomial order >2 is not supported for grids containing prism elements.");
732 }
733}
734
735} // namespace Impl
736
737
738
757template<typename GV, int k, typename R>
759 public LeafPreBasisMixin< LagrangePreBasis<GV,k,R> >
760{
761 static const int dim = GV::dimension;
762 static const bool useDynamicOrder = (k<0);
763
764 static Dune::MCMGLayout dofLayout(unsigned int order)
765 {
766 return [order](Dune::GeometryType type, int dim) -> std::size_t {
767 if (order==0)
768 return type.dim() == dim;
769 if (type.isSimplex())
770 return Dune::binomial(order-1, type.dim());
771 if (type.isCube())
772 return Dune::power(order-1, type.dim());
773 if (type.isPyramid())
774 return 0;
775 if (type.isPrism() and (order>1))
776 return (order-1)*(order-1)*(order-2)/2;
777 return 0;
778 };
779 }
780
782
783public:
784
786 using GridView = GV;
787
790
793
796 : LagrangePreBasis(gv, std::numeric_limits<unsigned int>::max())
797 {}
798
800 LagrangePreBasis(const GridView& gv, unsigned int runTimeOrder)
801 : gridView_(gv)
802 , order_(runTimeOrder)
803 , mapper_(gridView_, dofLayout(useDynamicOrder ? runTimeOrder : k))
804 , faceDOFPermutation_(gridView_.grid().globalIdSet(), useDynamicOrder ? runTimeOrder : k)
805 {
806 if (!useDynamicOrder && runTimeOrder!=std::numeric_limits<unsigned int>::max())
807 DUNE_THROW(RangeError, "Template argument k has to be -1 when supplying a run-time order!");
808 Impl::checkLagrangePreBasisOrder<dim>(gridView_.indexSet(), order());
809 if ((dim == 3) and (order() > FaceDOFPermutation::maxOrder3d))
810 DUNE_THROW(RangeError, "Polynomial order >" << FaceDOFPermutation::maxOrder3d << " is not supported in 3d");
811 }
812
815 {}
816
818 const GridView& gridView() const
819 {
820 return gridView_;
821 }
822
824 void update (const GridView& gv)
825 {
826 Impl::checkLagrangePreBasisOrder<dim>(gv.indexSet(), order());
827 gridView_ = gv;
828 mapper_.update(gridView_);
829 faceDOFPermutation_ = FaceDOFPermutation(gridView_.grid().globalIdSet(), order());
830 }
831
836 {
837 return Node{order()};
838 }
839
842 {
843 return mapper_.size();
844 }
845
848 {
849 // That cast to unsigned int is necessary because GV::dimension is an enum,
850 // which is not recognized by the power method as an integer type...
851 return power(order()+1, (unsigned int)GV::dimension);
852 }
853
854 template<class Node, class It>
855 It indices(const Node& node, It it) const
856 {
857 const auto& element = node.element();
858 const auto& localCoefficients = node.finiteElement().localCoefficients();
859
860 // Short-cut for order 1 since directly using the IndexSet is cheaper than the Mapper.
861 if (order() == 1)
862 {
863 for(auto localIndex : Dune::range(localCoefficients.size()))
864 {
865 auto localKey = localCoefficients.localKey(localIndex);
866 auto globalIndex = mapper_.gridView().indexSet().subIndex(element, localKey.subEntity(), localKey.codim());
867 *it = {{ (size_type)(globalIndex) }};
868 ++it;
869 }
870 return it;
871 }
872
873 // Precompute orientations of all faces
874 auto faceOrientations = faceDOFPermutation_.computeFaceOrientations(element);
875 for(auto localIndex : Dune::range(localCoefficients.size()))
876 {
877 auto localKey = localCoefficients.localKey(localIndex);
878 auto globalIndex = mapper_.subIndex(element, localKey.subEntity(), localKey.codim());
879 globalIndex += faceDOFPermutation_.permuteFaceDOF(localKey, faceOrientations);
880 *it = {{ (size_type)(globalIndex) }};
881 ++it;
882 }
883 return it;
884 }
885
887 unsigned int order() const
888 {
889 return (useDynamicOrder) ? order_ : k;
890 }
891
892protected:
894
895 // Run-time order, only valid if k<0
896 unsigned int order_;
897
900};
901
902
903
904template<typename GV, int k, typename R>
906 public LeafBasisNode
907{
908 static constexpr int dim = GV::dimension;
909
910 // A simple cache handing storing exactly one LFE. This can be
911 // used for grids with only a single element type. In contrast to
912 // StaticLagrangeLocalFiniteElementCache this also supports
913 // Lagrange*LocalFiniteElement with run-time order.
914 template <class LFE>
915 class SingleLocalFiniteElementCache
916 {
917 LFE lfe_;
918 public:
919 using FiniteElementType = LFE;
920
921 template<class... Args>
922 SingleLocalFiniteElementCache(Args&&... args)
923 : lfe_(std::forward<Args>(args)...)
924 {}
925
927 const FiniteElementType& get ([[maybe_unused]] Dune::GeometryType type) const
928 {
929 return lfe_;
930 }
931 };
932
933 // Utility function to construct the FiniteElementCache type.
934 // Since the function is just a helper to generate a type,
935 // it hands out a MetaType<T> instead of a raw T.
936 static constexpr auto makeCacheType()
937 {
938 using D = typename GV::ctype;
940 {
942 if constexpr (type.isSimplex())
943 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangeSimplexLocalFiniteElement<D,R,dim,k>>>{};
944 else if constexpr (type.isCube())
945 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangeCubeLocalFiniteElement<D,R,dim,k>>>{};
946 else if constexpr (type.isPrism())
947 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangePrismLocalFiniteElement<D,R,k>>>{};
948 else if constexpr (type.isPyramid())
949 return Dune::MetaType<SingleLocalFiniteElementCache<Dune::LagrangePyramidLocalFiniteElement<D,R,k>>>{};
950 }
951 else
953 }
954
955 using FiniteElementCache = typename decltype(makeCacheType())::type;
956
957public:
958
960 using Element = typename GV::template Codim<0>::Entity;
961 using FiniteElement = typename FiniteElementCache::FiniteElementType;
962
965 LagrangeNode(k)
966 {}
967
969 LagrangeNode(unsigned int order) :
970 cache_(order),
971 finiteElement_(nullptr),
972 element_(nullptr)
973 {}
974
976 const Element& element() const
977 {
978 return *element_;
979 }
980
986 {
987 return *finiteElement_;
988 }
989
991 void bind(const Element& e)
992 {
993 element_ = &e;
994 finiteElement_ = &(cache_.get(element_->type()));
995 this->setSize(finiteElement_->size());
996 }
997
998protected:
999
1000 FiniteElementCache cache_;
1003};
1004
1005
1006
1007namespace BasisFactory {
1008
1017template<std::size_t k, typename R=double>
1019{
1020 return [](const auto& gridView) {
1021 return LagrangePreBasis<std::decay_t<decltype(gridView)>, k, R>(gridView);
1022 };
1023}
1024
1032template<typename R=double>
1033auto lagrange(int order)
1034{
1035 return [=](const auto& gridView) {
1036 return LagrangePreBasis<std::decay_t<decltype(gridView)>, -1, R>(gridView, order);
1037 };
1038}
1039
1040} // end namespace BasisFactory
1041
1042
1043
1064template<typename GV, int k=-1, typename R=double>
1066
1067
1068
1069
1070
1071} // end namespace Functions
1072} // end namespace Dune
1073
1074
1075#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
auto lagrange()
Create a pre-basis factory that can create a Lagrange pre-basis.
Definition lagrangebasis.hh:1018
STL namespace.
int size() const
auto transformedRangeView(R &&range, F &&f)
static constexpr IntegralRange< T > range(T from, T 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:907
LagrangeNode(unsigned int order)
Constructor with a run-time order.
Definition lagrangebasis.hh:969
const FiniteElement & finiteElement() const
Return the LocalFiniteElement for the element we are bound to.
Definition lagrangebasis.hh:985
const Element * element_
Definition lagrangebasis.hh:1002
const Element & element() const
Return current element, throw if unbound.
Definition lagrangebasis.hh:976
FiniteElementCache cache_
Definition lagrangebasis.hh:1000
typename FiniteElementCache::FiniteElementType FiniteElement
Definition lagrangebasis.hh:961
void bind(const Element &e)
Bind to element.
Definition lagrangebasis.hh:991
typename GV::template Codim< 0 >::Entity Element
Definition lagrangebasis.hh:960
const FiniteElement * finiteElement_
Definition lagrangebasis.hh:1001
LagrangeNode()
Constructor without order (uses the compile-time value)
Definition lagrangebasis.hh:964
A pre-basis for a PQ-lagrange bases with given order.
Definition lagrangebasis.hh:760
unsigned int order_
Definition lagrangebasis.hh:896
LagrangePreBasis(const GridView &gv, unsigned int runTimeOrder)
Constructor for a given grid view object and run-time order.
Definition lagrangebasis.hh:800
void initializeIndices()
Initialize the global indices.
Definition lagrangebasis.hh:814
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition lagrangebasis.hh:841
LagrangePreBasis(const GridView &gv)
Constructor for a given grid view object with compile-time order.
Definition lagrangebasis.hh:795
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition lagrangebasis.hh:824
GV GridView
The grid view that the FE basis is defined on.
Definition lagrangebasis.hh:786
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition lagrangebasis.hh:818
GridView gridView_
Definition lagrangebasis.hh:893
Node makeNode() const
Create tree node.
Definition lagrangebasis.hh:835
unsigned int order() const
Polynomial order used in the local Lagrange finite-elements.
Definition lagrangebasis.hh:887
FaceDOFPermutation faceDOFPermutation_
Definition lagrangebasis.hh:899
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition lagrangebasis.hh:847
It indices(const Node &node, It it) const
Definition lagrangebasis.hh:855
Dune::MultipleCodimMultipleGeomTypeMapper< GridView > mapper_
Definition lagrangebasis.hh:898
A generic MixIn class for PreBasis.
Definition leafprebasismixin.hh:36
Definition nodes.hh:214
T swap(T... args)
T to_ulong(T... args)