3 #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_CUBICHERMITEBASIS_HH
4 #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_CUBICHERMITEBASIS_HH
6 #include <dune/common/exceptions.hh>
7 #include <dune/common/tuplevector.hh>
9 #include <dune/grid/common/capabilities.hh>
10 #include <dune/grid/common/mcmgmapper.hh>
11 #include <dune/grid/common/rangegenerators.hh>
13 #include <dune/localfunctions/common/localfiniteelementvariant.hh>
14 #include <dune/localfunctions/rannacherturek.hh>
15 #include <dune/localfunctions/crouzeixraviart.hh>
17 #include <dune/functions/functionspacebases/nodes.hh>
18 #include <dune/functions/functionspacebases/defaultglobalbasis.hh>
19 #include <dune/functions/functionspacebases/leafprebasismappermixin.hh>
32 template<
class Gr
idView>
33 auto subIndexSet(
const Dune::MultipleCodimMultipleGeomTypeMapper<GridView>& mapper,
const typename GridView::template Codim<0>::Entity& element)
35 using Mapper = Dune::MultipleCodimMultipleGeomTypeMapper<GridView>;
36 using Index =
typename Mapper::Index;
37 constexpr
auto dimension = GridView::dimension;
38 auto subIndices = std::vector<Index>();
39 auto referenceElement = Dune::referenceElement<double, dimension>(element.type());
40 for(
auto codim : Dune::range(dimension+1))
42 for(
auto subEntity : Dune::range(referenceElement.size(codim)))
44 std::size_t c = mapper.layout()(referenceElement.type(subEntity, codim), dimension);
47 std::size_t firstIndex = mapper.subIndex(element, subEntity, codim);
48 for(
auto j : Dune::range(firstIndex, firstIndex+c))
50 subIndices.push_back(j);
62 template<
class Mapper>
63 auto computeAverageSubEntityMeshSize(
const Mapper& mapper)
65 constexpr
auto dimension = Mapper::GridView::dimension;
67 std::vector<unsigned int> adjacentElements(mapper.size(), 0);
68 std::vector<double> subEntityMeshSize(mapper.size(), 0.0);
69 for(
const auto& element : Dune::elements(mapper.gridView()))
71 auto A = element.geometry().volume();
72 for(
auto i : Impl::subIndexSet(mapper, element))
74 subEntityMeshSize[i] += A;
75 ++(adjacentElements[i]);
78 for(
auto i : Dune::range(mapper.size()))
79 subEntityMeshSize[i] = std::pow(subEntityMeshSize[i]/adjacentElements[i], 1./dimension);
80 return subEntityMeshSize;
91 static constexpr
auto evaluateMonomialValues(
const Dune::FieldVector<K,1>& x)
93 using Range = Dune::FieldVector<K,1>;
94 constexpr std::size_t maxOrder=3;
95 constexpr std::size_t size = (maxOrder+1);
96 auto xPowers = std::array<double,maxOrder+1>{};
98 for(
auto k: Dune::range(maxOrder))
99 xPowers[k+1] = xPowers[k]*x[0];
100 auto y = Dune::FieldVector<Range,size>{};
101 for(
auto order : Dune::range(maxOrder+1))
102 y[order] = xPowers[order];
108 static constexpr
auto evaluateMonomialJacobians(
const Dune::FieldVector<K,1>& x)
110 using Jacobian = Dune::FieldMatrix<K,1,1>;
111 constexpr std::size_t maxOrder=3;
112 constexpr std::size_t size = (maxOrder+1);
113 auto xPowers = std::array<double,maxOrder+1>{};
115 for(
auto k: Dune::range(maxOrder))
116 xPowers[k+1] = xPowers[k]*x[0];
117 auto y = Dune::FieldVector<Jacobian,size>{};
118 for(
auto order : Dune::range(std::size_t(1), maxOrder+1))
119 y[order][0][2] = order*xPowers[order-1];
125 static constexpr
auto evaluateMonomialValues(
const Dune::FieldVector<K,2>& x)
127 using Range = Dune::FieldVector<K,1>;
128 constexpr std::size_t maxOrder=3;
129 constexpr std::size_t dim=2;
130 constexpr std::size_t size = (maxOrder+1)*(maxOrder+2)/2;
131 auto xPowers = std::array<std::array<double,maxOrder+1>,dim>{};
132 for(
auto j: Dune::range(dim))
135 for(
auto k: Dune::range(maxOrder))
136 xPowers[j][k+1] = xPowers[j][k]*x[j];
138 auto y = Dune::FieldVector<Range,size>{};
140 for(
auto order : Dune::range(maxOrder+1))
142 for(
auto k : Dune::range(order+1))
144 y[index] = xPowers[0][order-k]*xPowers[1][k];
153 static constexpr
auto evaluateMonomialJacobians(
const Dune::FieldVector<K,2>& x)
155 using Jacobian = Dune::FieldMatrix<K,1,2>;
156 constexpr std::size_t maxOrder=3;
157 constexpr std::size_t dim=2;
158 constexpr std::size_t size = (maxOrder+1)*(maxOrder+2)/2;
159 auto xPowers = std::array<std::array<double,maxOrder+1>,dim>{};
160 for(
auto j: Dune::range(dim))
163 for(
auto k: Dune::range(maxOrder))
164 xPowers[j][k+1] = xPowers[j][k]*x[j];
166 auto y = Dune::FieldVector<Jacobian,size>{};
168 for(
auto order : Dune::range(maxOrder+1))
170 for(
auto k : Dune::range(order+1))
173 y[index][0][0] = (order-k)*xPowers[0][order-k-1]*xPowers[1][k];
175 y[index][0][1] = k*xPowers[0][order-k]*xPowers[1][k-1];
190 template<
class DF,
class RF,
unsigned int dim,
bool reduced>
191 class CubicHermiteLocalBasis
194 static constexpr
auto makeReferenceBasisCoefficients() {
195 if constexpr (dim==1)
196 return
Dune::FieldMatrix<
int,4,4>{
202 if constexpr ((dim==2) and (not reduced))
203 return Dune::FieldMatrix<int,10,10>{
204 { 1, 0, 0, -3, -13, -3, 2, 13, 13, 2},
205 { 0, 1, 0, -2, -3, 0, 1, 3, 2, 0},
206 { 0, 0, 1, 0, -3, -2, 0, 2, 3, 1},
207 { 0, 0, 0, 3, -7, 0, -2, 7, 7, 0},
208 { 0, 0, 0, -1, 2, 0, 1, -2, -2, 0},
209 { 0, 0, 0, 0, -1, 0, 0, 2, 1, 0},
210 { 0, 0, 0, 0, -7, 3, 0, 7, 7, -2},
211 { 0, 0, 0, 0, -1, 0, 0, 1, 2, 0},
212 { 0, 0, 0, 0, 2, -1, 0, -2, -2, 1},
213 { 0, 0, 0, 0, 27, 0, 0, -27, -27, 0}
215 if constexpr ((dim==2) and (reduced))
217 auto w = std::array{1./3, 1./18, 1./18, 1./3, -1./9, 1./18, 1./3, 1./18, -1./9};
218 return Dune::FieldMatrix<double,9,10>{
219 { 1, 0, 0, -3, -13 + w[0]*27, -3, 2, 13 - w[0]*27, 13 - w[0]*27, 2},
220 { 0, 1, 0, -2, -3 + w[1]*27, 0, 1, 3 - w[1]*27, 2 - w[1]*27, 0},
221 { 0, 0, 1, 0, -3 + w[2]*27, -2, 0, 2 - w[2]*27, 3 - w[2]*27, 1},
222 { 0, 0, 0, 3, -7 + w[3]*27, 0, -2, 7 - w[3]*27, 7 - w[3]*27, 0},
223 { 0, 0, 0, -1, 2 + w[4]*27, 0, 1, -2 - w[4]*27, -2 - w[4]*27, 0},
224 { 0, 0, 0, 0, -1 + w[5]*27, 0, 0, 2 - w[5]*27, 1 - w[5]*27, 0},
225 { 0, 0, 0, 0, -7 + w[6]*27, 3, 0, 7 - w[6]*27, 7 - w[6]*27, -2},
226 { 0, 0, 0, 0, -1 + w[7]*27, 0, 0, 1 - w[7]*27, 2 - w[7]*27, 0},
227 { 0, 0, 0, 0, 2 + w[8]*27, -1, 0, -2 - w[8]*27, -2 - w[8]*27, 1},
243 static constexpr
auto referenceBasisCoefficients = makeReferenceBasisCoefficients();
251 template<
class LambdaRefValues,
class Entry>
252 void transformToElementBasis(
const LambdaRefValues& refValues, std::vector<Entry>& out)
const
254 if constexpr (dim==1)
256 const auto& J = elementJacobian_;
257 out.resize(refValues.size());
258 out[0] = refValues[0];
259 out[1] = J*refValues[1] / (*localSubEntityMeshSize_)[1];
260 out[2] = refValues[2];
261 out[3] = J*refValues[3] / (*localSubEntityMeshSize_)[1];;
263 if constexpr (dim==2)
265 const auto& J = elementJacobian_;
266 out.resize(refValues.size());
267 out[0] = refValues[0];
268 out[1] = (J[0][0]*refValues[1] + J[0][1]*refValues[2]) / (*localSubEntityMeshSize_)[1];
269 out[2] = (J[1][0]*refValues[1] + J[1][1]*refValues[2]) / (*localSubEntityMeshSize_)[2];
270 out[3] = refValues[3];
271 out[4] = (J[0][0]*refValues[4] + J[0][1]*refValues[5]) / (*localSubEntityMeshSize_)[4];
272 out[5] = (J[1][0]*refValues[4] + J[1][1]*refValues[5]) / (*localSubEntityMeshSize_)[5];
273 out[6] = refValues[6];
274 out[7] = (J[0][0]*refValues[7] + J[0][1]*refValues[8]) / (*localSubEntityMeshSize_)[7];
275 out[8] = (J[1][0]*refValues[7] + J[1][1]*refValues[8]) / (*localSubEntityMeshSize_)[8];
276 if constexpr (not reduced)
277 out[9] = refValues[9];
281 using ElementJacobian = Dune::FieldMatrix<DF, dim,dim>;
283 using LocalSubEntityMeshSize = std::vector<double>;
287 using Domain = Dune::FieldVector<DF, dim>;
288 using Range = Dune::FieldVector<RF, 1>;
289 using Jacobian = Dune::FieldMatrix<RF, 1, dim>;
290 using Traits = Dune::LocalBasisTraits<DF, dim, Domain, RF, 1, Range, Jacobian>;
291 using OrderArray = std::array<unsigned int, dim>;
293 static constexpr
unsigned int size()
295 return decltype(referenceBasisCoefficients)::rows;
298 inline void evaluateFunction(
const Domain& x, std::vector<Range>& values)
const
300 auto monomialValues = evaluateMonomialValues(x);
301 auto referenceValues = Dune::FieldVector<Range, size()>{};
302 referenceBasisCoefficients.mv(monomialValues, referenceValues);
303 transformToElementBasis(referenceValues, values);
306 inline void evaluateJacobian(
const Domain& x, std::vector<Jacobian>& jacobians)
const
308 auto monomialJacobians = evaluateMonomialJacobians(x);
309 auto referenceJacobians = Dune::FieldVector<Jacobian, size()>{};
310 referenceBasisCoefficients.mv(monomialJacobians, referenceJacobians);
311 transformToElementBasis(referenceJacobians, jacobians);
314 void partial(
const OrderArray& order,
const Domain& x, std::vector<Range>& out)
const
316 auto totalOrder = std::accumulate(order.begin(), order.end(), 0);
318 evaluateFunction(x, out);
319 DUNE_THROW(RangeError,
"partial() not implemented for given order");
322 unsigned int order()
const
327 template<
class Element>
328 void bind(
const Element& element,
const LocalSubEntityMeshSize& localSubEntityMeshSize) {
329 localSubEntityMeshSize_ = &localSubEntityMeshSize;
330 auto center = Dune::ReferenceElements<DF, dim>::simplex().position(0, 0);
331 elementJacobian_ = element.geometry().jacobian(center);
335 ElementJacobian elementJacobian_;
336 const LocalSubEntityMeshSize* localSubEntityMeshSize_;
341 template<
unsigned int dim,
bool reduced>
342 struct CubicHermiteLocalCoefficients
345 static constexpr
auto makeLocalKeys() {
346 if constexpr (dim==1)
353 if constexpr ((dim==2) and (not reduced))
366 if constexpr ((dim==2) and (reduced))
380 using LocalKeys = std::decay_t<decltype(makeLocalKeys())>;
384 std::size_t size()
const
386 return localKeys_.size();
389 const LocalKey& localKey(std::size_t i)
const
391 assert( i < localKeys_.size() );
392 return localKeys_[i];
395 LocalKeys localKeys_ = makeLocalKeys();
400 template<
class DF,
class RF,
unsigned int dim,
bool reduced>
401 class CubicHermiteLocalInterpolation
403 using ElementJacobianInverse = Dune::FieldMatrix<DF, dim,dim>;
404 using LocalSubEntityMeshSize = std::vector<double>;
408 template<
class Element>
409 void bind(
const Element& element,
const LocalSubEntityMeshSize& localSubEntityMeshSize) {
410 localSubEntityMeshSize_ = &localSubEntityMeshSize;
413 template<
class F,
class C>
414 void interpolate(
const F& f, std::vector<C>& out)
const
416 using Domain = Dune::FieldVector<DF, dim>;
418 if constexpr (dim==1)
422 out[1] = df(0) * (*localSubEntityMeshSize_)[1];
424 out[3] = df(1) * (*localSubEntityMeshSize_)[3];
426 if constexpr (dim==2)
428 if constexpr (not reduced)
431 out[9] = f(Domain({1.0/3.0,1.0/3.0}));
433 if constexpr (reduced)
435 auto J0 = df(Domain({0,0}));
436 auto J1 = df(Domain({1,0}));
437 auto J2 = df(Domain({0,1}));
438 out[0] = f(Domain({0,0}));
439 out[1] = J0[0][0] * (*localSubEntityMeshSize_)[1];
440 out[2] = J0[0][1] * (*localSubEntityMeshSize_)[2];
441 out[3] = f(Domain({1,0}));
442 out[4] = J1[0][0] * (*localSubEntityMeshSize_)[4];
443 out[5] = J1[0][1] * (*localSubEntityMeshSize_)[5];
444 out[6] = f(Domain({0,1}));
445 out[7] = J2[0][0] * (*localSubEntityMeshSize_)[7];
446 out[8] = J2[0][1] * (*localSubEntityMeshSize_)[8];
450 const LocalSubEntityMeshSize* localSubEntityMeshSize_;
462 template<
class DF,
class RF,
unsigned int dim,
bool reduced>
463 class CubicHermiteLocalFiniteElement
465 using LocalBasis = CubicHermiteLocalBasis<DF, RF, dim, reduced>;
466 using LocalCoefficients = CubicHermiteLocalCoefficients<dim, reduced>;
467 using LocalInterpolation = CubicHermiteLocalInterpolation<DF, RF, dim, reduced>;
468 using LocalSubEntityMeshSize = std::vector<double>;
472 using Traits = LocalFiniteElementTraits<LocalBasis, LocalCoefficients, LocalInterpolation>;
474 const LocalBasis& localBasis()
const {
478 const LocalCoefficients& localCoefficients()
const {
479 return localCoefficients_;
482 const LocalInterpolation& localInterpolation()
const {
483 return localInterpolation_;
486 unsigned int size()
const {
487 return localBasis_.size();
490 GeometryType type()
const {
494 template<
class Element,
class Mapper,
class MeshSizeContainer>
495 void bind(
const Element& element,
const Mapper& mapper,
const MeshSizeContainer& subEntityMeshSize) {
497 localSubEntityMeshSize_.resize(localCoefficients_.size());
498 for(
auto i : Dune::range(size()))
500 auto localKey = localCoefficients_.localKey(i);
501 auto subEntityIndex = mapper.subIndex(element, localKey.subEntity(), localKey.codim());
502 localSubEntityMeshSize_[i] = subEntityMeshSize[subEntityIndex];
505 localBasis_.bind(element, localSubEntityMeshSize_);
506 localInterpolation_.bind(element, localSubEntityMeshSize_);
507 type_ = element.type();
511 LocalSubEntityMeshSize localSubEntityMeshSize_;
512 LocalBasis localBasis_;
513 LocalCoefficients localCoefficients_;
514 LocalInterpolation localInterpolation_;
536 template<
typename GV,
bool reduced>
537 class CubicHermiteNode :
540 static const int gridDim = GV::dimension;
542 using CubeFiniteElement = Impl::CubicHermiteLocalFiniteElement<typename GV::ctype, double, gridDim, reduced>;
543 using SubEntityMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
544 using Base = LeafBasisNode;
548 using size_type = std::size_t;
549 using Element =
typename GV::template Codim<0>::Entity;
550 using FiniteElement = CubeFiniteElement;
553 CubicHermiteNode(
const SubEntityMapper& subEntityMapper,
const std::vector<double>& subEntityMeshSize) :
556 subEntityMapper_(&subEntityMapper),
557 subEntityMeshSize_(&subEntityMeshSize)
561 const Element& element()
const
570 const FiniteElement& finiteElement()
const
572 return finiteElement_;
576 void bind(
const Element& e)
579 finiteElement_.bind(*element_, *subEntityMapper_, *subEntityMeshSize_);
580 this->setSize(finiteElement_.size());
585 FiniteElement finiteElement_;
586 const Element* element_;
587 const SubEntityMapper* subEntityMapper_;
588 const std::vector<double>* subEntityMeshSize_;
600 template<
typename GV,
bool reduced = false>
605 using SubEntityMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
607 static constexpr
auto cubicHermiteMapperLayout(Dune::GeometryType type,
int gridDim) {
610 if ((type.isTriangle()) and (not reduced))
616 static constexpr
auto subEntityLayout(Dune::GeometryType type,
int gridDim) {
617 return (cubicHermiteMapperLayout(type, gridDim) > 0);
623 using Node = CubicHermiteNode<GridView, reduced>;
626 Base(gv, cubicHermiteMapperLayout),
627 subEntityMapper_(gv, subEntityLayout)
629 static_assert(GridView::dimension<=2,
"CubicHermitePreBasis is only implemented for dim<=2");
630 subEntityMeshSize_ = Impl::computeAverageSubEntityMeshSize(subEntityMapper_);
636 subEntityMapper_.update(gv);
637 subEntityMeshSize_ = Impl::computeAverageSubEntityMeshSize(subEntityMapper_);
640 Node makeNode()
const
642 return Node{subEntityMapper_, subEntityMeshSize_};
646 std::vector<double> subEntityMeshSize_;
647 SubEntityMapper subEntityMapper_;
652 namespace BasisFactory {
659 template<
class Dummy=
void>
662 return [](
const auto& gridView) {
672 template<
class Dummy=
void>
675 return [](
const auto& gridView) {
691 template<
typename GV>
702 template<
typename GV>
Pre-basis for a CubicHermite basis.
Definition: cubichermitebasis.hh:602
Global basis for given pre-basis.
Definition: defaultglobalbasis.hh:46
A generic MixIn class for PreBasis with flat indices computed from a mapper.
Definition: leafprebasismappermixin.hh:58
void update(const GridView &gv)
Update the stored GridView.
Definition: leafprebasismappermixin.hh:97
GV GridView
Type of the associated GridView.
Definition: leafprebasismappermixin.hh:64
TrigonometricFunction< K, -cosFactor, sinFactor > derivative(const TrigonometricFunction< K, sinFactor, cosFactor > &f)
Obtain derivative of TrigonometricFunction function.
Definition: trigonometricfunction.hh:39
auto cubicHermite()
Create a pre-basis factory that can create a CubicHermite pre-basis.
Definition: cubichermitebasis.hh:660
auto reducedCubicHermite()
Create a pre-basis factory that can create a CubicHermite pre-basis.
Definition: cubichermitebasis.hh:673
Definition: polynomial.hh:13