5#ifndef DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGESIMPLEX_HH
6#define DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGESIMPLEX_HH
18#include <dune/common/hybridutilities.hh>
21#include <dune/common/std/mdarray.hh>
22#include <dune/common/std/mdspan.hh>
24#include <dune/geometry/referenceelements.hh>
26#include <dune/localfunctions/common/localbasis.hh>
27#include <dune/localfunctions/common/localfiniteelementtraits.hh>
28#include <dune/localfunctions/common/localkey.hh>
30namespace Dune {
namespace Impl
33 template<
unsigned int dim,
int compileTimeOrder>
34 struct LagrangeSimplexTraits
36 static constexpr bool is_static_order = (compileTimeOrder >= 0);
38 constexpr LagrangeSimplexTraits(
int = compileTimeOrder)
40 static_assert(compileTimeOrder >= 0,
"LagrangeSimplex: order must be non-negative");
44 static constexpr unsigned int order() {
return compileTimeOrder; }
50 static constexpr unsigned int size() {
return binomial(compileTimeOrder+dim,dim); }
55 template<
unsigned int dim>
56 struct LagrangeSimplexTraits<dim,-1>
58 const unsigned int k_;
59 const unsigned int size_;
61 static constexpr bool is_static_order =
false;
63 constexpr explicit LagrangeSimplexTraits(
int runTimeOrder)
64 : k_(runTimeOrder >= 0 ? (unsigned int)(runTimeOrder) : 0u)
72 constexpr unsigned int order()
const
78 constexpr unsigned int size()
const
93 template<
class R,
unsigned int dim,
int k>
94 struct LagrangeSimplexLocalBasisBuffers
96 LagrangeSimplexLocalBasisBuffers(
int ) {}
99 static auto makeValueBuffer(
int )
101 using E = Std::extents<int,dim+1,k+1>;
102 using C = std::array<R,(dim+1)*(k+1)>;
103 return Std::mdarray<R,E,Std::layout_right,C>{};
107 static auto makeJacobianBuffer(
int )
109 using E = Std::extents<int,dim+1,2,k+1>;
110 using C = std::array<R,(dim+1)*2*(k+1)>;
111 return Std::mdarray<R,E,Std::layout_right,C>{};
115 template <
class T, T derivativeOrder>
116 static auto makePartialBuffer(std::integral_constant<T,derivativeOrder>,
int )
118 using E = Std::extents<int,dim+1,derivativeOrder+1,k+1>;
119 using C = std::array<R,(dim+1)*(derivativeOrder+1)*(k+1)>;
120 return Std::mdarray<R,E,Std::layout_right,C>{};
132 template<
class R,
unsigned int dim>
133 struct LagrangeSimplexLocalBasisBuffers<R,dim,-1>
135 LagrangeSimplexLocalBasisBuffers(
int order)
136 : buffer_((dim+1)*
std::
max<int>(2,order+1)*(order+1))
139 mutable std::vector<R> buffer_{};
142 auto makeValueBuffer(
int order)
const
144 using E = Std::extents<int,dim+1,std::dynamic_extent>;
145 return Std::mdspan<R,E>{buffer_.data(), E(order+1)};
149 auto makeJacobianBuffer(
int order)
const
151 using E = Std::extents<int,dim+1,2,std::dynamic_extent>;
152 return Std::mdspan<R,E>{buffer_.data(), E(order+1)};
156 auto makePartialBuffer(
int derivativeOrder,
int order)
const
158 using E = Std::extents<int,dim+1,std::dynamic_extent,std::dynamic_extent>;
159 return Std::mdspan<R,E>{buffer_.data(), E(derivativeOrder+1, order+1)};
174 template<
class D,
class R,
unsigned int dim,
int compileTimeOrder>
175 class LagrangeSimplexLocalBasis
176 :
public LagrangeSimplexTraits<dim,compileTimeOrder>
177 ,
private LagrangeSimplexLocalBasisBuffers<R,dim,compileTimeOrder>
179 template <
class>
friend class LagrangeSimplexLocalInterpolation;
183 using Base = LagrangeSimplexTraits<dim,compileTimeOrder>;
184 using Buffers = LagrangeSimplexLocalBasisBuffers<R,dim,compileTimeOrder>;
185 static constexpr bool is_static_order = Base::is_static_order;
187 constexpr LagrangeSimplexLocalBasis(
int runTimeOrder = compileTimeOrder)
189 , Buffers(runTimeOrder)
200 template <
class I, std::size_t e0, std::size_t... ee,
class A>
201 static auto slice(Std::mdspan<R,Std::extents<I,e0,ee...>,Std::layout_right,A> L,
int i)
204 return Std::mdspan<R,Std::extents<I,ee...>,Std::layout_right>{
205 L.data_handle() + i * L.stride(0), L.extent(ii+1)...};
206 }, std::make_index_sequence<
sizeof...(ee)>{});
210 template <
class I, std::size_t e0, std::size_t... ee,
class C>
211 static auto slice(Std::mdarray<R,Std::extents<I,e0,ee...>,Std::layout_right,C>& L,
int i)
213 return slice(L.to_mdspan(), i);
223 constexpr auto barycentric(
const auto& x)
const
225 auto b = std::array<R,dim+1>{};
229 b[i] = order() * x[i];
239 static constexpr void evaluateLagrangePolynomials(
const R& t,
auto&& L,
int k)
243 L[i+1] = L[i] * (t - i) / (i+1);
248 static constexpr void evaluateLagrangePolynomialDerivative(
const R& t,
auto&& LL,
unsigned int maxDerivativeOrder,
int k)
250 auto L = slice(LL,0);
253 L[i+1] = L[i] * (t - i) / (i+1);
256 auto F = slice(LL,j);
257 auto DF = slice(LL,j+1);
260 DF[i+1] = (DF[i] * (t - i) + (j+1)*F[i]) / (i+1);
264 using BarycentricMultiIndex = std::array<int,dim+1>;
280 static constexpr R barycentricDerivative(
281 BarycentricMultiIndex beta,
284 const BarycentricMultiIndex& i,
285 const BarycentricMultiIndex& alpha = {})
298 auto leftDerivatives = alpha;
299 auto rightDerivatives = alpha;
300 leftDerivatives[j]++;
301 rightDerivatives.back()++;
303 return (barycentricDerivative(beta, L, k, i, leftDerivatives) -
304 barycentricDerivative(beta, L, k, i, rightDerivatives)) * k;
314 y *= L(j,alpha[j],i[j]);
320 using Traits = LocalBasisTraits<D,dim,FieldVector<D,dim>,R,1,FieldVector<R,1>,FieldMatrix<R,1,dim> >;
324 std::vector<typename Traits::RangeType>& out)
const
326 const int k = order();
340 for (
size_t i=0; i<dim; i++)
349 auto z = barycentric(x);
351 auto L = Buffers::makeValueBuffer(k);
353 evaluateLagrangePolynomials(z[j], slice(L,j), k);
359 for (
auto i1 : std::array{k - i0})
360 out[n++] = L(0,i0) * L(1,i1);
368 for (
auto i2 : std::array{k - i1 - i0})
369 out[n++] = L(0,i0) * L(1,i1) * L(2,i2);
378 for (
auto i3 : std::array{k - i2 - i1 - i0})
379 out[n++] = L(0,i0) * L(1,i1) * L(2,i2) * L(3,i3);
383 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalBasis for k>=2 only implemented for dim<=3");
392 std::vector<typename Traits::JacobianType>& out)
const
394 const int k = order();
400 std::fill(out[0][0].begin(), out[0][0].end(), 0);
407 std::fill(out[0][0].begin(), out[0][0].end(), -1);
409 for (
unsigned int i=0; i<dim; i++)
410 for (
unsigned int j=0; j<dim; j++)
411 out[i+1][0][j] = (i==j);
417 auto z = barycentric(x);
420 auto L = Buffers::makeJacobianBuffer(k);
422 evaluateLagrangePolynomialDerivative(z[j], slice(L,j), 1, k);
429 for (
auto i1 : std::array{k-i0})
431 out[n][0][0] = (L(0,1,i0) * L(1,0,i1) - L(0,0,i0) * L(1,1,i1))*k;
444 for (
auto i2 : std::array{k - i1 - i0})
446 out[n][0][0] = (L(0,1,i0) * L(1,0,i1) * L(2,0,i2) - L(0,0,i0) * L(1,0,i1) * L(2,1,i2))*k;
447 out[n][0][1] = (L(0,0,i0) * L(1,1,i1) * L(2,0,i2) - L(0,0,i0) * L(1,0,i1) * L(2,1,i2))*k;
463 for (
auto i3 : std::array{k - i2 - i1 - i0})
465 out[n][0][0] = (L(0,1,i0) * L(1,0,i1) * L(2,0,i2) * L(3,0,i3) - L(0,0,i0) * L(1,0,i1) * L(2,0,i2) * L(3,1,i3))*k;
466 out[n][0][1] = (L(0,0,i0) * L(1,1,i1) * L(2,0,i2) * L(3,0,i3) - L(0,0,i0) * L(1,0,i1) * L(2,0,i2) * L(3,1,i3))*k;
467 out[n][0][2] = (L(0,0,i0) * L(1,0,i1) * L(2,1,i2) * L(3,0,i3) - L(0,0,i0) * L(1,0,i1) * L(2,0,i2) * L(3,1,i3))*k;
477 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalBasis for k>=2 only implemented for dim<=3");
486 void partial(
const std::array<unsigned int,dim>& derivativeOrder,
488 std::vector<typename Traits::RangeType>& out)
const
490 const int k = order();
491 int totalOrder =
std::accumulate(derivativeOrder.begin(), derivativeOrder.end(), 0u);
498 evaluateFunction(in, out);
505 for(
auto& out_i : out)
516 auto direction = std::find(derivativeOrder.begin(), derivativeOrder.end(), 1);
518 for (
unsigned int i=0; i<dim; i++)
519 out[i+1] = (i==(direction-derivativeOrder.begin()));
527 auto supportedOrders = [&]{
528 if constexpr(is_static_order)
536 auto z = barycentric(in);
539 auto L = Buffers::makePartialBuffer(staticTotalOrder,k);
541 evaluateLagrangePolynomialDerivative(z[j], slice(L,j), derivativeOrder[j], k);
542 evaluateLagrangePolynomialDerivative(z[dim], slice(L,dim), totalOrder, k);
544 auto barycentricOrder = BarycentricMultiIndex{};
546 barycentricOrder[j] = derivativeOrder[j];
547 barycentricOrder[dim] = 0;
549 if constexpr (dim==1)
553 for (
auto i1 : std::array{k - i0})
554 out[n++] = barycentricDerivative(barycentricOrder, L, k, BarycentricMultiIndex{i0, i1});
556 if constexpr (dim==2)
561 for (
auto i2 : std::array{k - i1 - i0})
562 out[n++] = barycentricDerivative(barycentricOrder, L, k, BarycentricMultiIndex{i0, i1, i2});
564 if constexpr (dim==3)
570 for (
auto i3 : std::array{k - i2 - i1 - i0})
571 out[n++] = barycentricDerivative(barycentricOrder, L, k, BarycentricMultiIndex{i0, i1, i2, i3});
582 template<
unsigned int dim,
int compileTimeOrder>
583 class LagrangeSimplexLocalCoefficients
584 :
public LagrangeSimplexTraits<dim,compileTimeOrder>
586 using Base = LagrangeSimplexTraits<dim,compileTimeOrder>;
590 LagrangeSimplexLocalCoefficients (
int runTimeOrder = compileTimeOrder)
592 , localKeys_(Base::
size())
594 const int k = Base::order();
597 localKeys_[0] = LocalKey(0,0,0);
603 for (std::size_t i=0; i<Base::size(); i++)
604 localKeys_[i] = LocalKey(i,dim,0);
611 localKeys_[0] = LocalKey(0,1,0);
612 for (
int i=1; i<k; i++)
613 localKeys_[i] = LocalKey(0,0,i-1);
614 localKeys_.back() = LocalKey(1,1,0);
622 for (
int j=0; j<=k; j++)
623 for (
int i=0; i<=k-j; i++)
627 localKeys_[n++] = LocalKey(0,2,0);
632 localKeys_[n++] = LocalKey(1,2,0);
637 localKeys_[n++] = LocalKey(2,2,0);
642 localKeys_[n++] = LocalKey(0,1,i-1);
647 localKeys_[n++] = LocalKey(1,1,j-1);
652 localKeys_[n++] = LocalKey(2,1,j-1);
655 localKeys_[n++] = LocalKey(0,0,c++);
662 std::array<unsigned int, dim+1> vertexMap;
663 for (
unsigned int i=0; i<=dim; i++)
665 generateLocalKeys(vertexMap);
668 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for k<=1 or dim<=3!");
677 constexpr LagrangeSimplexLocalCoefficients (
const std::array<unsigned int, dim+1> vertexMap)
678 : localKeys_(Base::
size())
680 if (dim!=2 && dim!=3)
681 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==2 and dim==3!");
683 generateLocalKeys(vertexMap);
687 template<
class VertexMap>
688 constexpr LagrangeSimplexLocalCoefficients(
const VertexMap &vertexmap)
689 : localKeys_(Base::
size())
691 if (dim!=2 && dim!=3)
692 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==2 and dim==3!");
694 std::array<unsigned int, dim+1> vertexmap_array;
695 std::copy(vertexmap, vertexmap + dim + 1, vertexmap_array.begin());
696 generateLocalKeys(vertexmap_array);
700 constexpr const LocalKey& localKey (std::size_t i)
const
702 return localKeys_[i];
709 std::vector<LocalKey> localKeys_;
711 constexpr void generateLocalKeys(
const std::array<unsigned int, dim+1> vertexMap)
713 const int k = Base::order();
716 localKeys_[0] = LocalKey(0,0,0);
725 for (
int j=0; j<=k; j++)
726 for (
int i=0; i<=k-j; i++)
730 localKeys_[n++] = LocalKey(0,2,0);
735 localKeys_[n++] = LocalKey(1,2,0);
740 localKeys_[n++] = LocalKey(2,2,0);
745 localKeys_[n++] = LocalKey(0,1,i-1);
750 localKeys_[n++] = LocalKey(1,1,j-1);
755 localKeys_[n++] = LocalKey(2,1,j-1);
758 localKeys_[n++] = LocalKey(0,0,c++);
763 flip[0] = vertexMap[0] > vertexMap[1];
764 flip[1] = vertexMap[0] > vertexMap[2];
765 flip[2] = vertexMap[1] > vertexMap[2];
766 for (std::size_t i=0; i<Base::size(); i++)
767 if (localKeys_[i].codim()==1 && flip[localKeys_[i].subEntity()])
768 localKeys_[i].index(k-2-localKeys_[i].index());
774 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==3!");
776 unsigned int subindex[16];
777 unsigned int codim_count[4] = {0};
778 for (
unsigned int m = 1; m < 16; ++m)
780 unsigned int codim = !(m&1) + !(m&2) + !(m&4) + !(m&8);
781 subindex[m] = codim_count[codim]++;
784 int a1 = (3*k + 12)*k + 11;
786 unsigned int dof_count[16] = {0};
788 for (i[3] = 0; i[3] <= k; ++i[3])
789 for (i[2] = 0; i[2] <= k - i[3]; ++i[2])
790 for (i[1] = 0; i[1] <= k - i[2] - i[3]; ++i[1])
792 i[0] = k - i[1] - i[2] - i[3];
794 unsigned int entity = 0;
795 unsigned int codim = 0;
796 for (
unsigned int m = 0; m < 4; ++m)
798 j[m] = i[vertexMap[m]];
799 entity += !!j[m] << m;
802 int local_index = j[3]*(a1 + (a2 + j[3])*j[3])/6
803 + j[2]*(2*(k - j[3]) + 3 - j[2])/2 + j[1];
804 localKeys_[local_index] = LocalKey(subindex[entity], codim, dof_count[entity]++);
813 template<
class LocalBasis>
814 class LagrangeSimplexLocalInterpolation
815 :
public LocalBasis::Base
817 using Base =
typename LocalBasis::Base;
820 constexpr LagrangeSimplexLocalInterpolation () =
default;
823 explicit constexpr LagrangeSimplexLocalInterpolation (
const LocalBasis& localBasis)
834 template<
typename F,
typename C>
835 constexpr void interpolate (
const F& f, std::vector<C>& out)
const
837 constexpr auto dim = LocalBasis::Traits::dimDomain;
838 const int k = Base::order();
839 using D =
typename LocalBasis::Traits::DomainFieldType;
841 typename LocalBasis::Traits::DomainType x;
843 out.resize(Base::size());
857 std::fill(x.begin(), x.end(), 0);
861 for (
int i=0; i<dim; i++)
863 for (
int j=0; j<dim; j++)
873 for (
int i=0; i<k+1; i++)
884 for (
int j=0; j<=k; j++)
885 for (
int i=0; i<=k-j; i++)
887 x = { ((D)i)/k, ((D)j)/k };
895 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalInterpolation only implemented for dim<=3!");
897 const int kdiv = (k==0 ? 1 : k);
900 for (
int i2 = 0; i2 <= k; i2++)
901 for (
int i1 = 0; i1 <= k-i2; i1++)
902 for (
int i0 = 0; i0 <= k-i1-i2; i0++)
904 x[0] = ((D)i0)/((D)kdiv);
905 x[1] = ((D)i1)/((D)kdiv);
906 x[2] = ((D)i2)/((D)kdiv);
971 template<
class D,
class R,
int d,
int compileTimeOrder = -1>
978 Impl::LagrangeSimplexLocalBasis<D,R,d,compileTimeOrder>,
979 Impl::LagrangeSimplexLocalCoefficients<d,compileTimeOrder>,
980 Impl::LagrangeSimplexLocalInterpolation<Impl::LagrangeSimplexLocalBasis<D,R,d,compileTimeOrder> > >;
986 , interpolation_(basis_)
988 static_assert(compileTimeOrder >= 0,
"Default constructor only allowed for compile-time >= 0");
993 : basis_(runTimeOrder)
994 , coefficients_(runTimeOrder)
995 , interpolation_(basis_)
997 if (runTimeOrder < 0)
1003 template<
typename VertexMap>
1006 , coefficients_(vertexmap)
1007 , interpolation_(basis_)
1021 return coefficients_;
1028 return interpolation_;
1032 constexpr std::size_t
size ()
const
1034 return basis_.size();
Unique label for each type of entities that can occur in DUNE grids.
Definition: type.hh:114
Default exception if a function was called while the object is not in a valid state for that function...
Definition: exceptions.hh:375
Lagrange finite element for simplices with arbitrary compile-time dimension and static or dynamic pol...
Definition: lagrangesimplex.hh:973
constexpr std::size_t size() const
The number of shape functions.
Definition: lagrangesimplex.hh:1032
constexpr const Traits::LocalCoefficientsType & localCoefficients() const
Returns the assignment of the degrees of freedom to the element subentities.
Definition: lagrangesimplex.hh:1019
constexpr LagrangeSimplexLocalFiniteElement(const VertexMap &vertexmap)
Constructs a finite element given a vertex reordering.
Definition: lagrangesimplex.hh:1004
static constexpr GeometryType type()
The reference element that the local finite element is defined on.
Definition: lagrangesimplex.hh:1039
constexpr LagrangeSimplexLocalFiniteElement()
Constructor for compile-time order.
Definition: lagrangesimplex.hh:983
constexpr LagrangeSimplexLocalFiniteElement(int runTimeOrder)
Constructor for run-time order.
Definition: lagrangesimplex.hh:992
constexpr const Traits::LocalBasisType & localBasis() const
Returns the local basis, i.e., the set of shape functions.
Definition: lagrangesimplex.hh:1012
constexpr const Traits::LocalInterpolationType & localInterpolation() const
Returns object that evaluates degrees of freedom.
Definition: lagrangesimplex.hh:1026
A few common exception classes.
Implements a matrix constructed from a given type representing a field and compile-time given number ...
Implements a vector constructed from a given type representing a field and a compile-time given size.
decltype(auto) constexpr unpackIntegerSequence(F &&f, std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition: indices.hh:124
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
constexpr GeometryType simplex(unsigned int dim)
Returns a GeometryType representing a simplex of dimension dim.
Definition: type.hh:453
void interpolate(const F &f, const GFS &gfs, XG &xg)
interpolation from a given grid function
Definition: interpolate.hh:177
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Switch statement.
Definition: hybridutilities.hh:661
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
constexpr T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:284
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:288
Some useful basic math stuff.
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
Utilities for reduction like operations on ranges.
static const ReferenceElement & simplex()
get simplex reference elements
Definition: referenceelements.hh:162
D DomainType
domain type
Definition: localbasis.hh:43
traits helper struct
Definition: localfiniteelementtraits.hh:13
LB LocalBasisType
Definition: localfiniteelementtraits.hh:16
LC LocalCoefficientsType
Definition: localfiniteelementtraits.hh:20
LI LocalInterpolationType
Definition: localfiniteelementtraits.hh:24