5#ifndef DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGESIMPLEX_HH
6#define DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGESIMPLEX_HH
32namespace Dune {
namespace Impl
35 template<
unsigned int dim,
int compileTimeOrder>
36 struct LagrangeSimplexTraits;
39 template<
unsigned int dim,
int compileTimeOrder>
40 requires (compileTimeOrder >= 0)
41 struct LagrangeSimplexTraits<dim,compileTimeOrder>
43 static constexpr bool is_static_order =
true;
45 constexpr LagrangeSimplexTraits(
int = compileTimeOrder) {}
48 static constexpr unsigned int order() {
return compileTimeOrder; }
59 template<
unsigned int dim>
60 struct LagrangeSimplexTraits<
dim,-1>
65 static constexpr bool is_static_order =
false;
67 constexpr explicit LagrangeSimplexTraits(
int runTimeOrder)
68 : order_(runTimeOrder >= 0 ? (unsigned int)(runTimeOrder) : 0u)
76 constexpr unsigned int order()
const
97 template<
class R,
unsigned int dim,
int k>
98 struct LagrangeSimplexLocalBasisBuffers
100 LagrangeSimplexLocalBasisBuffers(
int ) {}
103 static auto makeValueBuffer(
int )
105 using E = Std::extents<int,dim+1,k+1>;
107 return Std::mdarray<R,E,Std::layout_right,C>{};
111 static auto makeJacobianBuffer(
int )
113 using E = Std::extents<int,dim+1,2,k+1>;
115 return Std::mdarray<R,E,Std::layout_right,C>{};
119 template <
class T, T partialOrders>
122 using E = Std::extents<int,dim+1,partialOrders+1,k+1>;
124 return Std::mdarray<R,E,Std::layout_right,C>{};
136 template<
class R,
unsigned int dim>
137 struct LagrangeSimplexLocalBasisBuffers<R,
dim,-1>
139 LagrangeSimplexLocalBasisBuffers(
int order)
140 : buffer_((
dim+1)*
std::
max<int>(2,order+1)*(order+1))
146 auto makeValueBuffer(
int order)
const
148 using E = Std::extents<int,dim+1,std::dynamic_extent>;
149 return Std::mdspan<R,E>{buffer_.
data(), E(order+1)};
153 auto makeJacobianBuffer(
int order)
const
155 using E = Std::extents<int,dim+1,2,std::dynamic_extent>;
156 return Std::mdspan<R,E>{buffer_.data(), E(order+1)};
160 auto makePartialBuffer(
int partialOrders,
int order)
const
162 using E = Std::extents<int,dim+1,std::dynamic_extent,std::dynamic_extent>;
163 return Std::mdspan<R,E>{buffer_.data(), E(partialOrders+1, order+1)};
178 template<
class D,
class R,
unsigned int dim,
int compileTimeOrder>
179 class LagrangeSimplexLocalBasis
180 :
private LagrangeSimplexTraits<dim,compileTimeOrder>
181 ,
private LagrangeSimplexLocalBasisBuffers<R,dim,compileTimeOrder>
183 using OrderTraits = LagrangeSimplexTraits<dim,compileTimeOrder>;
184 using Buffers = LagrangeSimplexLocalBasisBuffers<R,dim,compileTimeOrder>;
185 static constexpr bool is_static_order = OrderTraits::is_static_order;
189 constexpr LagrangeSimplexLocalBasis ()
requires (OrderTraits::is_static_order)
190 : LagrangeSimplexLocalBasis(OrderTraits())
194 explicit constexpr LagrangeSimplexLocalBasis(OrderTraits orderTraits)
195 : OrderTraits(orderTraits)
196 , Buffers(orderTraits.order())
199 using OrderTraits::order;
200 using OrderTraits::size;
208 static auto slice(Std::mdspan<R,Std::extents<I,e0,ee...>,Std::layout_right,A> L,
int i)
211 return Std::mdspan<R,Std::extents<I,ee...>,Std::layout_right>{
212 L.data_handle() + i * L.stride(0), L.extent(ii+1)...};
218 static auto slice(Std::mdarray<R,Std::extents<I,e0,ee...>,Std::layout_right,C>& L,
int i)
220 return slice(L.to_mdspan(), i);
230 constexpr auto barycentric(
const auto& x)
const
236 b[i] = order() * x[i];
246 static constexpr void evaluateLagrangePolynomials(
const R& t,
auto&& L,
int k)
250 L[i+1] = L[i] * (t - i) / (i+1);
255 static constexpr void evaluateLagrangePolynomialDerivative(
const R& t,
auto&& LL,
unsigned int maxDerivativeOrder,
int k)
257 auto L = slice(LL,0);
260 L[i+1] = L[i] * (t - i) / (i+1);
261 for(
auto j :
Dune::
range(maxDerivativeOrder))
263 auto F = slice(LL,j);
264 auto DF = slice(LL,j+1);
267 DF[i+1] = (DF[i] * (t - i) + (j+1)*F[i]) / (i+1);
287 static constexpr R barycentricDerivative(
288 BarycentricMultiIndex beta,
291 const BarycentricMultiIndex& i,
292 const BarycentricMultiIndex& alpha = {})
305 auto leftDerivatives = alpha;
306 auto rightDerivatives = alpha;
307 leftDerivatives[j]++;
308 rightDerivatives.
back()++;
310 return (barycentricDerivative(beta, L, k, i, leftDerivatives) -
311 barycentricDerivative(beta, L, k, i, rightDerivatives)) * k;
321 y *= L(j,alpha[j],i[j]);
327 using Traits = LocalBasisTraits<D,dim,FieldVector<D,dim>,R,1,FieldVector<R,1>,FieldMatrix<R,1,dim> >;
333 const int k = order();
347 for (
size_t i=0; i<
dim; i++)
356 auto z = barycentric(x);
358 auto L = Buffers::makeValueBuffer(k);
360 evaluateLagrangePolynomials(z[j], slice(L,j), k);
366 for (auto i1 :
std::array{k - i0})
367 out[n++] = L(0,i0) * L(1,i1);
375 for (auto i2 :
std::array{k - i1 - i0})
376 out[n++] = L(0,i0) * L(1,i1) * L(2,i2);
384 for (auto i0 :
Dune::
range(k - i2 - i1 + 1))
385 for (auto i3 :
std::array{k - i2 - i1 - i0})
386 out[n++] = L(0,i0) * L(1,i1) * L(2,i2) * L(3,i3);
390 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalBasis for k>=2 only implemented for dim<=3");
401 const int k = order();
416 for (
unsigned int i=0; i<
dim; i++)
417 for (
unsigned int j=0; j<
dim; j++)
418 out[i+1][0][j] = (i==j);
424 auto z = barycentric(x);
427 auto L = Buffers::makeJacobianBuffer(k);
429 evaluateLagrangePolynomialDerivative(z[j], slice(L,j), 1, k);
436 for (
auto i1 :
std::array{k-i0})
438 out[n][0][0] = (L(0,1,i0) * L(1,0,i1) - L(0,0,i0) * L(1,1,i1))*k;
451 for (
auto i2 :
std::array{k - i1 - i0})
453 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;
454 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;
468 for (
auto i0 :
Dune::
range(k - i2 - i1 + 1))
470 for (
auto i3 :
std::array{k - i2 - i1 - i0})
472 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;
473 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;
474 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;
484 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalBasis for k>=2 only implemented for dim<=3");
497 const int k = order();
505 evaluateFunction(in, out);
512 for(
auto& out_i : out)
525 for (
unsigned int i=0; i<
dim; i++)
526 out[i+1] = (i==(direction-partialOrders.
begin()));
534 auto supportedOrders = [&]{
535 if constexpr(is_static_order)
543 auto z = barycentric(in);
546 auto L = Buffers::makePartialBuffer(staticTotalOrder,k);
548 evaluateLagrangePolynomialDerivative(z[j], slice(L,j), partialOrders[j], k);
549 evaluateLagrangePolynomialDerivative(z[
dim], slice(L,
dim), totalOrder, k);
551 auto barycentricOrder = BarycentricMultiIndex{};
553 barycentricOrder[j] = partialOrders[j];
554 barycentricOrder[
dim] = 0;
556 if constexpr (
dim==1)
560 for (auto i1 :
std::array{k - i0})
561 out[n++] = barycentricDerivative(barycentricOrder, L, k, BarycentricMultiIndex{i0, i1});
563 if constexpr (
dim==2)
568 for (auto i2 :
std::array{k - i1 - i0})
569 out[n++] = barycentricDerivative(barycentricOrder, L, k, BarycentricMultiIndex{i0, i1, i2});
571 if constexpr (
dim==3)
576 for (auto i0 :
Dune::
range(k - i2 - i1 + 1))
577 for (auto i3 :
std::array{k - i2 - i1 - i0})
578 out[n++] = barycentricDerivative(barycentricOrder, L, k, BarycentricMultiIndex{i0, i1, i2, i3});
589 template<
unsigned int dim,
int compileTimeOrder>
590 class LagrangeSimplexLocalCoefficients
591 :
private LagrangeSimplexTraits<dim,compileTimeOrder>
593 using OrderTraits = LagrangeSimplexTraits<dim,compileTimeOrder>;
597 LagrangeSimplexLocalCoefficients ()
requires (OrderTraits::is_static_order)
598 : LagrangeSimplexLocalCoefficients(OrderTraits())
602 LagrangeSimplexLocalCoefficients (OrderTraits orderTraits)
603 : OrderTraits(orderTraits)
604 , localKeys_(OrderTraits::
size())
606 const int k = OrderTraits::order();
609 localKeys_[0] = LocalKey(0,0,0);
616 localKeys_[i] = LocalKey(i,
dim,0);
623 localKeys_[0] = LocalKey(0,1,0);
624 for (
int i=1; i<k; i++)
625 localKeys_[i] = LocalKey(0,0,i-1);
626 localKeys_.back() = LocalKey(1,1,0);
634 for (
int j=0; j<=k; j++)
635 for (
int i=0; i<=k-j; i++)
639 localKeys_[n++] = LocalKey(0,2,0);
644 localKeys_[n++] = LocalKey(1,2,0);
649 localKeys_[n++] = LocalKey(2,2,0);
654 localKeys_[n++] = LocalKey(0,1,i-1);
659 localKeys_[n++] = LocalKey(1,1,j-1);
664 localKeys_[n++] = LocalKey(2,1,j-1);
667 localKeys_[n++] = LocalKey(0,0,c++);
675 for (
unsigned int i=0; i<=
dim; i++)
677 generateLocalKeys(vertexMap);
680 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for k<=1 or dim<=3!");
690 : localKeys_(OrderTraits::
size())
693 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==2 and dim==3!");
695 generateLocalKeys(vertexMap);
699 template<std::input_iterator VertexMap>
700 constexpr LagrangeSimplexLocalCoefficients(
const VertexMap &vertexmap)
requires (OrderTraits::is_static_order)
701 : localKeys_(OrderTraits::
size())
704 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==2 and dim==3!");
708 generateLocalKeys(vertexmap_array);
712 constexpr const LocalKey& localKey (
std::size_t i)
const
714 return localKeys_[i];
717 using OrderTraits::order;
718 using OrderTraits::size;
725 const int k = OrderTraits::order();
728 localKeys_[0] = LocalKey(0,0,0);
737 for (
int j=0; j<=k; j++)
738 for (
int i=0; i<=k-j; i++)
742 localKeys_[n++] = LocalKey(0,2,0);
747 localKeys_[n++] = LocalKey(1,2,0);
752 localKeys_[n++] = LocalKey(2,2,0);
757 localKeys_[n++] = LocalKey(0,1,i-1);
762 localKeys_[n++] = LocalKey(1,1,j-1);
767 localKeys_[n++] = LocalKey(2,1,j-1);
770 localKeys_[n++] = LocalKey(0,0,c++);
775 flip[0] = vertexMap[0] > vertexMap[1];
776 flip[1] = vertexMap[0] > vertexMap[2];
777 flip[2] = vertexMap[1] > vertexMap[2];
779 if (localKeys_[i].codim()==1 && flip[localKeys_[i].subEntity()])
780 localKeys_[i].
index(k-2-localKeys_[i].
index());
786 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==3!");
788 unsigned int subindex[16];
789 unsigned int codim_count[4] = {0};
790 for (
unsigned int m = 1; m < 16; ++m)
792 unsigned int codim = !(m&1) + !(m&2) + !(m&4) + !(m&8);
793 subindex[m] = codim_count[codim]++;
796 int a1 = (3*k + 12)*k + 11;
798 unsigned int dof_count[16] = {0};
800 for (i[3] = 0; i[3] <= k; ++i[3])
801 for (i[2] = 0; i[2] <= k - i[3]; ++i[2])
802 for (i[1] = 0; i[1] <= k - i[2] - i[3]; ++i[1])
804 i[0] = k - i[1] - i[2] - i[3];
806 unsigned int entity = 0;
807 unsigned int codim = 0;
808 for (
unsigned int m = 0; m < 4; ++m)
810 j[m] = i[vertexMap[m]];
811 entity += !!j[m] << m;
814 int local_index = j[3]*(a1 + (a2 + j[3])*j[3])/6
815 + j[2]*(2*(k - j[3]) + 3 - j[2])/2 + j[1];
816 localKeys_[local_index] = LocalKey(subindex[entity], codim, dof_count[entity]++);
828 template<
class D,
class R,
int dim,
int compileTimeOrder>
829 class LagrangeSimplexLocalInterpolation
830 :
private LagrangeSimplexTraits<dim, compileTimeOrder>
832 using OrderTraits = LagrangeSimplexTraits<dim, compileTimeOrder>;
833 using Traits =
typename LagrangeSimplexLocalBasis<D, R, dim, compileTimeOrder>::Traits;
835 using OrderTraits::size;
838 constexpr LagrangeSimplexLocalInterpolation ()
requires (OrderTraits::is_static_order)
843 explicit constexpr LagrangeSimplexLocalInterpolation (OrderTraits orderTraits)
844 : OrderTraits(orderTraits)
854 template<
typename F,
typename C>
855 constexpr void interpolate (
const F& f,
std::vector<C>& out)
const
857 const int k = OrderTraits::order();
858 out.
resize(OrderTraits::size());
863 auto center = ReferenceElements<D,dim>::simplex().position(0,0);
864 out[0] = Impl::rangeCast(f(center));
868 typename Traits::DomainType x;
875 out[0] = Impl::rangeCast(f(x));
878 for (
unsigned int i=0; i<
dim; i++)
880 for (
unsigned int j=0; j<
dim; j++)
883 out[i+1] = Impl::rangeCast(f(x));
890 for (
int i=0; i<k+1; i++)
893 out[i] = Impl::rangeCast(f(x));
901 for (
int j=0; j<=k; j++)
902 for (
int i=0; i<=k-j; i++)
904 x = { ((D)i)/k, ((D)j)/k };
905 out[n] = Impl::rangeCast(f(x));
912 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalInterpolation only implemented for dim<=3!");
914 const int kdiv = (k==0 ? 1 : k);
917 for (
int i2 = 0; i2 <= k; i2++)
918 for (
int i1 = 0; i1 <= k-i2; i1++)
919 for (
int i0 = 0; i0 <= k-i1-i2; i0++)
921 x[0] = ((D)i0)/((D)kdiv);
922 x[1] = ((D)i1)/((D)kdiv);
923 x[2] = ((D)i2)/((D)kdiv);
924 out[n] = Impl::rangeCast(f(x));
988 template<
class D,
class R,
int dim,
int compileTimeOrder = -1>
990 :
private Impl::LagrangeSimplexTraits<dim, compileTimeOrder>
992 using OrderTraits = Impl::LagrangeSimplexTraits<dim, compileTimeOrder>;
998 Impl::LagrangeSimplexLocalBasis<D,R,dim,compileTimeOrder>,
999 Impl::LagrangeSimplexLocalCoefficients<dim,compileTimeOrder>,
1000 Impl::LagrangeSimplexLocalInterpolation<D,R,dim,compileTimeOrder> >;
1006 , coefficients_(*this)
1007 , interpolation_(*this)
1009 static_assert(OrderTraits::is_static_order,
"Default constructor only allowed for compile-time order >= 0");
1010 static_assert(compileTimeOrder >= 0,
"Default constructor only allowed for compile-time order >= 0");
1015 : OrderTraits(runTimeOrder)
1017 , coefficients_(*this)
1018 , interpolation_(*this)
1020 if (runTimeOrder < 0)
1022 if (compileTimeOrder >= 0 && compileTimeOrder != runTimeOrder)
1028 template<
typename VertexMap>
1032 , coefficients_(vertexmap)
1033 , interpolation_(*this)
1047 return coefficients_;
1054 return interpolation_;
1058 using OrderTraits::size;
1064 return GeometryTypes::simplex(
dim);
static constexpr IntegralRange< T > range(T from, T to) noexcept
decltype(auto) constexpr unpackIntegerSequence(F &&f, std::integer_sequence< I, i... > sequence)
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
std::ptrdiff_t index() const
#define DUNE_THROW(E,...)
static constexpr T binomial(const T &n, const T &k) noexcept
D DomainType
domain type
Definition common/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
Lagrange finite element for simplices with arbitrary compile-time dimension and static or dynamic pol...
Definition lagrangesimplex.hh:991
constexpr const Traits::LocalCoefficientsType & localCoefficients() const
Returns the assignment of the degrees of freedom to the element subentities.
Definition lagrangesimplex.hh:1045
constexpr LagrangeSimplexLocalFiniteElement(const VertexMap &vertexmap)
Constructs a finite element given a vertex reordering.
Definition lagrangesimplex.hh:1029
static constexpr GeometryType type()
The reference element that the local finite element is defined on.
Definition lagrangesimplex.hh:1062
constexpr const Traits::LocalBasisType & localBasis() const
Returns the local basis, i.e., the set of shape functions.
Definition lagrangesimplex.hh:1038
constexpr const Traits::LocalInterpolationType & localInterpolation() const
Returns object that evaluates degrees of freedom.
Definition lagrangesimplex.hh:1052
constexpr LagrangeSimplexLocalFiniteElement(int runTimeOrder)
Constructor for run-time order.
Definition lagrangesimplex.hh:1014
constexpr LagrangeSimplexLocalFiniteElement()
Constructor for compile-time order.
Definition lagrangesimplex.hh:1003