DUNE-FUNCTIONS (unstable)

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>
7 #include <dune/common/exceptions.hh>
8 
9 #include <dune/localfunctions/lagrange.hh>
10 #include <dune/localfunctions/lagrange/equidistantpoints.hh>
11 #include <dune/localfunctions/lagrange/lagrangelfecache.hh>
12 
13 #include <dune/functions/functionspacebases/nodes.hh>
14 #include <dune/functions/functionspacebases/defaultglobalbasis.hh>
15 #include <dune/functions/functionspacebases/leafprebasismixin.hh>
16 
17 
18 namespace Dune {
19 namespace Functions {
20 
21 // *****************************************************************************
22 // This is the reusable part of the LagrangeBasis. It contains
23 //
24 // LagrangePreBasis
25 // LagrangeNode
26 //
27 // The pre-basis allows to create the others and is the owner of possible shared
28 // state. These components do _not_ depend on the global basis and local view
29 // and can be used without a global basis.
30 // *****************************************************************************
31 
32 template<typename GV, int k, typename R=double>
33 class LagrangeNode;
34 
35 template<typename GV, int k, typename R=double>
36 class LagrangePreBasis;
37 
38 
39 
54 template<typename GV, int k, typename R>
56  public LeafPreBasisMixin< LagrangePreBasis<GV,k,R> >
57 {
58  static const int dim = GV::dimension;
59  static const bool useDynamicOrder = (k<0);
60 
61 public:
62 
64  using GridView = GV;
65 
67  using size_type = std::size_t;
68 
70  using Node = LagrangeNode<GV, k, R>;
71 
74  : LagrangePreBasis(gv, std::numeric_limits<unsigned int>::max())
75  {}
76 
78  LagrangePreBasis(const GridView& gv, unsigned int order) :
79  gridView_(gv), order_(order)
80  {
81  if (!useDynamicOrder && order!=std::numeric_limits<unsigned int>::max())
82  DUNE_THROW(RangeError, "Template argument k has to be -1 when supplying a run-time order!");
83 
84  for (int i=0; i<=dim; i++)
85  {
86  dofsPerCube_[i] = computeDofsPerCube(i);
87  dofsPerSimplex_[i] = computeDofsPerSimplex(i);
88  }
89  dofsPerPrism_ = computeDofsPerPrism();
90  dofsPerPyramid_ = computeDofsPerPyramid();
91  }
92 
95  {
96  vertexOffset_ = 0;
97  edgeOffset_ = vertexOffset_ + dofsPerCube(0) * ((size_type)gridView_.size(dim));
98 
99  if (dim>=2)
100  {
101  triangleOffset_ = edgeOffset_ + dofsPerCube(1) * ((size_type) gridView_.size(dim-1));
102 
103  quadrilateralOffset_ = triangleOffset_ + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle));
104  }
105 
106  if (dim==3) {
107  tetrahedronOffset_ = quadrilateralOffset_ + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral));
108 
109  prismOffset_ = tetrahedronOffset_ + dofsPerSimplex(3) * ((size_type)gridView_.size(Dune::GeometryTypes::tetrahedron));
110 
111  hexahedronOffset_ = prismOffset_ + dofsPerPrism() * ((size_type)gridView_.size(Dune::GeometryTypes::prism));
112 
113  pyramidOffset_ = hexahedronOffset_ + dofsPerCube(3) * ((size_type)gridView_.size(Dune::GeometryTypes::hexahedron));
114  }
115  }
116 
118  const GridView& gridView() const
119  {
120  return gridView_;
121  }
122 
124  void update (const GridView& gv)
125  {
126  gridView_ = gv;
127  }
128 
132  Node makeNode() const
133  {
134  return Node{order_};
135  }
136 
139  {
140  switch (dim)
141  {
142  case 1:
143  return dofsPerCube(0) * ((size_type)gridView_.size(dim))
144  + dofsPerCube(1) * ((size_type)gridView_.size(dim-1));
145  case 2:
146  {
147  return dofsPerCube(0) * ((size_type)gridView_.size(dim))
148  + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
149  + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle))
150  + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral));
151  }
152  case 3:
153  {
154  return dofsPerCube(0) * ((size_type)gridView_.size(dim))
155  + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
156  + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle))
157  + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral))
158  + dofsPerSimplex(3) * ((size_type)gridView_.size(Dune::GeometryTypes::tetrahedron))
159  + dofsPerPyramid() * ((size_type)gridView_.size(Dune::GeometryTypes::pyramid))
160  + dofsPerPrism() * ((size_type)gridView_.size(Dune::GeometryTypes::prism))
161  + dofsPerCube(3) * ((size_type)gridView_.size(Dune::GeometryTypes::hexahedron));
162  }
163  }
164  DUNE_THROW(Dune::NotImplemented, "No size method for " << dim << "d grids available yet!");
165  }
166 
169  {
170  // That cast to unsigned int is necessary because GV::dimension is an enum,
171  // which is not recognized by the power method as an integer type...
172  return power(order()+1, (unsigned int)GV::dimension);
173  }
174 
175  template<typename It>
176  It indices(const Node& node, It it) const
177  {
178  for (size_type i = 0, end = node.finiteElement().size() ; i < end ; ++it, ++i)
179  {
180  Dune::LocalKey localKey = node.finiteElement().localCoefficients().localKey(i);
181  const auto& gridIndexSet = gridView().indexSet();
182  const auto& element = node.element();
183 
184  // The dimension of the entity that the current dof is related to
185  auto dofDim = dim - localKey.codim();
186 
187  // Test for a vertex dof
188  // The test for k==1 is redundant, but having it here allows the compiler to conclude
189  // at compile-time that the dofDim==0 case is the only one that will ever happen.
190  // This leads to measurable speed-up: see
191  // https://gitlab.dune-project.org/staging/dune-functions/issues/30
192  if (k==1 || dofDim==0) {
193  *it = {{ (size_type)(gridIndexSet.subIndex(element,localKey.subEntity(),dim)) }};
194  continue;
195  }
196 
197  if (dofDim==1)
198  { // edge dof
199  if (dim==1) // element dof -- any local numbering is fine
200  {
201  *it = {{ edgeOffset_
202  + dofsPerCube(1) * ((size_type)gridIndexSet.subIndex(element,0,0))
203  + localKey.index() }};
204  continue;
205  }
206  else
207  {
208  const auto refElement
209  = Dune::referenceElement<double,dim>(element.type());
210 
211  // We have to reverse the numbering if the local element edge is
212  // not aligned with the global edge.
213  auto v0 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),0,dim),dim);
214  auto v1 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),1,dim),dim);
215  bool flip = (v0 > v1);
216  *it = {{ (flip)
217  ? edgeOffset_
218  + dofsPerCube(1)*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim()))
219  + (dofsPerCube(1)-1)-localKey.index()
220  : edgeOffset_
221  + dofsPerCube(1)*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim()))
222  + localKey.index() }};
223  continue;
224  }
225  }
226 
227  if (dofDim==2)
228  {
229  if (dim==2) // element dof -- any local numbering is fine
230  {
231  if (element.type().isTriangle())
232  {
233  *it = {{ triangleOffset_ + dofsPerSimplex(2)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
234  continue;
235  }
236  else if (element.type().isQuadrilateral())
237  {
238  *it = {{ quadrilateralOffset_ + dofsPerCube(2)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
239  continue;
240  }
241  else
242  DUNE_THROW(Dune::NotImplemented, "2d elements have to be triangles or quadrilaterals");
243  } else
244  {
245  const auto refElement
246  = Dune::referenceElement<double,dim>(element.type());
247 
248  if (order()>3)
249  DUNE_THROW(Dune::NotImplemented, "LagrangeBasis for 3D grids is only implemented if k<=3");
250 
251  if (order()==3 and !refElement.type(localKey.subEntity(), localKey.codim()).isTriangle())
252  DUNE_THROW(Dune::NotImplemented, "LagrangeBasis for 3D grids with k==3 is only implemented if the grid is a simplex grid");
253 
254  *it = {{ triangleOffset_ + ((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim())) }};
255  continue;
256  }
257  }
258 
259  if (dofDim==3)
260  {
261  if (dim==3) // element dof -- any local numbering is fine
262  {
263  if (element.type().isTetrahedron())
264  {
265  *it = {{ tetrahedronOffset_ + dofsPerSimplex(3)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
266  continue;
267  }
268  else if (element.type().isHexahedron())
269  {
270  *it = {{ hexahedronOffset_ + dofsPerCube(3)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
271  continue;
272  }
273  else if (element.type().isPrism())
274  {
275  *it = {{ prismOffset_ + dofsPerPrism()*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
276  continue;
277  }
278  else if (element.type().isPyramid())
279  {
280  *it = {{ pyramidOffset_ + dofsPerPyramid()*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
281  continue;
282  }
283  else
284  DUNE_THROW(Dune::NotImplemented, "3d elements have to be tetrahedra, hexahedra, prisms, or pyramids");
285  } else
286  DUNE_THROW(Dune::NotImplemented, "Grids of dimension larger than 3 are no supported");
287  }
288  DUNE_THROW(Dune::NotImplemented, "Grid contains elements not supported for the LagrangeBasis");
289  }
290  return it;
291  }
292 
294  unsigned int order() const
295  {
296  return (useDynamicOrder) ? order_ : k;
297  }
298 
299 protected:
300  GridView gridView_;
301 
302  // Run-time order, only valid if k<0
303  unsigned int order_;
304 
306  size_type dofsPerSimplex(std::size_t simplexDim) const
307  {
308  return useDynamicOrder ? dofsPerSimplex_[simplexDim] : computeDofsPerSimplex(simplexDim);
309  }
310 
312  size_type dofsPerCube(std::size_t cubeDim) const
313  {
314  return useDynamicOrder ? dofsPerCube_[cubeDim] : computeDofsPerCube(cubeDim);
315  }
316 
317  size_type dofsPerPrism() const
318  {
319  return useDynamicOrder ? dofsPerPrism_ : computeDofsPerPrism();
320  }
321 
322  size_type dofsPerPyramid() const
323  {
324  return useDynamicOrder ? dofsPerPyramid_ : computeDofsPerPyramid();
325  }
326 
328  size_type computeDofsPerSimplex(std::size_t simplexDim) const
329  {
330  return order() == 0 ? (dim == simplexDim ? 1 : 0) : Dune::binomial(std::size_t(order()-1),simplexDim);
331  }
332 
334  size_type computeDofsPerCube(std::size_t cubeDim) const
335  {
336  return order() == 0 ? (dim == cubeDim ? 1 : 0) : Dune::power(order()-1, cubeDim);
337  }
338 
339  size_type computeDofsPerPrism() const
340  {
341  return order() == 0 ? (dim == 3 ? 1 : 0) : (order()-1)*(order()-1)*(order()-2)/2;
342  }
343 
344  size_type computeDofsPerPyramid() const
345  {
346  return order() == 0 ? (dim == 3 ? 1 : 0) : (order()-2)*(order()-1)*(2*order()-3)/6;
347  }
348 
349  // When the order is given at run-time, the following numbers are pre-computed:
350  std::array<size_type,dim+1> dofsPerSimplex_;
351  std::array<size_type,dim+1> dofsPerCube_;
352  size_type dofsPerPrism_;
353  size_type dofsPerPyramid_;
354 
355  size_type vertexOffset_;
356  size_type edgeOffset_;
357  size_type triangleOffset_;
358  size_type quadrilateralOffset_;
359  size_type tetrahedronOffset_;
360  size_type pyramidOffset_;
361  size_type prismOffset_;
362  size_type hexahedronOffset_;
363 
364 };
365 
366 
367 
368 template<typename GV, int k, typename R>
369 class LagrangeNode :
370  public LeafBasisNode
371 {
372  // Stores LocalFiniteElement implementations with run-time order as a function of GeometryType
373  template<typename Domain, typename Range, int dim>
374  class LagrangeRunTimeLFECache
375  {
376  public:
377  using FiniteElementType = LagrangeLocalFiniteElement<EquidistantPointSet,dim,Domain,Range>;
378 
379  const FiniteElementType& get(GeometryType type)
380  {
381  auto i = data_.find(type);
382  if (i==data_.end())
383  i = data_.emplace(type,FiniteElementType(type,order_)).first;
384  return (*i).second;
385  }
386 
387  std::map<GeometryType, FiniteElementType> data_;
388  unsigned int order_;
389  };
390 
391  static constexpr int dim = GV::dimension;
392  static constexpr bool useDynamicOrder = (k<0);
393 
394  using FiniteElementCache = std::conditional_t<(useDynamicOrder),
395  LagrangeRunTimeLFECache<typename GV::ctype, R, dim>,
396  LagrangeLocalFiniteElementCache<typename GV::ctype, R, dim, std::max(k,0)>
397  >;
398 
399 public:
400 
401  using size_type = std::size_t;
402  using Element = typename GV::template Codim<0>::Entity;
403  using FiniteElement = typename FiniteElementCache::FiniteElementType;
404 
406  LagrangeNode() :
407  finiteElement_(nullptr),
408  element_(nullptr)
409  {}
410 
412  LagrangeNode(unsigned int order) :
413  order_(order),
414  finiteElement_(nullptr),
415  element_(nullptr)
416  {
417  // Only the cache for the run-time-order case (i.e., k<0), has the 'order_' member
418  if constexpr (useDynamicOrder)
419  cache_.order_ = order;
420  }
421 
423  const Element& element() const
424  {
425  return *element_;
426  }
427 
432  const FiniteElement& finiteElement() const
433  {
434  return *finiteElement_;
435  }
436 
438  void bind(const Element& e)
439  {
440  element_ = &e;
441  finiteElement_ = &(cache_.get(element_->type()));
442  this->setSize(finiteElement_->size());
443  }
444 
445 protected:
446 
447  unsigned int order() const
448  {
449  return (useDynamicOrder) ? order_ : k;
450  }
451 
452  // Run-time order, only valid if k<0
453  unsigned int order_;
454 
455  FiniteElementCache cache_;
456  const FiniteElement* finiteElement_;
457  const Element* element_;
458 };
459 
460 
461 
462 namespace BasisFactory {
463 
472 template<std::size_t k, typename R=double>
473 auto lagrange()
474 {
475  return [](const auto& gridView) {
476  return LagrangePreBasis<std::decay_t<decltype(gridView)>, k, R>(gridView);
477  };
478 }
479 
487 template<typename R=double>
488 auto lagrange(int order)
489 {
490  return [=](const auto& gridView) {
491  return LagrangePreBasis<std::decay_t<decltype(gridView)>, -1, R>(gridView, order);
492  };
493 }
494 
495 } // end namespace BasisFactory
496 
497 
498 
522 template<typename GV, int k=-1, typename R=double>
524 
525 
526 
527 
528 
529 } // end namespace Functions
530 } // end namespace Dune
531 
532 
533 #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:57
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:334
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:328
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: lagrangebasis.hh:118
LagrangeNode< GV, k, R > Node
Template mapping root tree path to type of created tree node.
Definition: lagrangebasis.hh:70
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:306
std::size_t size_type
Type used for indices and size information.
Definition: lagrangebasis.hh:67
void initializeIndices()
Initialize the global indices.
Definition: lagrangebasis.hh:94
LagrangePreBasis(const GridView &gv, unsigned int order)
Constructor for a given grid view object and run-time order.
Definition: lagrangebasis.hh:78
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: lagrangebasis.hh:138
LagrangePreBasis(const GridView &gv)
Constructor for a given grid view object with compile-time order.
Definition: lagrangebasis.hh:73
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: lagrangebasis.hh:124
GV GridView
The grid view that the FE basis is defined on.
Definition: lagrangebasis.hh:64
Node makeNode() const
Create tree node.
Definition: lagrangebasis.hh:132
unsigned int order() const
Polynomial order used in the local Lagrange finite-elements.
Definition: lagrangebasis.hh:294
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: lagrangebasis.hh:168
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:312
A generic MixIn class for PreBasis.
Definition: leafprebasismixin.hh:32
auto lagrange(int order)
Create a pre-basis factory that can create a Lagrange pre-basis with a run-time order.
Definition: lagrangebasis.hh:488
auto power(ChildPreBasisFactory &&childPreBasisFactory, std::size_t k, const IndexMergingStrategy &)
Create a pre-basis factory that can build a PowerPreBasis.
Definition: dynamicpowerbasis.hh:405
Definition: polynomial.hh:13
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)