DUNE PDELab (git)

morleybasis.hh
Go to the documentation of this file.
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#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_MORLEYBASIS_HH
7#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_MORLEYBASIS_HH
8
9#include <algorithm>
10#include <type_traits>
11#include <vector>
12#include <array>
13#include <bitset>
14
18
20#include <dune/grid/common/rangegenerators.hh>
21
22#include <dune/localfunctions/common/localbasis.hh>
23#include <dune/localfunctions/common/localfiniteelementtraits.hh>
24#include <dune/localfunctions/common/localkey.hh>
25
26#include <dune/functions/analyticfunctions/monomialset.hh>
27#include <dune/functions/common/densevectorview.hh>
29#include <dune/functions/functionspacebases/defaultglobalbasis.hh>
30#include <dune/functions/functionspacebases/functionaldescriptor.hh>
31#include <dune/functions/functionspacebases/leafprebasismappermixin.hh>
32#include <dune/functions/functionspacebases/nodes.hh>
33#include <dune/functions/functionspacebases/transformedfiniteelementmixin.hh>
34
51namespace Dune::Functions
52{
53
54 template<class GV, class R>
55 struct MorleyPreBasis;
56
74 template<class GV, class R = double>
76
77
78 namespace Impl
79 {
80
87 template<class D, class R>
88 class MorleyReferenceLocalBasis
89 {
90 public:
91 static constexpr int dim = 2;
92 using Traits = H2LocalBasisTraits<D, dim, FieldVector<D, dim>, R, 1, FieldVector<R, 1>,
94
95 private:
96
109 static constexpr auto getMorleyCoefficients()
110 {
111 // Define std::sqrt(2.) manually in double precision,
112 // because std::sqrt is not constexpr before C++26.
113 D sqrt2 = 0.5 * 1.414213562373095;
114
115 return Dune::FieldMatrix<D, 6,6>({{1, -1, -1, 0, 2, 0},
116 {0, 0.5, 0.5, 0.5, -1, -0.5},
117 {0, 0.5, 0.5, -0.5, -1, 0.5},
118 {0, 0, 1, 0, 0, -1},
119 {0, -1., 0, 1., 0, 0},
120 {0, sqrt2, sqrt2, -sqrt2, -2. * sqrt2, -sqrt2}});
121 }
122
123 static constexpr auto referenceBasisCoefficients = getMorleyCoefficients();
125
126 public:
127
130 static constexpr unsigned int size()
131 {
132 return 6;
133 }
134
137 static constexpr unsigned int order()
138 {
139 return 2;
140 }
141
147 void evaluateFunction(const typename Traits::DomainType &in,
148 std::vector<typename Traits::RangeType> &out) const
149 {
150 out.resize(size());
151 auto monomialValues = monomials(in);
152 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
153 }
154
160 void evaluateJacobian(const typename Traits::DomainType &in,
161 std::vector<typename Traits::JacobianType> &out) const
162 {
163 out.resize(size());
164 auto monomialValues = derivative(monomials)(in);
165 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
166 }
167
173 void evaluateHessian(const typename Traits::DomainType &in,
174 std::vector<typename Traits::HessianType> &out) const
175 {
176 out.resize(size());
177 auto monomialValues = derivative(derivative(monomials))(in);
178 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
179 }
180
187 void partial(std::array<unsigned int, dim> order, const typename Traits::DomainType &in,
188 std::vector<typename Traits::RangeType> &out) const
189 {
190 out.resize(size());
191 auto totalOrder = std::accumulate(order.begin(), order.end(), 0);
192 if (totalOrder == 0)
193 evaluateFunction(in, out);
194 else if (totalOrder == 1)
195 {
196 evaluateJacobian(in,jacobiansBuffer_);
197 std::size_t which = std::max_element(order.begin(), order.end()) - order.begin();
198 for (auto i : Dune::range(size()))
199 out[i] = jacobiansBuffer_[i][0][which];
200 }
201 else if (totalOrder == 2)
202 {
203 evaluateHessian(in, hessianBuffer_);
204 std::size_t first, second;
205 first = std::max_element(order.begin(), order.end()) - order.begin();
206 if (order[first] == 2)
207 second = first;
208 else
209 {
210 order[first] = 0;
211 second = std::max_element(order.begin(), order.end()) - order.begin();
212 }
213 for (auto i : Dune::range(size()))
214 out[i] = hessianBuffer_[i][first][second];
215 }
216 else
217 DUNE_THROW(RangeError, "partial() not implemented for given order");
218 }
219
220 private:
221 mutable std::vector<typename Traits::JacobianType> jacobiansBuffer_;
222 mutable std::vector<typename Traits::HessianType> hessianBuffer_;
223 };
224
225
229 class MorleyLocalCoefficients
230 {
231 public:
232 using size_type = std::size_t;
233
234 MorleyLocalCoefficients()
235 {
236 for (size_type i = 0; i < 3; ++i)
237 {
238 localKeys_[i] = LocalKey(i, 2, 0); // vertex dofs
239 localKeys_[3 + i] = LocalKey(i, 1, 0); // edge dofs
240 }
241 }
242
245 static constexpr size_type size()
246 {
247 return 6;
248 }
249
252 constexpr LocalKey const &localKey(size_type i) const
253 {
254 return localKeys_[i];
255 }
256
257 private:
258 std::array<LocalKey, 6> localKeys_;
259 };
260
261
267 template<class D>
268 class MorleyLocalInterpolation
269 {
270 using size_type = std::size_t;
271 using FunctionalDescriptor = Dune::Functions::Impl::FunctionalDescriptor<2>;
272
273 public:
274
275 MorleyLocalInterpolation()
276 {
277 descriptors_[0] = FunctionalDescriptor();
278 descriptors_[1] = FunctionalDescriptor();
279 descriptors_[2] = FunctionalDescriptor();
280 descriptors_[3] = FunctionalDescriptor(1);
281 descriptors_[4] = FunctionalDescriptor(1);
282 descriptors_[5] = FunctionalDescriptor(1);
283 }
284
287 template <class Element>
288 void bind(const Element &element, const std::bitset<3> &edgeOrientation)
289 {
290 auto geometry = element.geometry();
291
292 // get global Normals and midpoints
293 auto refElement = Dune::referenceElement<double, 2>(geometry.type());
294 for (std::size_t i = 0; i < 3; ++i)
295 {
296 localVertices_[i] = refElement.position(i, 2);
297
298 localMidpoints_[i] = refElement.position(i, 1);
299 std::size_t lower = (i == 2) ? 1 : 0;
300 std::size_t upper = (i == 0) ? 1 : 2;
301
302 auto edge = geometry.global(refElement.position(upper, 2))
303 - geometry.global(refElement.position(lower, 2));
304 // normalize and orient
305 edge /= edge.two_norm() * (edgeOrientation[i] ? -1. : 1.);
306 // Rotation by pi/2. Note that Kirby rotates by 3*pi/2
307 globalNormals_[i] = {-edge[1], edge[0]};
308 }
309 }
310
318 template <class F, class C>
319 void interpolate(const F &f, std::vector<C> &out) const
320 {
321 out.resize(6);
322 auto&& df = derivative(f);
323 for (size_type i = 0; i < 3; ++i)
324 {
325 out[i] = f(localVertices_[i]);
326 out[3 + i] = squeeze(df(localMidpoints_[i])).dot(globalNormals_[i]);
327 }
328 }
329
330 const FunctionalDescriptor& functionalDescriptor(size_type i) const
331 {
332 return descriptors_[i];
333 }
334
335 protected:
336 std::array<Dune::FieldVector<D, 2>, 3> globalNormals_;
337 std::array<Dune::FieldVector<D, 2>, 3> localMidpoints_;
338 std::array<Dune::FieldVector<D, 2>, 3> localVertices_;
339 std::array<FunctionalDescriptor, 6> descriptors_;
340
341 };
342
343 template<class D, class R>
344 using MorleyLocalBasisTraits = typename Impl::MorleyReferenceLocalBasis<D, R>::Traits;
345
354 template<class D, class R>
355 class MorleyLocalFiniteElement
356 : public Impl::TransformedFiniteElementMixin<MorleyLocalFiniteElement<D,R>, MorleyLocalBasisTraits<D, R>>
357 {
358 using Base = Impl::TransformedFiniteElementMixin< MorleyLocalFiniteElement<D,R>, MorleyLocalBasisTraits<D, R>>;
359 friend class Impl::TransformedLocalBasis<MorleyLocalFiniteElement<D,R>, MorleyLocalBasisTraits<D, R>>;
360 static constexpr int dim = 2;
361 public:
362
365 using size_type = std::size_t;
366 using Traits = LocalFiniteElementTraits<
367 Impl::TransformedLocalBasis<MorleyLocalFiniteElement<D,R>, MorleyLocalBasisTraits<D, R>>,
368 Impl::MorleyLocalCoefficients,
369 Impl::MorleyLocalInterpolation<D>>;
370
374 const typename Traits::LocalCoefficientsType &localCoefficients() const
375 {
376 return coefficients_;
377 }
378
381 const typename Traits::LocalInterpolationType &localInterpolation() const
382 {
383 return interpolation_;
384 }
385
388 static constexpr GeometryType type()
389 {
390 return GeometryTypes::simplex(dim);
391 }
392
395 static constexpr size_type size()
396 {
397 return 6;
398 }
399
402 template<class Element>
403 void bind(std::bitset<3> const& data, Element const &e)
404 {
405 edgeOrientation_ = data;
406
407 fillMatrix(e.geometry());
408 interpolation_.bind(e, edgeOrientation_);
409 }
410
411 protected:
412
415 Impl::MorleyReferenceLocalBasis<D, R> const& referenceLocalBasis() const
416 {
417 return basis_;
418 }
419
425 template<class InputValues, class OutputValues>
426 void transform(InputValues const& inValues, OutputValues& outValues) const
427 {
428 // Here we cannot directly use
429 // mat_.mv(inValues, outValues);
430 // because mv expects the DenseVector interface.
431 auto inValuesDenseVector = Impl::DenseVectorView(inValues);
432 auto outValuesDenseVector = Impl::DenseVectorView(outValues);
433 mat_.mv(inValuesDenseVector, outValuesDenseVector);
434 }
435
436 private:
437
444 template<class Geometry>
445 void fillMatrix(Geometry const &geometry)
446 {
447 std::array<R, 3> B_11;
448 std::array<R, 3> B_12;
449 std::array<R, 3> l_inv;
450
451 std::array<Dune::FieldVector<R, 2>, 3> referenceTangents;
452 std::array<Dune::FieldVector<R, 2>, 3> globalTangents;
453
454 // By default, edges point from the vertex with the smaller index
455 // to the vertex with the larger index.
456
457 // get local and global Tangents
458 auto refElement = Dune::referenceElement<double, 2>(geometry.type());
459 auto x = refElement.position(0,0);
460 for (std::size_t i = 0; i < 3; ++i)
461 {
462 std::size_t lower = (i == 2) ? 1 : 0;
463 std::size_t upper = (i == 0) ? 1 : 2;
464 auto edge = refElement.position(upper, 2) - refElement.position(lower, 2);
465
466 referenceTangents[i] = edge / edge.two_norm();
467
468 auto globalEdge = geometry.global(refElement.position(upper, 2))
469 - geometry.global(refElement.position(lower, 2));
470
471 l_inv[i] = 1. / globalEdge.two_norm();
472 globalTangents[i] = globalEdge * l_inv[i];
473 }
474
475 auto jacobianTransposed = geometry.jacobianTransposed(x);
476 for (std::size_t i = 0; i < 3; ++i)
477 {
478 B_11[i] = -referenceTangents[i][1]
479 *(-globalTangents[i][1] * jacobianTransposed[0][0]
480 + globalTangents[i][0] * jacobianTransposed[0][1])
481 + referenceTangents[i][0]
482 *(-globalTangents[i][1] * jacobianTransposed[1][0]
483 + globalTangents[i][0] * jacobianTransposed[1][1]);
484 B_12[i] = -referenceTangents[i][1]
485 *(globalTangents[i][0] * jacobianTransposed[0][0]
486 + globalTangents[i][1] * jacobianTransposed[0][1])
487 + referenceTangents[i][0]
488 *(globalTangents[i][0] * jacobianTransposed[1][0]
489 + globalTangents[i][1] * jacobianTransposed[1][1]);
490 }
491
492 // Actually setup matrix
493 int sign = -1;
494 for (std::size_t i = 0; i < 3; ++i)
495 {
496 mat_[i][i] = 1.;
497 for (std::size_t j = 0; j < 3; ++j)
498 {
499 if (j != (2 - i)) // dune specific edge order
500 {
501 mat_[j][3 + i] = sign * B_12[i] * l_inv[i];
502 sign *= -1;
503 }
504 }
505 mat_[3 + i][3 + i] = (edgeOrientation_[i] ? -1. : 1.) * B_11[i];
506 }
507 }
508
509 // a finite element consists of a basis, coeffiecents and an interpolation
510 typename Impl::MorleyReferenceLocalBasis<D, R> basis_;
511 typename Traits::LocalCoefficientsType coefficients_;
512 typename Traits::LocalInterpolationType interpolation_;
513 // This is the matrix M in Kirbys paper
515 // the local state, i.e. a collection of global information restricted to this element
516 std::bitset<3> edgeOrientation_;
517
518 };
519
520 } // end namespace Impl
521
522
523
524 // *****************************************************************************
525 // This is the reusable part of the basis. It contains
526 //
527 // MorleyPreBasis
528 // MorleyNode
529 //
530 // The pre-basis allows to create the others and is the owner of possible shared
531 // state. These components do _not_ depend on the global basis and local view
532 // and can be used without a global basis.
533 // *****************************************************************************
534
535 template<class GV, class R>
536 class MorleyNode
537 : public LeafBasisNode
538 {
540 public:
541 using size_type = std::size_t;
542 using Element = typename GV::template Codim<0>::Entity;
543 using FiniteElement = typename Impl::MorleyLocalFiniteElement<typename GV::ctype, R>;
544
545
546 MorleyNode(Mapper const& m, std::vector<std::bitset<3>> const& data)
547 : mapper_(&m), data_(&data)
548 {
549 this->setSize(finiteElement_.size());
550 }
551
553 Element const &element() const
554 {
555 return *element_;
556 }
557
563 FiniteElement const &finiteElement() const
564 {
565 return finiteElement_;
566 }
567
569 void bind(Element const &e)
570 {
571 element_ = &e;
572 finiteElement_.bind((*data_)[mapper_->index(e)], *element_);
573 }
574
576 unsigned int order() const
577 {
578 return finiteElement_.localBasis().order();
579 }
580
581 protected:
582 FiniteElement finiteElement_;
583 Element const* element_;
584 Mapper const* mapper_;
585 std::vector<std::bitset<3>> const* data_;
586 };
587
588
598 template<class GV, class R>
600 : public LeafPreBasisMapperMixin<GV>
601 {
604 using Element = typename GV::template Codim<0>::Entity;
605 using D = typename GV::ctype;
606 static const std::size_t dim = GV::dimension;
607
608 // helper methods to assign each subentity the number of dofs. Used by the LeafPreBasisMapperMixin.
609 static constexpr auto morleyMapperLayout(Dune::GeometryType type, int gridDim)
610 {
611 assert(gridDim == 2);
612 if (type.isVertex())
613 return 1; // one evaluation dof per vertex
614 if (type.isLine())
615 return 1;
616 if ((type.isTriangle()) )
617 return 0;
618 else
619 return 0;
620 }
621
622 public:
624 using GridView = GV;
625
627 using size_type = std::size_t;
628
630 using Node = MorleyNode<GridView, R>;
631
633 MorleyPreBasis(const GV &gv)
634 : Base(gv, morleyMapperLayout)
635 , mapper_({gv, mcmgElementLayout()})
636 {
637 updateState(gv);
638 }
639
641 void update(GridView const &gv)
642 {
643 Base::update(gv);
644 updateState(gv);
645 }
646
651 {
652 return Node{mapper_, data_};
653 }
654
655 protected:
656
657 void updateState(GridView const &gridView)
658 {
659 data_.resize(gridView.size(0));
660 // compute orientation for all elements
661 unsigned short orientation = 0;
662 auto const& idSet = gridView.grid().globalIdSet();
663
664 for (const auto &element : elements(gridView))
665 {
666 const auto &refElement = referenceElement(element);
667 auto elementIndex = mapper_.index(element);
668
669 orientation = 0;
670
671 for (std::size_t i = 0; i < element.subEntities(dim - 1); i++)
672 {
673 // Local vertex indices within the element
674 auto localV0 = refElement.subEntity(i, dim - 1, 0, dim);
675 auto localV1 = refElement.subEntity(i, dim - 1, 1, dim);
676
677 // Global vertex indices within the grid
678 auto globalV0 = idSet.subId(element, localV0, dim);
679 auto globalV1 = idSet.subId(element, localV1, dim);
680
681 // The edge is flipped if the local ordering disagrees with global ordering
682 if ((localV0 < localV1 && globalV0 > globalV1)
683 || (localV0 > localV1 && globalV0 < globalV1))
684 {
685 orientation |= (1 << i);
686 }
687 }
688 data_[elementIndex] = orientation;
689 }
690 }
691
692 SubEntityMapper mapper_;
693 std::vector<std::bitset<3>> data_;
694
695 }; // class MorleyPreBasis
696
697 namespace BasisFactory
698 {
699
706 template<class R = double>
707 auto morley()
708 {
709 return [=](auto const &gridView) {
710 return MorleyPreBasis<std::decay_t<decltype(gridView)>, R>(gridView);
711 };
712 }
713
714 } // end namespace BasisFactory
715
716} // end namespace Dune::Functions
717
718#endif
Macro for wrapping boundary checks.
FieldTraits< value_type >::real_type two_norm() const
two norm sqrt(sum over squared values of entries)
Definition: densevector.hh:641
A dense n x m matrix.
Definition: fmatrix.hh:117
vector space out of a tensor product of fields.
Definition: fvector.hh:92
Global basis for given pre-basis.
Definition: defaultglobalbasis.hh:50
A generic MixIn class for PreBasis with flat indices computed from a mapper.
Definition: leafprebasismappermixin.hh:62
const GridView & gridView() const
Export the stored GridView.
Definition: leafprebasismappermixin.hh:95
std::size_t size_type
Type used for index digits.
Definition: leafprebasismappermixin.hh:71
void update(const GridView &gv)
Update the stored GridView.
Definition: leafprebasismappermixin.hh:101
GV GridView
Type of the associated GridView.
Definition: leafprebasismappermixin.hh:68
Unique label for each type of entities that can occur in DUNE grids.
Definition: type.hh:114
constexpr bool isVertex() const
Return true if entity is a vertex.
Definition: type.hh:279
constexpr bool isTriangle() const
Return true if entity is a triangle.
Definition: type.hh:289
constexpr bool isLine() const
Return true if entity is a line segment.
Definition: type.hh:284
Wrapper class for geometries.
Definition: geometry.hh:71
JacobianTransposed jacobianTransposed(const LocalCoordinate &local) const
Return the transposed of the Jacobian.
Definition: geometry.hh:302
GeometryType type() const
Return the type of the reference element. The type can be used to access the Dune::ReferenceElement.
Definition: geometry.hh:194
GlobalCoordinate global(const LocalCoordinate &local) const
Evaluate the map .
Definition: geometry.hh:228
Grid view abstract base class.
Definition: gridview.hh:66
Describe position of one degree of freedom.
Definition: localkey.hh:24
Mapper interface.
Definition: mapper.hh:110
Implementation class for a multiple codim and multiple geometry type mapper.
Definition: mcmgmapper.hh:129
Index index(const EntityType &e) const
Map entity to starting index in array for dof block.
Definition: mcmgmapper.hh:171
Default exception class for range errors.
Definition: exceptions.hh:346
This file provides an implementation of the cubic Hermite finite element in 1 to 3 dimensions.
A few common exception classes.
Implements a vector constructed from a given type representing a field and a compile-time given size.
#define DUNE_THROW(E,...)
Definition: exceptions.hh:312
TrigonometricFunction< K, -cosFactor, sinFactor > derivative(const TrigonometricFunction< K, sinFactor, cosFactor > &f)
Obtain derivative of TrigonometricFunction function.
Definition: trigonometricfunction.hh:43
unspecified value type referenceElement(T &&... t)
Returns a reference element for the objects t....
constexpr GeometryType simplex(unsigned int dim)
Returns a GeometryType representing a simplex of dimension dim.
Definition: type.hh:453
void interpolate(const F &f, const GFS &gfs, XG &xg)
interpolation from a given grid function
Definition: interpolate.hh:177
constexpr T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:279
MCMGLayout mcmgElementLayout()
layout for elements (codim-0 entities)
Definition: mcmgmapper.hh:97
Mapper for multiple codim and multiple geometry types.
auto morley()
construct a PreBasisFactory for the Morley Finite Element
Definition: morleybasis.hh:707
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
int sign(const T &val)
Return the sign of the value.
Definition: math.hh:180
Static tag representing a codimension.
Definition: dimension.hh:24
Function, which evaluates all monomials up to degree maxDegree in a given coordinate.
Definition: monomialset.hh:64
A pre-basis for a Morleybasis.
Definition: morleybasis.hh:601
void update(GridView const &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: morleybasis.hh:641
Node makeNode() const
Create tree node.
Definition: morleybasis.hh:650
MorleyNode< GridView, R > Node
Template mapping root tree path to type of created tree node.
Definition: morleybasis.hh:630
MorleyPreBasis(const GV &gv)
Constructor for a given grid view object.
Definition: morleybasis.hh:633
traits helper struct
Definition: localfiniteelementtraits.hh:13
LC LocalCoefficientsType
Definition: localfiniteelementtraits.hh:20
LI LocalInterpolationType
Definition: localfiniteelementtraits.hh:24
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jan 8, 23:30, 2025)