KASKADE 7 development version
lagrangeshapefunctions.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2021 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef FEM_LAGRANGESHAPEFUNCTIONS_HH
14#define FEM_LAGRANGESHAPEFUNCTIONS_HH
15
24#include <cmath>
25#include <functional>
26#include <map>
27#include <memory>
28#include <numeric>
29#include <tuple>
30#include <utility>
31
32#include <dune/common/config.h>
33#include <dune/common/fvector.hh>
34#include <dune/geometry/referenceelements.hh>
35#include <dune/geometry/quadraturerules.hh>
36
37#include "fem/barycentric.hh"
43#include "utilities/power.hh"
45
46//---------------------------------------------------------------------
47
48namespace Kaskade
49{
50 // forward declarations
51 template <class ctype, int dimension, class Scalar>
52 class LagrangeSimplexShapeFunctionSet;
53
57 namespace SimplexLagrangeDetail {
58
59
64 inline int size(int dim, int order)
65 {
66 if (order < 0)
67 return 0;
68
69 return binomial(dim+order,dim);
70 }
71
79 inline int local(int const* xi, int dim, int order)
80 {
81 assert(std::accumulate(xi,xi+dim,0)<=order);
82
83 int local = 0;
84 for (int dir=0; dir<dim; ++dir)
85 for (int i=0; i<xi[dir]; ++i) {
86 local += size(dim-1-dir,order);
87 --order;
88 }
89 return local;
90 }
91
101 template <int dim>
102 std::array<int,dim> tupleIndex(int const order, int const loc)
103 {
104 int m = order;
105 int k = loc;
106 std::array<int,dim> xi;
107 std::fill(begin(xi),end(xi),0);
108
109 for (int dir=0; dir<dim; ++dir) {
110 int s = size(dim-1-dir,m);
111 while (k>=s && s>0) {
112 k -= s;
113 --m;
114 ++xi[dir];
115 s = size(dim-1-dir,m);
116 }
117 }
118 assert(local(&xi[0],dim,order)==loc);
119 return xi;
120 }
121
125 template <int dim>
126 Dune::FieldVector<double,dim> nodalPosition(std::array<int,dim> const& xi, int const order)
127 {
128 // construct equidistant interpolation nodes. max in denominator is just to prevent GCC from
129 // choking on division by 0.
131 for (int i=0; i<dim; ++i)
132 x[i] = order==0? 1.0/(dim+1): static_cast<double>(xi[i])/(order>0? order: 1);
133 return x;
134 }
135
136
140 template <size_t dim_1>
141 int codim(std::array<int,dim_1> const& xi)
142 {
143 // That's simple. If a barycentric coordinate is 0, the node is
144 // located on the associated facet (codim=1) of the simplex. The
145 // node lies on the intersection of all facets on which is
146 // located. Each incident facet increases the codimension by one.
147 int count = 0;
148 int dim = dim_1 - 1;
149
150 for (int i=0; i<=dim; ++i)
151 if (xi[i]==0) ++count;
152
153 if (count > dim) // all entries 0 -> order==0
154 return 0;
155
156 return count;
157 }
158
159 // Given a barycentric coordinate vector, this function computes the
160 // simplex local id of the largest codim subentity on which the node
161 // is located. The implementation is based on the reference element
162 // documentation of Dune.
163 template <size_t dim_1>
164 int entity(std::array<int,dim_1> const& xi)
165 {
166 int dim = dim_1 - 1;
167
168 switch (dim) {
169 case 1: // lines
170 switch (codim(xi)) {
171 case 0: // edge
172 return 0;
173 case 1: // vertex
174 if (xi[0]!=0) return 1;
175 if (xi[1]!=0) return 0;
176 break;
177 default: assert(false);
178 }
179 break;
180 case 2: // triangles
181 switch (codim(xi)) {
182 case 0: // triangle
183 return 0;
184 case 1: // edge
185 if (xi[0]==0) return 1;
186 if (xi[1]==0) return /*2*/0;
187 if (xi[2]==0) return /*0*/2; //new Dune 2.0 numbering: 2-oldIndex
188 break;
189 case 2: // vertex
190 if (xi[0]!=0) return 1;
191 if (xi[1]!=0) return 2;
192 if (xi[2]!=0) return 0;
193 break;
194 }
195 break;
196 case 3: // tetrahedra
197 switch (codim(xi)) {
198 case 0: // tetrahedron
199 return 0;
200 case 1: // triangle
201 if (xi[0]==0) return /*1*/ 2 ; //new Dune 2.0 numbering: 3-oldIndex
202 if (xi[1]==0) return /*2*/ 1 ;
203 if (xi[2]==0) return /*3*/ 0 ;
204 if (xi[3]==0) return /*0*/ 3 ;
205 break;
206 case 2: // edge
207 if (xi[0]==0 && xi[1]==0) return 3;
208 if (xi[0]==0 && xi[2]==0) return /*2*/1; //new Dune 2.0 numbering: xchg(1,2)
209 if (xi[0]==0 && xi[3]==0) return 5;
210 if (xi[1]==0 && xi[2]==0) return 0;
211 if (xi[1]==0 && xi[3]==0) return 4;
212 if (xi[2]==0 && xi[3]==0) return /*1*/2;
213 break;
214 case 3: // vertex
215 if (xi[0]!=0) return 1;
216 if (xi[1]!=0) return 2;
217 if (xi[2]!=0) return 3;
218 if (xi[3]!=0) return 0;
219 break;
220 }
221 break;
222 }
223 assert("Unknown dimension/codimension\n"==0);
224 return -1;
225 }
226
227// // cycle through all possible tuple indices of sum up to m.
228// template <int dim>
229// void increment(Dune::FieldVector<int,dim>& x, int const m)
230// {
231// for (int i=0; i<dim; ++i) {
232// int sum = std::accumulate(x.begin(),x.end(),0);
233// if (sum==m) // carry
234// x[i] = 0;
235// else {
236// ++x[i];
237// break;
238// }
239// }
240// }
241
242
243
244 // Choose between normal (full polynomial) shape function sets and
245 // boundary-restricted ones.
246 template <class ctype, int dimension, class Scalar, bool restricted>
247 struct ChooseShapeFunctionSet
248 {
249 typedef LagrangeSimplexShapeFunctionSet<ctype,dimension,Scalar> type;
250 };
251
252 template <class ctype, int dimension, class Scalar>
253 struct ChooseShapeFunctionSet<ctype,dimension,Scalar,true>
254 {
255 typedef RestrictedShapeFunctionSet<LagrangeSimplexShapeFunctionSet<ctype,dimension,Scalar> > type;
256 };
257 } // End of namespace SimplexLagrangeDetail
262 //---------------------------------------------------------------------
263 //---------------------------------------------------------------------
264
265
266 template <int dim>
268 {
269 public:
276
280 int size() const
281 {
282 return ls.size();
283 }
284
288 int order() const
289 {
290 return myOrder;
291 }
292
293 std::array<int,dim+1> index(int i) const
294 {
295 return ls[i];
296 }
297
298 protected:
300 std::vector<std::array<int,dim+1>> ls;
301 };
302
303 //---------------------------------------------------------------------
304
312 template <int dim, class Real=double>
314 {
315 public:
317
324
329 Vector nodalPosition(int i) const;
330
331 Real value(int i, Vector const& xi) const;
332 Real derivative(int i, int dir, Vector const& xi) const;
333 Real derivative2(int i, int dir1, int dir2, Vector const& xi) const;
334
335 private:
336 std::vector<Real> normalization;
337 };
338
339 //---------------------------------------------------------------------
340
341 template <int dim, class Real=double>
343 {
344 public:
346
348 Vector nodalPosition(int i) const;
349 Real value(int i, Vector const& x) const;
350 Real derivative(int i, int dir, Vector const& xi) const;
351 Real derivative2(int i, int dir1, int dir2, Vector const& xi) const;
352 private:
353 std::vector<Real> lobatto; // Lobatto nodes on [0,1]
354 EquidistantLagrange<dim,Real> basis; // basis functions used for evaluation
355 DynamicMatrix<Real> vInv; // inverse of the Vandermonde matrix
356 };
357
358 //---------------------------------------------------------------------
359 //---------------------------------------------------------------------
360
381 template <class ctype, int dimension, class Basis, class Scalar=double>
382 class LagrangeSimplexShapeFunction: public ShapeFunction<ctype,dimension,Scalar>
383 {
384 public:
385 static int const dim = dimension;
386 static int const comps = 1;
387
388 typedef ctype CoordType;
389 typedef Scalar ResultType;
390
399 : local_(-1), codim_(-1), entity_(-1), entityIndex_(-1) {}
400
401
407 explicit LagrangeSimplexShapeFunction(int local,
408 std::shared_ptr<Basis const> basis_)
409 : local_(local)
410 , basis(basis_)
411 {
412 int const order = basis->order();
413
414 // Compute local subentity indices:
415 // Interprete the barycentric index interior to the subentity as
416 // complete barycentric index of a lower dimensional simplex
417 // with reduced order p=order-(dim-codim_+1).
418 if (order==0)
419 {
420 codim_ = 0;
421 entity_ = 0;
422 entityIndex_ = 0;
423 }
424 else
425 {
426 // construct barycentric indices
427 auto xi = basis->index(local_);
428
429 codim_ = SimplexLagrangeDetail::codim(xi);
430 entity_ = SimplexLagrangeDetail::entity(xi);
431
432 int yi[dim-codim_+1];
433 int j=0;
434 for (int i=0; i<=dim; ++i)
435 if (xi[i]!=0)
436 yi[j++] = xi[i]-1;
437 assert(j==dim-codim_+1);
438 entityIndex_ = SimplexLagrangeDetail::local(yi,dim-codim_,order-(dim-codim_+1));
439 assert(entityIndex_>=0);
440 }
441 }
442
447
456 {
457 return basis->value(local_,x);
458 }
459
470 {
472 for (int dir=0; dir<dim; ++dir)
473 d[0][dir] = basis->derivative(local_,dir,x);
474 return d;
475 }
476
487 {
488 // exploit symmetry of 2nd derivative
490 for (int dir1=0; dir1<dim; ++dir1)
491 for (int dir2=0; dir2<=dir1; ++dir2)
492 d[0][dir1][dir2] = basis->derivative2(local_,dir1,dir2,x);
493
494 for (int dir1=0; dir1<dim; ++dir1)
495 for (int dir2=dir1+1; dir2<dim; ++dir2)
496 d[0][dir1][dir2] = d[0][dir2][dir1];
497
498 return d;
499 }
500
501 virtual std::tuple<int,int,int,int> location() const
502 {
503 return std::make_tuple(basis->order(),codim_,entity_,entityIndex_);
504 }
505
506 private:
507 int local_;
508 int codim_;
509 int entity_;
510 int entityIndex_;
511
512 std::shared_ptr<Basis const> basis;
513 };
514
515
516
517 //---------------------------------------------------------------------
518
523 template <class ctype, int dimension, class Scalar>
524 class LagrangeSimplexShapeFunctionSet: public ShapeFunctionSet<ctype,dimension,Scalar>
525 {
526// using Basis = EquidistantLagrange<dimension,ctype>;
528
529 public:
532
534 : ShapeFunctionSet<ctype,dimension,Scalar>(Dune::GeometryType(Dune::GeometryType::simplex,dimension))
535 , basis(new Basis(order<0? 0: order))
536 {
537 int const dim = dimension;
538 int const n = basis->size();
539 this->iNodes.resize(n);
540
541 for (int i=0; i<n; ++i)
542 {
543 sf.push_back(std::unique_ptr<ShapeFunction<ctype,dim,Scalar>>(new value_type(i,basis)));
544 for (int j=0; j<dim; ++j)
545 this->iNodes[i] = basis->nodalPosition(i);
546 }
547 this->order_ = order;
548 this->size_ = n;
549 }
550
552 : ShapeFunctionSet<ctype,dimension,Scalar>(Dune::GeometryType(Dune::GeometryType::simplex,dimension))
553 {
554 this->iNodes = other.iNodes;
555 this->order_ = other.order_;
556 this->size_ = other.size_;
557 for(size_t i=0; i<other.sf.size(); ++i)
558 sf.push_back(std::make_unique<value_type>(dynamic_cast<value_type const&>(other[i])));
559 }
560
562 {
563 return *sf[i];
564 }
565
567 Matrix& IA) const
568 {
569 assert(A.N()==sf.size());
570 IA = A;
571 // For Lagrange shape functions, the interpolation at their nodes is just the identity. Copy!
572 }
573
574 void removeShapeFunction(size_t index)
575 {
576 assert(index>=0 && index < sf.size());
577 sf.erase(sf.begin()+index);
578 this->iNodes.erase(this->iNodes.begin()+index);
579 }
580
581 protected:
582 std::vector<std::unique_ptr<ShapeFunction<ctype,dimension,Scalar>>> sf;
583
584 private:
585 std::shared_ptr<Basis const> basis;
586 };
587
588 //---------------------------------------------------------------------
589 //---------------------------------------------------------------------
590 //---------------------------------------------------------------------
591
612 template <class ctype, int dimension, class Scalar, int O>
613 class LagrangeCubeShapeFunction: public ShapeFunction<ctype,dimension,Scalar>
614 {
615 public:
616 static int const dim = dimension;
617 static int const comps = 1;
618 static int const order = O;
619
620 typedef ctype CoordType;
621 typedef Scalar ResultType;
622
629 local_(-1)
630 {}
631
633 : local_(other.local_), codim_(other.codim_), entity_(other.entity_), entityIndex_(other.entityIndex_),
634 xi(other.xi), normalization(other.normalization), node(other.node)
635 {}
636
644
653 {
654 return normalization * evaluateNonNormalized(x);
655 }
656
658 {
659 return normalization * evaluateNonNormalized(x);
660 }
661
670 ResultType evaluateDerivative(int /* comp */, int dir, Dune::FieldVector<CoordType,dim> const& x) const
671 {
672 assert(0<=dir && dir<dim);
673 return normalization * evaluateDerivativeNonNormalized(dir,x);
674 }
675
677 {
679 for (int dir=0; dir<dim; ++dir)
680 d[0][dir] = normalization * evaluateDerivativeNonNormalized(dir,x);
681 return d;
682 }
683
684
686 {
688 for (int dir1=0; dir1<dim; ++dir1)
689 for (int dir2=0; dir2<dim; ++dir2)
690 dd[0][dir1][dir2] = normalization * evaluate2ndDerivativeNonNormalized(dir1,dir2,x);
691 return dd;
692 }
693
697 int localindex(int /* comp */) const { return local_; }
698
702 int codim() const { return codim_; }
703
708 int entity() const { return entity_; }
709
717 template <class Cell>
718 int entityIndex(Cell const& /* cell */) const
719 {
720 // If ordering of dofs is completely local (cell interiors) or
721 // globally unique (only one dof on subentity, e.g. vertex or order<=2), return the
722 // precomputed value.
723 if (entityIndex_ >= 0)
724 return entityIndex_;
725
726 // Otherwise we have to compute a globally unique ordering (which
727 // will necessarily depend on the actual element).
728 // @todo: implement this!
729 assert("Not implemented!"==0);
730 return -1;
731 }
732
737 {
739 for (int i=0; i<dim; ++i)
740 pos[i] = node[xi[i]];
741 return pos;
742 }
743
744 virtual std::tuple<int,int,int,int> location() const {
745 return std::make_tuple(order,codim_,entity_,entityIndex_);
746 }
747
748 private:
749 int local_;
750 int codim_;
751 int entity_;
752 int entityIndex_;
754 ResultType normalization;
756
757 ResultType evaluateNonNormalized(Dune::FieldVector<CoordType,dim> const& x) const
758 {
759 ResultType phi = 1;
760 for (int i=0; i<dim; ++i)
761 for (int k=0; k<=order; ++k)
762 if (k!=xi[i])
763 phi *= x[i]-node[k];
764 return phi;
765 }
766
767 Scalar evaluateDerivativeNonNormalized(int dir, Dune::FieldVector<ctype,dimension> const& x) const;
768
769 ResultType evaluate2ndDerivativeNonNormalized(int dir1, int dir2, Dune::FieldVector<CoordType,dim> const& x) const
770 {
771 static bool visited = false;
772 if (!visited)
773 {
774 visited = true;
775 std::cerr << "Not implemented: Lagrange cube shape function 2nd derivative at " << __FILE__ << ":" << __LINE__ << "\n";
776 }
777 return 0;
778 }
779 };
780
781 // static data member must be defined in order to take it's address (i.e. in std::make_tuple)
782 template <class ctype, int dimension, class Scalar, int O>
784
785 //---------------------------------------------------------------------
786
787 template <class ctype, int dimension, class Scalar, int Ord>
788 class LagrangeCubeShapeFunctionSet: public ShapeFunctionSet<ctype,dimension,Scalar>
789 {
790 public:
793
795
797 Matrix& IA) const
798 {
799 IA = A;
800 // For Lagrange shape functions, the interpolation at their nodes is just the identity. Copy!
801 }
802
803
804 virtual value_type const& operator[](int i) const{ return sf[i]; }
805 virtual Dune::GeometryType type() const { return Dune::GeometryType(Dune::GeometryType::cube,dimension); }
806
807 private:
808 std::vector<value_type> sf;
809 };
810
811 //---------------------------------------------------------------------
812 //---------------------------------------------------------------------
813
820 template <class ctype, int dimension, class Scalar, bool restricted=false>
822 {
823 public:
824 // The polymorphic container stores shape function sets or derived classes,
825 // and returns references to them.
827
828 private:
829 using Key = std::pair<Dune::GeometryType,int>;
830 using Value = std::unique_ptr<value_type>;
831 typedef std::map<Key,Value> Container;
832
833 using ActualSimplexSFS = typename SimplexLagrangeDetail::ChooseShapeFunctionSet<ctype,dimension,Scalar,restricted>::type;
834
835 public:
836
838
839
848 virtual value_type const& operator()(Dune::GeometryType type, int order) const;
849
850 private:
851 // A map storing Lagrange shape function sets associated with
852 // (geometry type, order). Due to runtime polymorphism,
853 // pointers are stored in the map. This class owns the shape
854 // function sets pointed to, and has to delete them in the
855 // destructor.
856 mutable Container container;
857 mutable std::mutex mut;
858
859 value_type const& createShapeFunctionSet(Dune::GeometryType simplex, int order) const;
860 };
861
862 // ----------------------------------------------------------------------------------------------
863
870 template <class ctype, int dimension, class Scalar=double, bool restricted=false>
872 lagrangeShapeFunctionSet(Dune::GeometryType type, int order)
873 {
874 // Initialization should be thread-safe (probably C++11 standard, 6.7/4).
876 return container(type,order);
877 }
878} // end of namespace Kaskade
879
880
881#endif
A LAPACK-compatible dense matrix class with shape specified at runtime.
Lagrange shape functions on an equidistant grid over the simplex. These are polynomial basis function...
Real value(int i, Vector const &xi) const
Real derivative(int i, int dir, Vector const &xi) const
EquidistantLagrange(int order)
Constructor.
Vector nodalPosition(int i) const
The spatial location of the interpolation node associated with the i-th basis function.
Real derivative2(int i, int dir1, int dir2, Vector const &xi) const
int order() const
The polynomial ansatz order of this Lagrange basis.
int size() const
The number of Lagrange polynomials.
std::vector< std::array< int, dim+1 > > ls
LagrangeBase(int order)
Constructor.
std::array< int, dim+1 > index(int i) const
Scalar Lagrange shape functions on the unit cube.
int entity() const
Returns the subentity number of the smallest codimension subentity on which the associated node is lo...
int localindex(int) const
Returns the local index of the shape function.
virtual Dune::FieldVector< Scalar, 1 > evaluateFunction(Dune::FieldVector< ctype, dim > const &x) const
Evaluates the shape function (all components at once).
LagrangeCubeShapeFunction(LagrangeCubeShapeFunction const &other)
virtual std::tuple< int, int, int, int > location() const
Returns a tuple (nominalOrder,codim,entity,index) giving detailed information about the location of t...
virtual Dune::FieldMatrix< ResultType, 1, dim > evaluateDerivative(Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the derivative of the shape function (all components and all directions at once).
ResultType evaluateDerivative(int, int dir, Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the partial derivative of the shape function in coordinate direction dir.
int entityIndex(Cell const &) const
Returns the local index on the subentity.
virtual Tensor< ResultType, 1, dim, dim > evaluate2ndDerivative(Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the second derivative of the shape function (all components and all directions at once).
int codim() const
Returns the codimension of the subentity on which the associated node is located.
ResultType evaluateFunction(int, Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the shape function at point x.
LagrangeCubeShapeFunction(Dune::FieldVector< int, dimension > const &xi_)
Creates a shape function associated to the node with indices xi_.
Dune::FieldVector< CoordType, dim > position() const
Returns the element-local position of the node associated to the shape function.
virtual void interpolate(typename ShapeFunctionSet< ctype, dimension, Scalar >::SfValueArray const &A, Matrix &IA) const
virtual value_type const & operator[](int i) const
Random access to a shape function.
LagrangeCubeShapeFunction< ctype, dimension, Scalar, Ord > value_type
virtual Dune::GeometryType type() const
ShapeFunctionSet< ctype, dimension, Scalar >::Matrix Matrix
ShapeFunctionSet< ctype, dimension, Scalar > value_type
virtual value_type const & operator()(Dune::GeometryType type, int order) const
Obtain a reference to a (persistent) shape function set of given order on cells of the given geometry...
Scalar Lagrange shape functions on the unit simplex.
virtual std::tuple< int, int, int, int > location() const
Returns a tuple (nominalOrder,codim,entity,index) giving detailed information about the location of t...
virtual Dune::FieldVector< Scalar, 1 > evaluateFunction(Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the shape function at point x.
virtual Dune::FieldMatrix< Scalar, 1, dim > evaluateDerivative(Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the derivative of the shape function.
virtual Tensor< Scalar, 1, dim, dim > evaluate2ndDerivative(Dune::FieldVector< CoordType, dim > const &x) const
Evaluates the second derivative of the shape function.
LagrangeSimplexShapeFunction(int local, std::shared_ptr< Basis const > basis_)
Creates a shape function associated to the node with tuple index xi_. The entries in xi_ have to be n...
LagrangeSimplexShapeFunction(LagrangeSimplexShapeFunction const &other)=default
Copy constructor.
A container of Lagrange shape functions of order Ord on the unit simplex of grid dimension....
LagrangeSimplexShapeFunction< ctype, dimension, Basis, Scalar > value_type
virtual ShapeFunction< ctype, dimension, Scalar > const & operator[](int i) const
Random access to a shape function.
virtual void interpolate(typename ShapeFunctionSet< ctype, dimension, Scalar >::SfValueArray const &A, Matrix &IA) const
std::vector< std::unique_ptr< ShapeFunction< ctype, dimension, Scalar > > > sf
LagrangeSimplexShapeFunctionSet(LagrangeSimplexShapeFunctionSet const &other)
ShapeFunctionSet< ctype, dimension, Scalar >::Matrix Matrix
Real value(int i, Vector const &x) const
Vector nodalPosition(int i) const
Real derivative(int i, int dir, Vector const &xi) const
Real derivative2(int i, int dir1, int dir2, Vector const &xi) const
Base class for sets of shape function containers.
A set of shape functions.
int order() const
Maximal polynomial order of shape functions.
int count(Cell const &cell, int codim)
Computes the number of subentities of codimension c of a given entity.
Definition: fixdune.hh:716
typename GridView::template Codim< 0 >::Entity Cell
The type of cells (entities of codimension 0) in the grid view.
Definition: gridBasics.hh:35
constexpr int binomial(int n, int k)
Computes the binomial coefficient .
LagrangeShapeFunctionSetContainer< ctype, dimension, Scalar, restricted >::value_type const & lagrangeShapeFunctionSet(Dune::GeometryType type, int order)
Returns a Lagrange shape function set for given reference element type and given polynomial order....