DUNE PDELab (git)

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/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
18namespace Dune {
19namespace 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
32template<typename GV, int k, typename R=double>
33class LagrangeNode;
34
35template<typename GV, int k, typename R=double>
36class LagrangePreBasis;
37
38
39
54template<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
61public:
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
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))
151 }
152 case 3:
153 {
154 return dofsPerCube(0) * ((size_type)gridView_.size(dim))
155 + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
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
299protected:
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
368template<typename GV, int k, typename R>
369class 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
399public:
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
445protected:
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
462namespace BasisFactory {
463
472template<std::size_t k, typename R=double>
474{
475 return [](const auto& gridView) {
476 return LagrangePreBasis<std::decay_t<decltype(gridView)>, k, R>(gridView);
477 };
478}
479
487template<typename R=double>
488auto 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
522template<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
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
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: lagrangebasis.hh:118
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
Grid view abstract base class.
Definition: gridview.hh:66
Describe position of one degree of freedom.
Definition: localkey.hh:24
constexpr unsigned int index() const noexcept
Return offset within subentity.
Definition: localkey.hh:70
constexpr unsigned int codim() const noexcept
Return codim of associated entity.
Definition: localkey.hh:63
constexpr unsigned int subEntity() const noexcept
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()
Create a pre-basis factory that can create a Lagrange pre-basis.
Definition: lagrangebasis.hh:473
constexpr GeometryType prism
GeometryType representing a 3D prism.
Definition: type.hh:528
constexpr GeometryType triangle
GeometryType representing a triangle.
Definition: type.hh:504
constexpr GeometryType quadrilateral
GeometryType representing a quadrilateral (a square).
Definition: type.hh:510
constexpr GeometryType hexahedron
GeometryType representing a hexahedron.
Definition: type.hh:534
constexpr GeometryType pyramid
GeometryType representing a 3D pyramid.
Definition: type.hh:522
constexpr GeometryType tetrahedron
GeometryType representing a tetrahedron.
Definition: type.hh:516
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
Convenience header that includes all implementations of Lagrange finite elements.
Dune namespace.
Definition: alignedallocator.hh:13
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
constexpr Base power(Base m, Exponent p)
Power method for integer exponents.
Definition: math.hh:75
LocalFiniteElementVariantCache< Impl::ImplementedLagrangeFiniteElements< D, R, dim, order > > LagrangeLocalFiniteElementCache
A cache that stores all available Pk/Qk like local finite elements for the given dimension and order.
Definition: lagrangelfecache.hh:118
constexpr auto get(std::integer_sequence< T, II... >, std::integral_constant< std::size_t, pos >={})
Return the entry at position pos of the given sequence.
Definition: integersequence.hh:22
STL namespace.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)