5#ifndef DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGESIMPLEX_HH
6#define DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGESIMPLEX_HH
15#include <dune/common/hybridutilities.hh>
19#include <dune/geometry/referenceelements.hh>
21#include <dune/localfunctions/common/localbasis.hh>
22#include <dune/localfunctions/common/localfiniteelementtraits.hh>
23#include <dune/localfunctions/common/localkey.hh>
25namespace Dune {
namespace Impl
37 template<
class D,
class R,
unsigned int dim,
unsigned int k>
38 class LagrangeSimplexLocalBasis
48 constexpr auto barycentric(
const auto& x)
const
50 auto b = std::array<R,dim+1>{};
64 static constexpr void evaluateLagrangePolynomials(
const R& t,
auto& L)
68 L[i+1] = L[i] * (t - i) / (i+1);
73 static constexpr void evaluateLagrangePolynomialDerivative(
const R& t,
auto& LL,
unsigned int maxDerivativeOrder)
78 L[i+1] = L[i] * (t - i) / (i+1);
85 DF[i+1] = (DF[i] * (t - i) + (j+1)*F[i]) / (i+1);
89 using BarycentricMultiIndex = std::array<unsigned int,dim+1>;
105 static constexpr R barycentricDerivative(
106 BarycentricMultiIndex beta,
108 const BarycentricMultiIndex& i,
109 const BarycentricMultiIndex& alpha = {})
122 auto leftDerivatives = alpha;
123 auto rightDerivatives = alpha;
124 leftDerivatives[j]++;
125 rightDerivatives.back()++;
127 return (barycentricDerivative(beta, L, i, leftDerivatives) - barycentricDerivative(beta, L, i, rightDerivatives))*k;
137 y *= L[j][alpha[j]][i[j]];
143 using Traits = LocalBasisTraits<D,dim,FieldVector<D,dim>,R,1,FieldVector<R,1>,FieldMatrix<R,1,dim> >;
149 static constexpr unsigned int size ()
156 std::vector<typename Traits::RangeType>& out)
const
171 for (
size_t i=0; i<dim; i++)
180 auto z = barycentric(x);
182 auto L = std::array<std::array<R,k+1>, dim+1>();
184 evaluateLagrangePolynomials(z[j], L[j]);
190 for (
auto i1 : std::array{k - i0})
191 out[n++] = L[0][i0] * L[1][i1];
199 for (
auto i2 : std::array{k - i1 - i0})
200 out[n++] = L[0][i0] * L[1][i1] * L[2][i2];
209 for (
auto i3 : std::array{k - i2 - i1 - i0})
210 out[n++] = L[0][i0] * L[1][i1] * L[2][i2] * L[3][i3];
214 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalBasis for k>=2 only implemented for dim<=3");
223 std::vector<typename Traits::JacobianType>& out)
const
230 std::fill(out[0][0].begin(), out[0][0].end(), 0);
237 std::fill(out[0][0].begin(), out[0][0].end(), -1);
239 for (
unsigned int i=0; i<dim; i++)
240 for (
unsigned int j=0; j<dim; j++)
241 out[i+1][0][j] = (i==j);
247 auto z = barycentric(x);
250 auto L = std::array<std::array<std::array<R,k+1>, 2>, dim+1>();
252 evaluateLagrangePolynomialDerivative(z[j], L[j], 1);
259 for (
auto i1 : std::array{k-i0})
261 out[n][0][0] = (L[0][1][i0] * L[1][0][i1] - L[0][0][i0] * L[1][1][i1])*k;
274 for (
auto i2 : std::array{k - i1 - i0})
276 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;
277 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;
293 for (
auto i3 : std::array{k - i2 - i1 - i0})
295 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;
296 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;
297 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;
307 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalBasis for k>=2 only implemented for dim<=3");
316 void partial(
const std::array<unsigned int,dim>& order,
318 std::vector<typename Traits::RangeType>& out)
const
327 evaluateFunction(in, out);
334 for(
auto& out_i : out)
345 auto direction = std::find(order.begin(), order.end(), 1);
347 for (
unsigned int i=0; i<dim; i++)
348 out[i+1] = (i==(direction-order.begin()));
360 auto z = barycentric(in);
363 auto L = std::array<std::array<std::array<R, k+1>, staticTotalOrder+1>, dim+1>();
365 evaluateLagrangePolynomialDerivative(z[j], L[j], order[j]);
366 evaluateLagrangePolynomialDerivative(z[dim], L[dim], totalOrder);
368 auto barycentricOrder = BarycentricMultiIndex{};
370 barycentricOrder[j] = order[j];
371 barycentricOrder[dim] = 0;
373 if constexpr (dim==1)
377 for (
auto i1 : std::array{k - i0})
378 out[n++] = barycentricDerivative(barycentricOrder, L, BarycentricMultiIndex{i0, i1});
380 if constexpr (dim==2)
385 for (
auto i2 : std::array{k - i1 - i0})
386 out[n++] = barycentricDerivative(barycentricOrder, L, BarycentricMultiIndex{i0, i1, i2});
388 if constexpr (dim==3)
394 for (
auto i3 : std::array{k - i2 - i1 - i0})
395 out[n++] = barycentricDerivative(barycentricOrder, L, BarycentricMultiIndex{i0, i1, i2, i3});
401 static constexpr unsigned int order ()
412 template<
unsigned int dim,
unsigned int k>
413 class LagrangeSimplexLocalCoefficients
417 LagrangeSimplexLocalCoefficients ()
422 localKeys_[0] = LocalKey(0,0,0);
428 for (std::size_t i=0; i<
size(); i++)
429 localKeys_[i] = LocalKey(i,dim,0);
436 localKeys_[0] = LocalKey(0,1,0);
437 for (
unsigned int i=1; i<k; i++)
438 localKeys_[i] = LocalKey(0,0,i-1);
439 localKeys_.back() = LocalKey(1,1,0);
447 for (
unsigned int j=0; j<=k; j++)
448 for (
unsigned int i=0; i<=k-j; i++)
452 localKeys_[n++] = LocalKey(0,2,0);
457 localKeys_[n++] = LocalKey(1,2,0);
462 localKeys_[n++] = LocalKey(2,2,0);
467 localKeys_[n++] = LocalKey(0,1,i-1);
472 localKeys_[n++] = LocalKey(1,1,j-1);
477 localKeys_[n++] = LocalKey(2,1,j-1);
480 localKeys_[n++] = LocalKey(0,0,c++);
487 std::array<unsigned int, dim+1> vertexMap;
488 for (
unsigned int i=0; i<=dim; i++)
490 generateLocalKeys(vertexMap);
493 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for k<=1 or dim<=3!");
502 LagrangeSimplexLocalCoefficients (
const std::array<unsigned int, dim+1> vertexMap)
505 if (dim!=2 && dim!=3)
506 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==2 and dim==3!");
508 generateLocalKeys(vertexMap);
512 template<
class VertexMap>
513 LagrangeSimplexLocalCoefficients(
const VertexMap &vertexmap)
516 if (dim!=2 && dim!=3)
517 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==2 and dim==3!");
519 std::array<unsigned int, dim+1> vertexmap_array;
520 std::copy(vertexmap, vertexmap + dim + 1, vertexmap_array.begin());
521 generateLocalKeys(vertexmap_array);
525 static constexpr std::size_t
size ()
531 const LocalKey& localKey (std::size_t i)
const
533 return localKeys_[i];
537 std::vector<LocalKey> localKeys_;
539 void generateLocalKeys(
const std::array<unsigned int, dim+1> vertexMap)
543 localKeys_[0] = LocalKey(0,0,0);
552 for (
unsigned int j=0; j<=k; j++)
553 for (
unsigned int i=0; i<=k-j; i++)
557 localKeys_[n++] = LocalKey(0,2,0);
562 localKeys_[n++] = LocalKey(1,2,0);
567 localKeys_[n++] = LocalKey(2,2,0);
572 localKeys_[n++] = LocalKey(0,1,i-1);
577 localKeys_[n++] = LocalKey(1,1,j-1);
582 localKeys_[n++] = LocalKey(2,1,j-1);
585 localKeys_[n++] = LocalKey(0,0,c++);
590 flip[0] = vertexMap[0] > vertexMap[1];
591 flip[1] = vertexMap[0] > vertexMap[2];
592 flip[2] = vertexMap[1] > vertexMap[2];
593 for (std::size_t i=0; i<
size(); i++)
594 if (localKeys_[i].codim()==1 && flip[localKeys_[i].subEntity()])
595 localKeys_[i].index(k-2-localKeys_[i].index());
601 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalCoefficients only implemented for dim==3!");
603 unsigned int subindex[16];
604 unsigned int codim_count[4] = {0};
605 for (
unsigned int m = 1; m < 16; ++m)
607 unsigned int codim = !(m&1) + !(m&2) + !(m&4) + !(m&8);
608 subindex[m] = codim_count[codim]++;
611 int a1 = (3*k + 12)*k + 11;
613 unsigned int dof_count[16] = {0};
615 for (i[3] = 0; i[3] <= k; ++i[3])
616 for (i[2] = 0; i[2] <= k - i[3]; ++i[2])
617 for (i[1] = 0; i[1] <= k - i[2] - i[3]; ++i[1])
619 i[0] = k - i[1] - i[2] - i[3];
621 unsigned int entity = 0;
622 unsigned int codim = 0;
623 for (
unsigned int m = 0; m < 4; ++m)
625 j[m] = i[vertexMap[m]];
626 entity += !!j[m] << m;
629 int local_index = j[3]*(a1 + (a2 + j[3])*j[3])/6
630 + j[2]*(2*(k - j[3]) + 3 - j[2])/2 + j[1];
631 localKeys_[local_index] = LocalKey(subindex[entity], codim, dof_count[entity]++);
640 template<
class LocalBasis>
641 class LagrangeSimplexLocalInterpolation
643 static const int kdiv = (LocalBasis::order() == 0 ? 1 : LocalBasis::order());
653 template<
typename F,
typename C>
654 void interpolate (
const F& f, std::vector<C>& out)
const
656 constexpr auto dim = LocalBasis::Traits::dimDomain;
657 constexpr auto k = LocalBasis::order();
658 using D =
typename LocalBasis::Traits::DomainFieldType;
660 typename LocalBasis::Traits::DomainType x;
662 out.resize(LocalBasis::size());
676 std::fill(x.begin(), x.end(), 0);
680 for (
int i=0; i<dim; i++)
682 for (
int j=0; j<dim; j++)
692 for (
unsigned int i=0; i<k+1; i++)
703 for (
unsigned int j=0; j<=k; j++)
704 for (
unsigned int i=0; i<=k-j; i++)
706 x = { ((D)i)/k, ((D)j)/k };
714 DUNE_THROW(NotImplemented,
"LagrangeSimplexLocalInterpolation only implemented for dim<=3!");
717 for (
int i2 = 0; i2 <= (int)k; i2++)
718 for (
int i1 = 0; i1 <= (int)k-i2; i1++)
719 for (
int i0 = 0; i0 <= (int)k-i1-i2; i0++)
721 x[0] = ((D)i0)/((D)kdiv);
722 x[1] = ((D)i1)/((D)kdiv);
723 x[2] = ((D)i2)/((D)kdiv);
788 template<
class D,
class R,
int d,
int k>
795 Impl::LagrangeSimplexLocalCoefficients<d,k>,
796 Impl::LagrangeSimplexLocalInterpolation<Impl::LagrangeSimplexLocalBasis<D,R,d,k> > >;
803 template<
typename VertexMap>
805 : coefficients_(vertexmap)
819 return coefficients_;
826 return interpolation_;
830 static constexpr std::size_t
size ()
832 return Impl::LagrangeSimplexLocalBasis<D,R,d,k>::size();
843 Impl::LagrangeSimplexLocalBasis<D,R,d,k> basis_;
844 Impl::LagrangeSimplexLocalCoefficients<d,k> coefficients_;
845 Impl::LagrangeSimplexLocalInterpolation<Impl::LagrangeSimplexLocalBasis<D,R,d,k> > interpolation_;
Unique label for each type of entities that can occur in DUNE grids.
Definition: type.hh:114
Lagrange finite element for simplices with arbitrary compile-time dimension and polynomial order.
Definition: lagrangesimplex.hh:790
const Traits::LocalInterpolationType & localInterpolation() const
Returns object that evaluates degrees of freedom.
Definition: lagrangesimplex.hh:824
const Traits::LocalBasisType & localBasis() const
Returns the local basis, i.e., the set of shape functions.
Definition: lagrangesimplex.hh:810
LagrangeSimplexLocalFiniteElement()
Definition: lagrangesimplex.hh:799
static constexpr std::size_t size()
The number of shape functions.
Definition: lagrangesimplex.hh:830
LagrangeSimplexLocalFiniteElement(const VertexMap &vertexmap)
Constructs a finite element given a vertex reordering.
Definition: lagrangesimplex.hh:804
const Traits::LocalCoefficientsType & localCoefficients() const
Returns the assignment of the degrees of freedom to the element subentities.
Definition: lagrangesimplex.hh:817
static constexpr GeometryType type()
The reference element that the local finite element is defined on.
Definition: lagrangesimplex.hh:837
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.
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:674
constexpr T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:280
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:294
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:131
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