DUNE-FUNCTIONS (2.7)

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 <dune/common/exceptions.hh>
7
8#include <dune/localfunctions/lagrange.hh>
9#include <dune/localfunctions/lagrange/equidistantpoints.hh>
10#include <dune/localfunctions/lagrange/pqkfactory.hh>
11
12#include <dune/functions/functionspacebases/nodes.hh>
13#include <dune/functions/functionspacebases/flatmultiindex.hh>
14#include <dune/functions/functionspacebases/defaultglobalbasis.hh>
15
16
17namespace Dune {
18namespace Functions {
19
20// *****************************************************************************
21// This is the reusable part of the LagrangeBasis. It contains
22//
23// LagrangePreBasis
24// LagrangeNodeIndexSet
25// LagrangeNode
26//
27// The pre-basis allows to create the others and is the owner of possible shared
28// state. These three components do _not_ depend on the global basis or index
29// set 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, class MI, typename R=double>
36class LagrangeNodeIndexSet;
37
38template<typename GV, int k, class MI, typename R=double>
39class LagrangePreBasis;
40
41
42
58template<typename GV, int k, class MI, typename R>
60{
61 static const int dim = GV::dimension;
62 static const bool useDynamicOrder = (k<0);
63
64public:
65
67 using GridView = GV;
68
70 using size_type = std::size_t;
71
72private:
73
74 template<typename, int, class, typename>
75 friend class LagrangeNodeIndexSet;
76
77public:
78
80 using Node = LagrangeNode<GV, k, R>;
81
83 using IndexSet = LagrangeNodeIndexSet<GV, k, MI, R>;
84
86 using MultiIndex = MI;
87
89 using SizePrefix = Dune::ReservedVector<size_type, 1>;
90
93 : LagrangePreBasis(gv, std::numeric_limits<unsigned int>::max())
94 {}
95
97 LagrangePreBasis(const GridView& gv, unsigned int order) :
98 gridView_(gv), order_(order)
99 {
100 if (!useDynamicOrder && order!=std::numeric_limits<unsigned int>::max())
101 DUNE_THROW(RangeError, "Template argument k has to be -1 when supplying a run-time order!");
102
103 for (int i=0; i<=dim; i++)
104 {
105 dofsPerCube_[i] = computeDofsPerCube(i);
106 dofsPerSimplex_[i] = computeDofsPerSimplex(i);
107 }
108 dofsPerPrism_ = computeDofsPerPrism();
109 dofsPerPyramid_ = computeDofsPerPyramid();
110 }
111
114 {
115 vertexOffset_ = 0;
116 edgeOffset_ = vertexOffset_ + dofsPerCube(0) * ((size_type)gridView_.size(dim));
117
118 if (dim>=2)
119 {
120 triangleOffset_ = edgeOffset_ + dofsPerCube(1) * ((size_type) gridView_.size(dim-1));
121
122 quadrilateralOffset_ = triangleOffset_ + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle));
123 }
124
125 if (dim==3) {
126 tetrahedronOffset_ = quadrilateralOffset_ + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral));
127
128 prismOffset_ = tetrahedronOffset_ + dofsPerSimplex(3) * ((size_type)gridView_.size(Dune::GeometryTypes::tetrahedron));
129
130 hexahedronOffset_ = prismOffset_ + dofsPerPrism() * ((size_type)gridView_.size(Dune::GeometryTypes::prism));
131
132 pyramidOffset_ = hexahedronOffset_ + dofsPerCube(3) * ((size_type)gridView_.size(Dune::GeometryTypes::hexahedron));
133 }
134 }
135
137 const GridView& gridView() const
138 {
139 return gridView_;
140 }
141
143 void update (const GridView& gv)
144 {
145 gridView_ = gv;
146 }
147
152 {
153 return Node{order_};
154 }
155
163 {
164 return IndexSet{*this};
165 }
166
169 {
170 switch (dim)
171 {
172 case 1:
173 return dofsPerCube(0) * ((size_type)gridView_.size(dim))
174 + dofsPerCube(1) * ((size_type)gridView_.size(dim-1));
175 case 2:
176 {
177 return dofsPerCube(0) * ((size_type)gridView_.size(dim))
178 + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
179 + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle))
180 + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral));
181 }
182 case 3:
183 {
184 return dofsPerCube(0) * ((size_type)gridView_.size(dim))
185 + dofsPerCube(1) * ((size_type)gridView_.size(dim-1))
186 + dofsPerSimplex(2) * ((size_type)gridView_.size(Dune::GeometryTypes::triangle))
187 + dofsPerCube(2) * ((size_type)gridView_.size(Dune::GeometryTypes::quadrilateral))
188 + dofsPerSimplex(3) * ((size_type)gridView_.size(Dune::GeometryTypes::tetrahedron))
189 + dofsPerPyramid() * ((size_type)gridView_.size(Dune::GeometryTypes::pyramid))
190 + dofsPerPrism() * ((size_type)gridView_.size(Dune::GeometryTypes::prism))
191 + dofsPerCube(3) * ((size_type)gridView_.size(Dune::GeometryTypes::hexahedron));
192 }
193 }
194 DUNE_THROW(Dune::NotImplemented, "No size method for " << dim << "d grids available yet!");
195 }
196
198 size_type size(const SizePrefix prefix) const
199 {
200 assert(prefix.size() == 0 || prefix.size() == 1);
201 return (prefix.size() == 0) ? size() : 0;
202 }
203
206 {
207 return size();
208 }
209
212 {
213 // That cast to unsigned int is necessary because GV::dimension is an enum,
214 // which is not recognized by the power method as an integer type...
215 return power(order()+1, (unsigned int)GV::dimension);
216 }
217
218protected:
219 GridView gridView_;
220
221 unsigned int order() const
222 {
223 return (useDynamicOrder) ? order_ : k;
224 }
225
226 // Run-time order, only valid if k<0
227 const unsigned int order_;
228
230 size_type dofsPerSimplex(std::size_t simplexDim) const
231 {
232 return useDynamicOrder ? dofsPerSimplex_[simplexDim] : computeDofsPerSimplex(simplexDim);
233 }
234
236 size_type dofsPerCube(std::size_t cubeDim) const
237 {
238 return useDynamicOrder ? dofsPerCube_[cubeDim] : computeDofsPerCube(cubeDim);
239 }
240
241 size_type dofsPerPrism() const
242 {
243 return useDynamicOrder ? dofsPerPrism_ : computeDofsPerPrism();
244 }
245
246 size_type dofsPerPyramid() const
247 {
248 return useDynamicOrder ? dofsPerPyramid_ : computeDofsPerPyramid();
249 }
250
252 size_type computeDofsPerSimplex(std::size_t simplexDim) const
253 {
254 return order() == 0 ? (dim == simplexDim ? 1 : 0) : Dune::binomial(std::size_t(order()-1),simplexDim);
255 }
256
258 size_type computeDofsPerCube(std::size_t cubeDim) const
259 {
260 return order() == 0 ? (dim == cubeDim ? 1 : 0) : Dune::power(order()-1, cubeDim);
261 }
262
263 size_type computeDofsPerPrism() const
264 {
265 return order() == 0 ? (dim == 3 ? 1 : 0) : (order()-1)*(order()-1)*(order()-2)/2;
266 }
267
268 size_type computeDofsPerPyramid() const
269 {
270 return order() == 0 ? (dim == 3 ? 1 : 0) : (order()-2)*(order()-1)*(2*order()-3)/6;
271 }
272
273 // When the order is given at run-time, the following numbers are pre-computed:
274 std::array<size_type,dim+1> dofsPerSimplex_;
275 std::array<size_type,dim+1> dofsPerCube_;
276 size_type dofsPerPrism_;
277 size_type dofsPerPyramid_;
278
279 size_type vertexOffset_;
280 size_type edgeOffset_;
281 size_type triangleOffset_;
282 size_type quadrilateralOffset_;
283 size_type tetrahedronOffset_;
284 size_type pyramidOffset_;
285 size_type prismOffset_;
286 size_type hexahedronOffset_;
287
288};
289
290
291
292template<typename GV, int k, typename R>
293class LagrangeNode :
294 public LeafBasisNode
295{
296 // Stores LocalFiniteElement implementations with run-time order as a function of GeometryType
297 template<typename Domain, typename Range, int dim>
298 class LagrangeRunTimeLFECache
299 {
300 public:
301 using FiniteElementType = LagrangeLocalFiniteElement<EquidistantPointSet,dim,Domain,Range>;
302
303 const FiniteElementType& get(GeometryType type)
304 {
305 auto i = data_.find(type);
306 if (i==data_.end())
307 i = data_.emplace(type,FiniteElementType(type,order_)).first;
308 return (*i).second;
309 }
310
311 std::map<GeometryType, FiniteElementType> data_;
312 unsigned int order_;
313 };
314
315 static const int dim = GV::dimension;
316 static const bool useDynamicOrder = (k<0);
317
318 using FiniteElementCache = typename std::conditional<(useDynamicOrder),
319 LagrangeRunTimeLFECache<typename GV::ctype, R, dim>,
320 PQkLocalFiniteElementCache<typename GV::ctype, R, dim, k>
321 >::type;
322
323public:
324
325 using size_type = std::size_t;
326 using Element = typename GV::template Codim<0>::Entity;
327 using FiniteElement = typename FiniteElementCache::FiniteElementType;
328
330 LagrangeNode() :
331 finiteElement_(nullptr),
332 element_(nullptr)
333 {}
334
336 LagrangeNode(unsigned int order) :
337 order_(order),
338 finiteElement_(nullptr),
339 element_(nullptr)
340 {
341 // Only the cache for the run-time-order case (i.e., k<0), has the 'order_' member
342 Hybrid::ifElse(Std::bool_constant<(useDynamicOrder)>(),
343 [&](auto id) {
344 id(cache_).order_ = order;
345 },
346 [&](auto id) {}
347 );
348 }
349
351 const Element& element() const
352 {
353 return *element_;
354 }
355
360 const FiniteElement& finiteElement() const
361 {
362 return *finiteElement_;
363 }
364
366 void bind(const Element& e)
367 {
368 element_ = &e;
369 finiteElement_ = &(cache_.get(element_->type()));
370 this->setSize(finiteElement_->size());
371 }
372
373protected:
374
375 unsigned int order() const
376 {
377 return (useDynamicOrder) ? order_ : k;
378 }
379
380 // Run-time order, only valid if k<0
381 unsigned int order_;
382
383 FiniteElementCache cache_;
384 const FiniteElement* finiteElement_;
385 const Element* element_;
386};
387
388
389
390template<typename GV, int k, class MI, typename R>
391class LagrangeNodeIndexSet
392{
393 enum {dim = GV::dimension};
394 static const bool useDynamicOrder = (k<0);
395
396public:
397
398 using size_type = std::size_t;
399
401 using MultiIndex = MI;
402
403 using PreBasis = LagrangePreBasis<GV, k, MI, R>;
404
405 using Node = LagrangeNode<GV, k, R>;
406
407 LagrangeNodeIndexSet(const PreBasis& preBasis) :
408 preBasis_(&preBasis),
409 node_(nullptr)
410 {}
411
417 void bind(const Node& node)
418 {
419 node_ = &node;
420 }
421
424 void unbind()
425 {
426 node_ = nullptr;
427 }
428
431 size_type size() const
432 {
433 assert(node_ != nullptr);
434 return node_->finiteElement().size();
435 }
436
438 template<typename It>
439 It indices(It it) const
440 {
441 assert(node_ != nullptr);
442 for (size_type i = 0, end = node_->finiteElement().size() ; i < end ; ++it, ++i)
443 {
444 Dune::LocalKey localKey = node_->finiteElement().localCoefficients().localKey(i);
445 const auto& gridIndexSet = preBasis_->gridView().indexSet();
446 const auto& element = node_->element();
447
448 // The dimension of the entity that the current dof is related to
449 auto dofDim = dim - localKey.codim();
450
451 // Test for a vertex dof
452 // The test for k==1 is redundant, but having it here allows the compiler to conclude
453 // at compile-time that the dofDim==0 case is the only one that will ever happen.
454 // This leads to measurable speed-up: see
455 // https://gitlab.dune-project.org/staging/dune-functions/issues/30
456 if (k==1 || dofDim==0) {
457 *it = {{ (size_type)(gridIndexSet.subIndex(element,localKey.subEntity(),dim)) }};
458 continue;
459 }
460
461 if (dofDim==1)
462 { // edge dof
463 if (dim==1) // element dof -- any local numbering is fine
464 {
465 *it = {{ preBasis_->edgeOffset_
466 + preBasis_->dofsPerCube(1) * ((size_type)gridIndexSet.subIndex(element,0,0))
467 + localKey.index() }};
468 continue;
469 }
470 else
471 {
472 const auto refElement
473 = Dune::referenceElement<double,dim>(element.type());
474
475 // we have to reverse the numbering if the local triangle edge is
476 // not aligned with the global edge
477 auto v0 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),0,dim),dim);
478 auto v1 = (size_type)gridIndexSet.subIndex(element,refElement.subEntity(localKey.subEntity(),localKey.codim(),1,dim),dim);
479 bool flip = (v0 > v1);
480 *it = {{ (flip)
481 ? preBasis_->edgeOffset_
482 + preBasis_->dofsPerCube(1)*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim()))
483 + (preBasis_->dofsPerCube(1)-1)-localKey.index()
484 : preBasis_->edgeOffset_
485 + preBasis_->dofsPerCube(1)*((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim()))
486 + localKey.index() }};
487 continue;
488 }
489 }
490
491 if (dofDim==2)
492 {
493 if (dim==2) // element dof -- any local numbering is fine
494 {
495 if (element.type().isTriangle())
496 {
497 *it = {{ preBasis_->triangleOffset_ + preBasis_->dofsPerSimplex(2)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
498 continue;
499 }
500 else if (element.type().isQuadrilateral())
501 {
502 *it = {{ preBasis_->quadrilateralOffset_ + preBasis_->dofsPerCube(2)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
503 continue;
504 }
505 else
506 DUNE_THROW(Dune::NotImplemented, "2d elements have to be triangles or quadrilaterals");
507 } else
508 {
509 const auto refElement
510 = Dune::referenceElement<double,dim>(element.type());
511
512 if (order()>3)
513 DUNE_THROW(Dune::NotImplemented, "LagrangeNodalBasis for 3D grids is only implemented if k<=3");
514
515 if (order()==3 and !refElement.type(localKey.subEntity(), localKey.codim()).isTriangle())
516 DUNE_THROW(Dune::NotImplemented, "LagrangeNodalBasis for 3D grids with k==3 is only implemented if the grid is a simplex grid");
517
518 *it = {{ preBasis_->triangleOffset_ + ((size_type)gridIndexSet.subIndex(element,localKey.subEntity(),localKey.codim())) }};
519 continue;
520 }
521 }
522
523 if (dofDim==3)
524 {
525 if (dim==3) // element dof -- any local numbering is fine
526 {
527 if (element.type().isTetrahedron())
528 {
529 *it = {{ preBasis_->tetrahedronOffset_ + preBasis_->dofsPerSimplex(3)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
530 continue;
531 }
532 else if (element.type().isHexahedron())
533 {
534 *it = {{ preBasis_->hexahedronOffset_ + preBasis_->dofsPerCube(3)*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
535 continue;
536 }
537 else if (element.type().isPrism())
538 {
539 *it = {{ preBasis_->prismOffset_ + preBasis_->dofsPerPrism()*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
540 continue;
541 }
542 else if (element.type().isPyramid())
543 {
544 *it = {{ preBasis_->pyramidOffset_ + preBasis_->dofsPerPyramid()*((size_type)gridIndexSet.subIndex(element,0,0)) + localKey.index() }};
545 continue;
546 }
547 else
548 DUNE_THROW(Dune::NotImplemented, "3d elements have to be tetrahedra, hexahedra, prisms, or pyramids");
549 } else
550 DUNE_THROW(Dune::NotImplemented, "Grids of dimension larger than 3 are no supported");
551 }
552 DUNE_THROW(Dune::NotImplemented, "Grid contains elements not supported for the LagrangeNodalBasis");
553 }
554 return it;
555 }
556
557protected:
558
559 auto order() const
560 {
561 return (useDynamicOrder) ? preBasis_->order() : k;
562 }
563
564 const PreBasis* preBasis_;
565
566 const Node* node_;
567};
568
569
570
571namespace BasisFactory {
572
573namespace Imp {
574
575template<int k, typename R=double>
576class LagrangePreBasisFactory
577{
578 static const bool useDynamicOrder = (k<0);
579public:
580 static const std::size_t requiredMultiIndexSize = 1;
581
582 // \brief Constructor for factory with compile-time order
583 LagrangePreBasisFactory() : order_(0)
584 {}
585
586 // \brief Constructor for factory with run-time order (template argument k is disregarded)
587 LagrangePreBasisFactory(unsigned int order)
588 : order_(order)
589 {}
590
591 template<class MultiIndex, class GridView>
592 auto makePreBasis(const GridView& gridView) const
593 {
594 return (useDynamicOrder)
595 ? LagrangePreBasis<GridView, k, MultiIndex, R>(gridView, order_)
596 : LagrangePreBasis<GridView, k, MultiIndex, R>(gridView);
597 }
598
599private:
600 unsigned int order_;
601};
602
603} // end namespace BasisFactory::Imp
604
605
606
615template<std::size_t k, typename R=double>
617{
618 return Imp::LagrangePreBasisFactory<k,R>();
619}
620
628template<typename R=double>
629auto lagrange(int order)
630{
631 return Imp::LagrangePreBasisFactory<-1,R>(order);
632}
633
634} // end namespace BasisFactory
635
636
637
661template<typename GV, int k=-1, typename R=double>
663
664
665
666
667
668} // end namespace Functions
669} // end namespace Dune
670
671
672#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LAGRANGEBASIS_HH
Global basis for given pre-basis.
Definition: defaultglobalbasis.hh:47
A pre-basis for a PQ-lagrange bases with given order.
Definition: lagrangebasis.hh:60
Node makeNode() const
Create tree node.
Definition: lagrangebasis.hh:151
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: lagrangebasis.hh:205
LagrangeNodeIndexSet< GV, k, MI, R > IndexSet
Template mapping root tree path to type of created tree node index set.
Definition: lagrangebasis.hh:83
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:236
size_type size() const
Same as size(prefix) with empty prefix.
Definition: lagrangebasis.hh:168
LagrangePreBasis(const GridView &gv, unsigned int order)
Constructor for a given grid view object and run-time order.
Definition: lagrangebasis.hh:97
LagrangePreBasis(const GridView &gv)
Constructor for a given grid view object with compile-time order.
Definition: lagrangebasis.hh:92
GV GridView
The grid view that the FE basis is defined on.
Definition: lagrangebasis.hh:67
LagrangeNode< GV, k, R > Node
Template mapping root tree path to type of created tree node.
Definition: lagrangebasis.hh:80
std::size_t size_type
Type used for indices and size information.
Definition: lagrangebasis.hh:70
IndexSet makeIndexSet() const
Create tree node index set.
Definition: lagrangebasis.hh:162
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: lagrangebasis.hh:143
MI MultiIndex
Type used for global numbering of the basis vectors.
Definition: lagrangebasis.hh:86
void initializeIndices()
Initialize the global indices.
Definition: lagrangebasis.hh:113
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:230
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:258
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: lagrangebasis.hh:137
size_type size(const SizePrefix prefix) const
Return number of possible values for next position in multi index.
Definition: lagrangebasis.hh:198
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: lagrangebasis.hh:211
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:252
Dune::ReservedVector< size_type, 1 > SizePrefix
Type used for prefixes handed to the size() method.
Definition: lagrangebasis.hh:89
auto lagrange(int order)
Create a pre-basis factory that can create a Lagrange pre-basis with a run-time order.
Definition: lagrangebasis.hh:629
auto power(ChildPreBasisFactory &&childPreBasisFactory, const IndexMergingStrategy &ims)
Create a pre-basis factory that can build a PowerPreBasis.
Definition: powerbasis.hh:483
Definition: polynomial.hh:10
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)