Dune Core Modules (2.9.0)

lagrangebasis.hh
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
4 #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
5 
6 #include <type_traits>
8 
10 #include <dune/localfunctions/lagrange/equidistantpoints.hh>
11 #include <dune/localfunctions/lagrange/pqkfactory.hh>
12 
13 #include <dune/functions/functionspacebases/nodes.hh>
14 #include <dune/functions/functionspacebases/defaultglobalbasis.hh>
15 
16 
17 namespace Dune {
18 namespace Functions {
19 
20 // *****************************************************************************
21 // This is the reusable part of the LagrangeBasis. It contains
22 //
23 // LagrangePreBasis
24 // LagrangeNode
25 //
26 // The pre-basis allows to create the others and is the owner of possible shared
27 // state. These components do _not_ depend on the global basis and local view
28 // and can be used without a global basis.
29 // *****************************************************************************
30 
31 template<typename GV, int k, typename R=double>
32 class LagrangeNode;
33 
34 template<typename GV, int k, typename R=double>
35 class LagrangePreBasis;
36 
37 
38 
53 template<typename GV, int k, typename R>
55 {
56  static const int dim = GV::dimension;
57  static const bool useDynamicOrder = (k<0);
58 
59 public:
60 
62  using GridView = GV;
63 
65  using size_type = std::size_t;
66 
68  using Node = LagrangeNode<GV, k, R>;
69 
70  static constexpr size_type maxMultiIndexSize = 1;
71  static constexpr size_type minMultiIndexSize = 1;
72  static constexpr size_type multiIndexBufferSize = 1;
73 
76  : LagrangePreBasis(gv, std::numeric_limits<unsigned int>::max())
77  {}
78 
80  LagrangePreBasis(const GridView& gv, unsigned int order) :
81  gridView_(gv), order_(order)
82  {
83  if (!useDynamicOrder && order!=std::numeric_limits<unsigned int>::max())
84  DUNE_THROW(RangeError, "Template argument k has to be -1 when supplying a run-time order!");
85 
86  for (int i=0; i<=dim; i++)
87  {
88  dofsPerCube_[i] = computeDofsPerCube(i);
89  dofsPerSimplex_[i] = computeDofsPerSimplex(i);
90  }
91  dofsPerPrism_ = computeDofsPerPrism();
92  dofsPerPyramid_ = computeDofsPerPyramid();
93  }
94 
97  {
98  vertexOffset_ = 0;
99  edgeOffset_ = vertexOffset_ + dofsPerCube(0) * ((size_type)gridView_.size(dim));
100 
101  if (dim>=2)
102  {
103  triangleOffset_ = edgeOffset_ + dofsPerCube(1) * ((size_type) gridView_.size(dim-1));
104 
105  quadrilateralOffset_ = triangleOffset_ + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle));
106  }
107 
108  if (dim==3) {
109  tetrahedronOffset_ = quadrilateralOffset_ + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral));
110 
111  prismOffset_ = tetrahedronOffset_ + dofsPerSimplex(3) * ((size_type)gridView_.size(Dune::GeometryTypes::tetrahedron));
112 
113  hexahedronOffset_ = prismOffset_ + dofsPerPrism() * ((size_type)gridView_.size(Dune::GeometryTypes::prism));
114 
115  pyramidOffset_ = hexahedronOffset_ + dofsPerCube(3) * ((size_type)gridView_.size(Dune::GeometryTypes::hexahedron));
116  }
117  }
118 
120  const GridView& gridView() const
121  {
122  return gridView_;
123  }
124 
126  void update (const GridView& gv)
127  {
128  gridView_ = gv;
129  }
130 
134  Node makeNode() const
135  {
136  return Node{order_};
137  }
138 
140  size_type size() const
141  {
142  switch (dim)
143  {
144  case 1:
145  return dofsPerCube(0) * ((size_type)gridView_.size(dim))
146  + dofsPerCube(1) * ((size_type)gridView_.size(dim-1));
147  case 2:
148  {
149  return dofsPerCube(0) * ((size_type)gridView_.size(dim))
150  + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
151  + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle))
152  + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral));
153  }
154  case 3:
155  {
156  return dofsPerCube(0) * ((size_type)gridView_.size(dim))
157  + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
158  + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle))
161  + dofsPerPyramid() * ((size_type)gridView_.size(Dune::GeometryTypes::pyramid))
162  + dofsPerPrism() * ((size_type)gridView_.size(Dune::GeometryTypes::prism))
163  + dofsPerCube(3) * ((size_type)gridView_.size(Dune::GeometryTypes::hexahedron));
164  }
165  }
166  DUNE_THROW(Dune::NotImplemented, "No size method for " << dim << "d grids available yet!");
167  }
168 
170  template<class SizePrefix>
171  size_type size(const SizePrefix& prefix) const
172  {
173  assert(prefix.size() == 0 || prefix.size() == 1);
174  return (prefix.size() == 0) ? size() : 0;
175  }
176 
179  {
180  return size();
181  }
182 
185  {
186  // That cast to unsigned int is necessary because GV::dimension is an enum,
187  // which is not recognized by the power method as an integer type...
188  return power(order()+1, (unsigned int)GV::dimension);
189  }
190 
191  template<typename It>
192  It indices(const Node& node, It it) const
193  {
194  for (size_type i = 0, end = node.finiteElement().size() ; i < end ; ++it, ++i)
195  {
196  Dune::LocalKey localKey = node.finiteElement().localCoefficients().localKey(i);
197  const auto& gridIndexSet = gridView().indexSet();
198  const auto& element = node.element();
199 
200  // The dimension of the entity that the current dof is related to
201  auto dofDim = dim - localKey.codim();
202 
203  // Test for a vertex dof
204  // The test for k==1 is redundant, but having it here allows the compiler to conclude
205  // at compile-time that the dofDim==0 case is the only one that will ever happen.
206  // This leads to measurable speed-up: see
207  // https://gitlab.dune-project.org/staging/dune-functions/issues/30
208  if (k==1 || dofDim==0) {
209  *it = {{ (size_type)(gridIndexSet.subIndex(element,localKey.subEntity(),dim)) }};
210  continue;
211  }
212 
213  if (dofDim==1)
214  { // edge dof
215  if (dim==1) // element dof -- any local numbering is fine
216  {
217  *it = {{ edgeOffset_
218  + dofsPerCube(1) * ((size_type)gridIndexSet.subIndex(element,0,0))
219  + localKey.index() }};
220  continue;
221  }
222  else
223  {
224  const auto refElement
225  = Dune::referenceElement<double,dim>(element.type());
226 
227  // We have to reverse the numbering if the local element edge is
228  // not aligned with the global edge.
229  auto v0 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),0,dim),dim);
230  auto v1 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),1,dim),dim);
231  bool flip = (v0 > v1);
232  *it = {{ (flip)
233  ? edgeOffset_
234  + dofsPerCube(1)*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim()))
235  + (dofsPerCube(1)-1)-localKey.index()
236  : edgeOffset_
237  + dofsPerCube(1)*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim()))
238  + localKey.index() }};
239  continue;
240  }
241  }
242 
243  if (dofDim==2)
244  {
245  if (dim==2) // element dof -- any local numbering is fine
246  {
247  if (element.type().isTriangle())
248  {
249  *it = {{ triangleOffset_ + dofsPerSimplex(2)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
250  continue;
251  }
252  else if (element.type().isQuadrilateral())
253  {
254  *it = {{ quadrilateralOffset_ + dofsPerCube(2)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
255  continue;
256  }
257  else
258  DUNE_THROW(Dune::NotImplemented, "2d elements have to be triangles or quadrilaterals");
259  } else
260  {
261  const auto refElement
262  = Dune::referenceElement<double,dim>(element.type());
263 
264  if (order()>3)
265  DUNE_THROW(Dune::NotImplemented, "LagrangeBasis for 3D grids is only implemented if k<=3");
266 
267  if (order()==3 and !refElement.type(localKey.subEntity(), localKey.codim()).isTriangle())
268  DUNE_THROW(Dune::NotImplemented, "LagrangeBasis for 3D grids with k==3 is only implemented if the grid is a simplex grid");
269 
270  *it = {{ triangleOffset_ + ((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim())) }};
271  continue;
272  }
273  }
274 
275  if (dofDim==3)
276  {
277  if (dim==3) // element dof -- any local numbering is fine
278  {
279  if (element.type().isTetrahedron())
280  {
281  *it = {{ tetrahedronOffset_ + dofsPerSimplex(3)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
282  continue;
283  }
284  else if (element.type().isHexahedron())
285  {
286  *it = {{ hexahedronOffset_ + dofsPerCube(3)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
287  continue;
288  }
289  else if (element.type().isPrism())
290  {
291  *it = {{ prismOffset_ + dofsPerPrism()*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
292  continue;
293  }
294  else if (element.type().isPyramid())
295  {
296  *it = {{ pyramidOffset_ + dofsPerPyramid()*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
297  continue;
298  }
299  else
300  DUNE_THROW(Dune::NotImplemented, "3d elements have to be tetrahedra, hexahedra, prisms, or pyramids");
301  } else
302  DUNE_THROW(Dune::NotImplemented, "Grids of dimension larger than 3 are no supported");
303  }
304  DUNE_THROW(Dune::NotImplemented, "Grid contains elements not supported for the LagrangeBasis");
305  }
306  return it;
307  }
308 
310  unsigned int order() const
311  {
312  return (useDynamicOrder) ? order_ : k;
313  }
314 
315 protected:
316  GridView gridView_;
317 
318  // Run-time order, only valid if k<0
319  const unsigned int order_;
320 
322  size_type dofsPerSimplex(std::size_t simplexDim) const
323  {
324  return useDynamicOrder ? dofsPerSimplex_[simplexDim] : computeDofsPerSimplex(simplexDim);
325  }
326 
328  size_type dofsPerCube(std::size_t cubeDim) const
329  {
330  return useDynamicOrder ? dofsPerCube_[cubeDim] : computeDofsPerCube(cubeDim);
331  }
332 
333  size_type dofsPerPrism() const
334  {
335  return useDynamicOrder ? dofsPerPrism_ : computeDofsPerPrism();
336  }
337 
338  size_type dofsPerPyramid() const
339  {
340  return useDynamicOrder ? dofsPerPyramid_ : computeDofsPerPyramid();
341  }
342 
344  size_type computeDofsPerSimplex(std::size_t simplexDim) const
345  {
346  return order() == 0 ? (dim == simplexDim ? 1 : 0) : Dune::binomial(std::size_t(order()-1),simplexDim);
347  }
348 
350  size_type computeDofsPerCube(std::size_t cubeDim) const
351  {
352  return order() == 0 ? (dim == cubeDim ? 1 : 0) : Dune::power(order()-1, cubeDim);
353  }
354 
355  size_type computeDofsPerPrism() const
356  {
357  return order() == 0 ? (dim == 3 ? 1 : 0) : (order()-1)*(order()-1)*(order()-2)/2;
358  }
359 
360  size_type computeDofsPerPyramid() const
361  {
362  return order() == 0 ? (dim == 3 ? 1 : 0) : (order()-2)*(order()-1)*(2*order()-3)/6;
363  }
364 
365  // When the order is given at run-time, the following numbers are pre-computed:
366  std::array<size_type,dim+1> dofsPerSimplex_;
367  std::array<size_type,dim+1> dofsPerCube_;
368  size_type dofsPerPrism_;
369  size_type dofsPerPyramid_;
370 
371  size_type vertexOffset_;
372  size_type edgeOffset_;
373  size_type triangleOffset_;
374  size_type quadrilateralOffset_;
375  size_type tetrahedronOffset_;
376  size_type pyramidOffset_;
377  size_type prismOffset_;
378  size_type hexahedronOffset_;
379 
380 };
381 
382 
383 
384 template<typename GV, int k, typename R>
385 class LagrangeNode :
386  public LeafBasisNode
387 {
388  // Stores LocalFiniteElement implementations with run-time order as a function of GeometryType
389  template<typename Domain, typename Range, int dim>
390  class LagrangeRunTimeLFECache
391  {
392  public:
393  using FiniteElementType = LagrangeLocalFiniteElement<EquidistantPointSet,dim,Domain,Range>;
394 
395  const FiniteElementType& get(GeometryType type)
396  {
397  auto i = data_.find(type);
398  if (i==data_.end())
399  i = data_.emplace(type,FiniteElementType(type,order_)).first;
400  return (*i).second;
401  }
402 
403  std::map<GeometryType, FiniteElementType> data_;
404  unsigned int order_;
405  };
406 
407  static constexpr int dim = GV::dimension;
408  static constexpr bool useDynamicOrder = (k<0);
409 
410  using FiniteElementCache = typename std::conditional<(useDynamicOrder),
411  LagrangeRunTimeLFECache<typename GV::ctype, R, dim>,
412  PQkLocalFiniteElementCache<typename GV::ctype, R, dim, k>
413  >::type;
414 
415 public:
416 
417  using size_type = std::size_t;
418  using Element = typename GV::template Codim<0>::Entity;
419  using FiniteElement = typename FiniteElementCache::FiniteElementType;
420 
422  LagrangeNode() :
423  finiteElement_(nullptr),
424  element_(nullptr)
425  {}
426 
428  LagrangeNode(unsigned int order) :
429  order_(order),
430  finiteElement_(nullptr),
431  element_(nullptr)
432  {
433  // Only the cache for the run-time-order case (i.e., k<0), has the 'order_' member
434  if constexpr (useDynamicOrder)
435  cache_.order_ = order;
436  }
437 
439  const Element& element() const
440  {
441  return *element_;
442  }
443 
448  const FiniteElement& finiteElement() const
449  {
450  return *finiteElement_;
451  }
452 
454  void bind(const Element& e)
455  {
456  element_ = &e;
457  finiteElement_ = &(cache_.get(element_->type()));
458  this->setSize(finiteElement_->size());
459  }
460 
461 protected:
462 
463  unsigned int order() const
464  {
465  return (useDynamicOrder) ? order_ : k;
466  }
467 
468  // Run-time order, only valid if k<0
469  unsigned int order_;
470 
471  FiniteElementCache cache_;
472  const FiniteElement* finiteElement_;
473  const Element* element_;
474 };
475 
476 
477 
478 namespace BasisFactory {
479 
488 template<std::size_t k, typename R=double>
489 auto lagrange()
490 {
491  return [](const auto& gridView) {
492  return LagrangePreBasis<std::decay_t<decltype(gridView)>, k, R>(gridView);
493  };
494 }
495 
503 template<typename R=double>
504 auto lagrange(int order)
505 {
506  return [=](const auto& gridView) {
507  return LagrangePreBasis<std::decay_t<decltype(gridView)>, -1, R>(gridView, order);
508  };
509 }
510 
511 } // end namespace BasisFactory
512 
513 
514 
538 template<typename GV, int k=-1, typename R=double>
540 
541 
542 
543 
544 
545 } // end namespace Functions
546 } // end namespace Dune
547 
548 
549 #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
Global basis for given pre-basis.
Definition: defaultglobalbasis.hh:46
A pre-basis for a PQ-lagrange bases with given order.
Definition: lagrangebasis.hh:55
size_type computeDofsPerCube(std::size_t cubeDim) const
Number of degrees of freedom assigned to a cube (without the ones assigned to its faces!...
Definition: lagrangebasis.hh:350
size_type computeDofsPerSimplex(std::size_t simplexDim) const
Number of degrees of freedom assigned to a simplex (without the ones assigned to its faces!...
Definition: lagrangebasis.hh:344
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: lagrangebasis.hh:120
LagrangeNode< GV, k, R > Node
Template mapping root tree path to type of created tree node.
Definition: lagrangebasis.hh:68
size_type dofsPerSimplex(std::size_t simplexDim) const
Number of degrees of freedom assigned to a simplex (without the ones assigned to its faces!...
Definition: lagrangebasis.hh:322
std::size_t size_type
Type used for indices and size information.
Definition: lagrangebasis.hh:65
void initializeIndices()
Initialize the global indices.
Definition: lagrangebasis.hh:96
LagrangePreBasis(const GridView &gv, unsigned int order)
Constructor for a given grid view object and run-time order.
Definition: lagrangebasis.hh:80
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: lagrangebasis.hh:178
LagrangePreBasis(const GridView &gv)
Constructor for a given grid view object with compile-time order.
Definition: lagrangebasis.hh:75
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: lagrangebasis.hh:126
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: lagrangebasis.hh:171
GV GridView
The grid view that the FE basis is defined on.
Definition: lagrangebasis.hh:62
Node makeNode() const
Create tree node.
Definition: lagrangebasis.hh:134
unsigned int order() const
Polynomial order used in the local Lagrange finite-elements.
Definition: lagrangebasis.hh:310
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: lagrangebasis.hh:184
size_type size() const
Same as size(prefix) with empty prefix.
Definition: lagrangebasis.hh:140
size_type dofsPerCube(std::size_t cubeDim) const
Number of degrees of freedom assigned to a cube (without the ones assigned to its faces!...
Definition: lagrangebasis.hh:328
Grid view abstract base class.
Definition: gridview.hh:66
Describe position of one degree of freedom.
Definition: localkey.hh:23
unsigned int index() const
Return offset within subentity.
Definition: localkey.hh:68
unsigned int codim() const
Return codim of associated entity.
Definition: localkey.hh:62
unsigned int subEntity() const
Return number of associated subentity.
Definition: localkey.hh:56
Default exception for dummy implementations.
Definition: exceptions.hh:263
Default exception class for range errors.
Definition: exceptions.hh:254
A few common exception classes.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
auto lagrange(int order)
Create a pre-basis factory that can create a Lagrange pre-basis with a run-time order.
Definition: lagrangebasis.hh:504
constexpr GeometryType prism
GeometryType representing a 3D prism.
Definition: type.hh:542
constexpr GeometryType triangle
GeometryType representing a triangle.
Definition: type.hh:518
constexpr GeometryType quadrilateral
GeometryType representing a quadrilateral (a square).
Definition: type.hh:524
constexpr GeometryType hexahedron
GeometryType representing a hexahedron.
Definition: type.hh:548
constexpr GeometryType pyramid
GeometryType representing a 3D pyramid.
Definition: type.hh:536
constexpr GeometryType tetrahedron
GeometryType representing a tetrahedron.
Definition: type.hh:530
auto max(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::max()
Definition: defaults.hh:81
Convenience header that includes all implementations of Lagrange finite elements.
Dune namespace.
Definition: alignedallocator.hh:13
constexpr Base power(Base m, Exponent p)
Power method for integer exponents.
Definition: math.hh:75
constexpr static T binomial(const T &n, const T &k) noexcept
calculate the binomial coefficient n over k as a constexpr
Definition: math.hh:131
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 4, 22:30, 2024)