6#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_MORLEYBASIS_HH
7#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_MORLEYBASIS_HH
15#include <dune/common/boundschecking.hh>
16#include <dune/common/exceptions.hh>
17#include <dune/common/fvector.hh>
19#include <dune/grid/common/mcmgmapper.hh>
20#include <dune/grid/common/rangegenerators.hh>
22#include <dune/localfunctions/common/localbasis.hh>
23#include <dune/localfunctions/common/localfiniteelementtraits.hh>
24#include <dune/localfunctions/common/localkey.hh>
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>
51namespace Dune::Functions
54 template<
class GV,
class R>
55 struct MorleyPreBasis;
74 template<
class GV,
class R =
double>
87 template<
class D,
class R>
88 class MorleyReferenceLocalBasis
91 static constexpr int dim = 2;
92 using Traits = H2LocalBasisTraits<D, dim, FieldVector<D, dim>, R, 1, FieldVector<R, 1>,
93 FieldMatrix<R, 1, dim>, FieldMatrix<R, dim, dim>>;
109 static constexpr auto getMorleyCoefficients()
113 D sqrt2 = 0.5 * 1.414213562373095;
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},
119 {0, -1., 0, 1., 0, 0},
120 {0, sqrt2, sqrt2, -sqrt2, -2. * sqrt2, -sqrt2}});
123 static constexpr auto referenceBasisCoefficients = getMorleyCoefficients();
130 static constexpr unsigned int size()
137 static constexpr unsigned int order()
147 void evaluateFunction(
const typename Traits::DomainType &in,
148 std::vector<typename Traits::RangeType> &out)
const
151 auto monomialValues = monomials(in);
152 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
160 void evaluateJacobian(
const typename Traits::DomainType &in,
161 std::vector<typename Traits::JacobianType> &out)
const
164 auto monomialValues =
derivative(monomials)(in);
165 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
173 void evaluateHessian(
const typename Traits::DomainType &in,
174 std::vector<typename Traits::HessianType> &out)
const
178 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
187 void partial(std::array<unsigned int, dim> order,
const typename Traits::DomainType &in,
188 std::vector<typename Traits::RangeType> &out)
const
191 auto totalOrder = std::accumulate(order.begin(), order.end(), 0);
193 evaluateFunction(in, out);
194 else if (totalOrder == 1)
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];
201 else if (totalOrder == 2)
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)
211 second = std::max_element(order.begin(), order.end()) - order.begin();
213 for (
auto i : Dune::range(size()))
214 out[i] = hessianBuffer_[i][first][second];
217 DUNE_THROW(RangeError,
"partial() not implemented for given order");
221 mutable std::vector<typename Traits::JacobianType> jacobiansBuffer_;
222 mutable std::vector<typename Traits::HessianType> hessianBuffer_;
229 class MorleyLocalCoefficients
232 using size_type = std::size_t;
234 MorleyLocalCoefficients()
236 for (size_type i = 0; i < 3; ++i)
238 localKeys_[i] = LocalKey(i, 2, 0);
239 localKeys_[3 + i] = LocalKey(i, 1, 0);
245 static constexpr size_type size()
252 constexpr LocalKey
const &localKey(size_type i)
const
254 return localKeys_[i];
258 std::array<LocalKey, 6> localKeys_;
268 class MorleyLocalInterpolation
270 using size_type = std::size_t;
271 using FunctionalDescriptor = Dune::Functions::Impl::FunctionalDescriptor<2>;
275 MorleyLocalInterpolation()
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);
287 template <
class Element>
288 void bind(
const Element &element,
const std::bitset<3> &edgeOrientation)
290 auto geometry = element.geometry();
293 auto refElement = Dune::referenceElement<double, 2>(geometry.type());
294 for (std::size_t i = 0; i < 3; ++i)
296 localVertices_[i] = refElement.position(i, 2);
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;
302 auto edge = geometry.global(refElement.position(upper, 2))
303 - geometry.global(refElement.position(lower, 2));
305 edge /= edge.two_norm() * (edgeOrientation[i] ? -1. : 1.);
307 globalNormals_[i] = {-edge[1], edge[0]};
318 template <
class F,
class C>
319 void interpolate(
const F &f, std::vector<C> &out)
const
323 for (size_type i = 0; i < 3; ++i)
325 out[i] = f(localVertices_[i]);
326 out[3 + i] = squeeze(df(localMidpoints_[i])).dot(globalNormals_[i]);
330 const FunctionalDescriptor& functionalDescriptor(size_type i)
const
332 return descriptors_[i];
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_;
343 template<
class D,
class R>
344 using MorleyLocalBasisTraits =
typename Impl::MorleyReferenceLocalBasis<D, R>::Traits;
354 template<
class D,
class R>
355 class MorleyLocalFiniteElement
356 :
public Impl::TransformedFiniteElementMixin<MorleyLocalFiniteElement<D,R>, MorleyLocalBasisTraits<D, R>>
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;
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>>;
374 const typename Traits::LocalCoefficientsType &localCoefficients()
const
376 return coefficients_;
381 const typename Traits::LocalInterpolationType &localInterpolation()
const
383 return interpolation_;
388 static constexpr GeometryType type()
390 return GeometryTypes::simplex(dim);
395 static constexpr size_type size()
402 template<
class Element>
403 void bind(std::bitset<3>
const& data, Element
const &e)
405 edgeOrientation_ = data;
407 fillMatrix(e.geometry());
408 interpolation_.bind(e, edgeOrientation_);
415 Impl::MorleyReferenceLocalBasis<D, R>
const& referenceLocalBasis()
const
425 template<
class InputValues,
class OutputValues>
426 void transform(InputValues
const& inValues, OutputValues& outValues)
const
431 auto inValuesDenseVector = Impl::DenseVectorView(inValues);
432 auto outValuesDenseVector = Impl::DenseVectorView(outValues);
433 mat_.mv(inValuesDenseVector, outValuesDenseVector);
444 template<
class Geometry>
445 void fillMatrix(Geometry
const &geometry)
447 std::array<R, 3> B_11;
448 std::array<R, 3> B_12;
449 std::array<R, 3> l_inv;
451 std::array<Dune::FieldVector<R, 2>, 3> referenceTangents;
452 std::array<Dune::FieldVector<R, 2>, 3> globalTangents;
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)
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);
466 referenceTangents[i] = edge / edge.two_norm();
468 auto globalEdge = geometry.global(refElement.position(upper, 2))
469 - geometry.global(refElement.position(lower, 2));
471 l_inv[i] = 1. / globalEdge.two_norm();
472 globalTangents[i] = globalEdge * l_inv[i];
475 auto jacobianTransposed = geometry.jacobianTransposed(x);
476 for (std::size_t i = 0; i < 3; ++i)
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]);
494 for (std::size_t i = 0; i < 3; ++i)
497 for (std::size_t j = 0; j < 3; ++j)
501 mat_[j][3 + i] = sign * B_12[i] * l_inv[i];
505 mat_[3 + i][3 + i] = (edgeOrientation_[i] ? -1. : 1.) * B_11[i];
510 typename Impl::MorleyReferenceLocalBasis<D, R> basis_;
511 typename Traits::LocalCoefficientsType coefficients_;
512 typename Traits::LocalInterpolationType interpolation_;
514 Dune::FieldMatrix<R, 6, 6>mat_;
516 std::bitset<3> edgeOrientation_;
535 template<
class GV,
class R>
537 :
public LeafBasisNode
539 using Mapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
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>;
546 MorleyNode(Mapper
const& m, std::vector<std::bitset<3>>
const& data)
547 : mapper_(&m), data_(&data)
549 this->setSize(finiteElement_.size());
553 Element
const &element()
const
563 FiniteElement
const &finiteElement()
const
565 return finiteElement_;
569 void bind(Element
const &e)
572 finiteElement_.bind((*data_)[mapper_->index(e)], *element_);
576 unsigned int order()
const
578 return finiteElement_.localBasis().order();
582 FiniteElement finiteElement_;
583 Element
const* element_;
584 Mapper
const* mapper_;
585 std::vector<std::bitset<3>>
const* data_;
598 template<
class GV,
class R>
603 using SubEntityMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
604 using Element =
typename GV::template Codim<0>::Entity;
605 using D =
typename GV::ctype;
606 static const std::size_t dim = GV::dimension;
609 static constexpr auto morleyMapperLayout(Dune::GeometryType type,
int gridDim)
611 assert(gridDim == 2);
616 if ((type.isTriangle()) )
630 using Node = MorleyNode<GridView, R>;
634 :
Base(gv, morleyMapperLayout)
635 , mapper_({gv, mcmgElementLayout()})
652 return Node{mapper_, data_};
661 unsigned short orientation = 0;
662 auto const& idSet =
gridView.grid().globalIdSet();
664 for (
const auto &element : elements(
gridView))
666 const auto &refElement = referenceElement(element);
667 auto elementIndex = mapper_.index(element);
671 for (std::size_t i = 0; i < element.subEntities(dim - 1); i++)
674 auto localV0 = refElement.subEntity(i, dim - 1, 0, dim);
675 auto localV1 = refElement.subEntity(i, dim - 1, 1, dim);
678 auto globalV0 = idSet.subId(element, localV0, dim);
679 auto globalV1 = idSet.subId(element, localV1, dim);
682 if ((localV0 < localV1 && globalV0 > globalV1)
683 || (localV0 > localV1 && globalV0 < globalV1))
685 orientation |= (1 << i);
688 data_[elementIndex] = orientation;
692 SubEntityMapper mapper_;
693 std::vector<std::bitset<3>> data_;
697 namespace BasisFactory
706 template<
class R =
double>
709 return [=](
auto const &gridView) {
710 return MorleyPreBasis<std::decay_t<
decltype(gridView)>, R>(gridView);
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
This file provides an implementation of the cubic Hermite finite element in 1 to 3 dimensions.
TrigonometricFunction< K, -cosFactor, sinFactor > derivative(const TrigonometricFunction< K, sinFactor, cosFactor > &f)
Obtain derivative of TrigonometricFunction function.
Definition: trigonometricfunction.hh:43
auto morley()
construct a PreBasisFactory for the Morley Finite Element
Definition: morleybasis.hh:707
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
GV GridView
The grid view that the FE basis is defined on.
Definition: morleybasis.hh:624
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