Loading [MathJax]/extensions/tex2jax.js

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