DUNE-FUNCTIONS (unstable)

argyrisbasis.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#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_ARGYRISBASIS_HH
7#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_ARGYRISBASIS_HH
8
9#include <algorithm>
10#include <array>
11
12#include <dune/common/exceptions.hh>
13#include <dune/common/fmatrix.hh>
14#include <dune/common/fvector.hh>
15#include <dune/common/rangeutilities.hh>
16
17#include <dune/grid/common/mcmgmapper.hh>
18
19#include <dune/localfunctions/common/localbasis.hh>
20#include <dune/localfunctions/common/localfiniteelementtraits.hh>
21#include <dune/localfunctions/common/localkey.hh>
22
23#include <dune/functions/analyticfunctions/monomialset.hh>
24#include <dune/functions/common/mapperutilities.hh>
26#include <dune/functions/functionspacebases/defaultglobalbasis.hh>
27#include <dune/functions/functionspacebases/functionaldescriptor.hh>
28#include <dune/functions/functionspacebases/leafprebasismappermixin.hh>
29#include <dune/functions/functionspacebases/nodes.hh>
30#include <dune/functions/functionspacebases/transformedfiniteelementmixin.hh>
31
45namespace Dune::Functions
46{
47
48 template<class GV, class R>
49 class ArgyrisPreBasis;
50
68 template<class GV, class R = double>
70
71 namespace Impl
72 {
73
76 class ArgyrisLocalCoefficients
77 {
78 public:
79 using size_type = std::size_t;
80 static constexpr int dim = 2;
81
82 ArgyrisLocalCoefficients()
83 {
84 for (unsigned int i = 0; i < 3; i++) // subentities: three vertices
85 for (unsigned int k = 0; k < 6; k++) // 6 basis functions per vertex
86 localKeys_[6 * i + k]
87 = LocalKey(i, dim, k); //(subentity, codim, number of dof for this subentity)
88 for (unsigned int i = 0; i < 3; ++i) // subentities: three edges
89 localKeys_[18 + i] = LocalKey(i, dim - 1, 0); // one node per edge
90 }
91
94 static constexpr size_type size()
95 {
96 return 21;
97 }
98
101 LocalKey const &localKey(size_type i) const
102 {
103 return localKeys_[i];
104 }
105
106 private:
107 std::array<Dune::LocalKey, 21> localKeys_;
108 };
109
110
116 template<class D, class R>
117 class ArgyrisReferenceLocalBasis
118 {
119 static constexpr int dim = 2;
120 public:
121 using Traits = H2LocalBasisTraits<D, dim, FieldVector<D, dim>, R, 1, FieldVector<R, 1>,
122 FieldMatrix<R, 1, dim>, FieldMatrix<R, dim, dim> >;
123 private:
124
139 static constexpr auto getArgyrisCoefficients()
140 {
141 // Define std::sqrt(2.) manually in double precision,
142 // because std::sqrt is not constexpr before C++26.
143 D sqrt2 = -8. * 1.414213562373095;
144 return Dune::FieldMatrix<D, 21,21>{
145 // vertex functionals
146 // l_0
147 {1, /*0th order*/
148 0, 0, /*1th order*/
149 0, 0, 0, /*2th order*/
150 -10, 0, 0, -10, /*3th order*/
151 15, 0, -30, 0, 15, /*4th order*/
152 -6, 0, 30, 30, 0, -6}, /*5th order*/
153 // l_1
154 {0,
155 1, 0,
156 0, 0, 0,
157 -6, 0, -11, 0,
158 8, 0, 10, 18, 0,
159 -3, 0, 1, -10, -8, 0},
160 // l_2, l_1 mirrored
161 {
162 0,
163 0, 1,
164 0, 0, 0,
165 0, -11, 0, -6,
166 0, 18, 10, 0, 8,
167 0, -8, -10, 1, 0, -3},
168 // l_3
169 {
170 0,
171 0, 0,
172 0.5, 0, 0,
173 -1.5, 0, 0, 0,
174 1.5, 0, -1.5, 0, 0,
175 -0.5, 0, 1.5, 1, 0, 0},
176 // l_4
177 {
178 0,
179 0, 0,
180 0, 1, 0,
181 0, -4, -4, 0,
182 0, 5, 10, 5, 0,
183 0, -2, -6, -6, -2, 0},
184 // l_5, l_3 mirrored
185 {
186 0,
187 0, 0,
188 0, 0, 0.5,
189 0, 0, 0, -1.5,
190 0, 0, -1.5, 0, 1.5,
191 0, 0, 1, 1.5, 0, -0.5},
192 // l_6
193 {0,
194 0, 0,
195 0, 0, 0,
196 10, 0, 0, 0,
197 -15, 0, 15, 0, 0,
198 6, 0, -15, -15, 0, 0},
199 // l_7
200 {0,
201 0, 0,
202 0, 0, 0,
203 -4, 0, 0, 0,
204 7, 0, -3.5, 0, 0,
205 -3, 0, 3.5, 3.5, 0, 0},
206 // l_8
207 {0,
208 0, 0,
209 0, 0, 0,
210 0, -5, 0, 0,
211 0, 14, 18.5, 0, 0,
212 0, -8, -18.5, -13.5, 0, 0},
213 // l_9
214 {
215 0,
216 0, 0,
217 0, 0, 0,
218 0.5, 0, 0, 0,
219 -1, 0, 0.25, 0, 0,
220 0.5, 0, -0.25, -0.25, 0, 0},
221 // l_10
222 {
223 0,
224 0, 0,
225 0, 0, 0,
226 0, 1, 0, 0,
227 0, -3, -3.5, 0, 0,
228 0, 2, 3.5, 2.5, 0, 0},
229 // l_11
230 {
231 0,
232 0, 0,
233 0, 0, 0,
234 0, 0, 0, 0,
235 0, 0, 1.25, 0, 0,
236 0, 0, -0.75, -1.25, 0, 0},
237 // l_12 mirrors l_6
238 {
239 0,
240 0, 0,
241 0, 0, 0,
242 0, 0, 0, 10,
243 0, 0, 15, 0, -15,
244 0, 0, -15, -15, 0, 6},
245 // l_13 mirrors l_8
246 {
247 0,
248 0, 0,
249 0, 0, 0,
250 0, 0, -5, 0,
251 0, 0, 18.5, 14, 0,
252 0, 0, -13.5, -18.5, -8, 0},
253 // l_14 mirrors l_7
254 {
255 0,
256 0, 0,
257 0, 0, 0,
258 0, 0, 0, -4,
259 0, 0, -3.5, 0, 7,
260 0, 0, 3.5, 3.5, 0, -3},
261 // l_15 mirrors l_11
262 {
263 0,
264 0, 0,
265 0, 0, 0,
266 0, 0, 0, 0,
267 0, 0, 1.25, 0, 0,
268 0, 0, -1.25, -0.75, 0, 0},
269 // l_16 mirrors l_10
270 {
271 0,
272 0, 0,
273 0, 0, 0,
274 0, 0, 1, 0,
275 0, 0, -3.5, -3, 0,
276 0, 0, 2.5, 3.5, 2, 0},
277 // l_17 mirrors l_9
278 {
279 0,
280 0, 0,
281 0, 0, 0,
282 0, 0, 0, 0.5,
283 0, 0, 0.25, 0, -1,
284 0, 0, -0.25, -0.25, 0, 0.5},
285 // edge functionals
286 // l_18
287 {
288 0,
289 0, 0,
290 0, 0, 0,
291 0, 16, 0, 0,
292 0, -32, -32, 0, 0,
293 0, 16, 32, 16, 0, 0},
294 // l_19
295 {
296 0,
297 0, 0,
298 0, 0, 0,
299 0, 0, -16, 0,
300 0, 0, 32, 32, 0,
301 0, 0, -16, -32, -16, 0},
302 // l_20
303 {
304 0,
305 0, 0,
306 0, 0, 0,
307 0, 0, 0, 0,
308 0, 0, -1. * sqrt2, 0, 0,
309 0, 0, sqrt2, sqrt2, 0, 0}};
310 }
311
312
313 static constexpr auto referenceBasisCoefficients = getArgyrisCoefficients();
314 static constexpr MonomialSet<typename Traits::RangeFieldType, dim, 5> monomials = {};
315
316 public:
317
320 static constexpr unsigned int size()
321 {
322 return ArgyrisLocalCoefficients::size();
323 }
324
327 static constexpr unsigned int order()
328 {
329 return 5;
330 }
331
337 void evaluateFunction(const typename Traits::DomainType &in,
338 std::vector<typename Traits::RangeType> &out) const
339 {
340 out.resize(size());
341 auto monomialValues = monomials(in);
342 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
343 }
344
350 void evaluateJacobian(const typename Traits::DomainType &in,
351 std::vector<typename Traits::JacobianType> &out) const
352 {
353 out.resize(size());
354 auto monomialValues = derivative(monomials)(in);
355 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
356 }
357
363 void evaluateHessian(const typename Traits::DomainType &in,
364 std::vector<typename Traits::HessianType> &out) const
365 {
366 out.resize(size());
367 auto monomialValues = derivative(derivative(monomials))(in);
368 multiplyWithCoefficentMatrix(referenceBasisCoefficients, monomialValues, out);
369 }
370
377 void partial(std::array<unsigned int, dim> order, const typename Traits::DomainType &in,
378 std::vector<typename Traits::RangeType> &out) const
379 {
380 out.resize(size());
381 auto totalOrder = std::accumulate(order.begin(), order.end(), 0);
382 if (totalOrder == 0)
383 evaluateFunction(in, out);
384 else if (totalOrder == 1)
385 {
386 evaluateJacobian(in,jacobiansBuffer_);
387 std::size_t which = std::max_element(order.begin(), order.end()) - order.begin();
388 for (auto i : Dune::range(size()))
389 out[i] = jacobiansBuffer_[i][0][which];
390 }
391 else if (totalOrder == 2)
392 {
393 evaluateHessian(in, hessianBuffer_);
394 std::size_t first, second;
395 first = std::max_element(order.begin(), order.end()) - order.begin();
396 if (order[first] == 2)
397 second = first;
398 else
399 {
400 order[first] = 0;
401 second = std::max_element(order.begin(), order.end()) - order.begin();
402 }
403 for (auto i : Dune::range(size()))
404 out[i] = hessianBuffer_[i][first][second];
405 }
406 else
407 DUNE_THROW(RangeError, "partial() not implemented for given order");
408 }
409
410 private:
411 mutable std::vector<typename Traits::JacobianType> jacobiansBuffer_;
412 mutable std::vector<typename Traits::HessianType> hessianBuffer_;
413 };
414
415
421 template<class D>
422 class ArgyrisLocalInterpolation
423 {
424 using size_type = std::size_t;
425 static constexpr int dim = 2;
426
427 static constexpr unsigned int size()
428 {
429 return ArgyrisLocalCoefficients::size();
430 }
431
432 using FunctionalDescriptor = Dune::Functions::Impl::FunctionalDescriptor<dim>;
433
434 public:
435
436 ArgyrisLocalInterpolation()
437 {
438 // first vertex
439 // function evaluation
440 descriptors_[0] = FunctionalDescriptor();
441 // gradient evaluations
442 descriptors_[1] = FunctionalDescriptor({1,0});
443 descriptors_[2] = FunctionalDescriptor({0,1});
444 // hessian evaluations
445 descriptors_[3] = FunctionalDescriptor({2,0});
446 descriptors_[4] = FunctionalDescriptor({1,1});
447 descriptors_[5] = FunctionalDescriptor({0,2});
448 // second vertex
449 descriptors_[6] = FunctionalDescriptor();
450 descriptors_[7] = FunctionalDescriptor({1,0});
451 descriptors_[8] = FunctionalDescriptor({0,1});
452 descriptors_[9] = FunctionalDescriptor({2,0});
453 descriptors_[10] = FunctionalDescriptor({1,1});
454 descriptors_[11] = FunctionalDescriptor({0,2});
455 // third vertex
456 descriptors_[12] = FunctionalDescriptor();
457 descriptors_[13] = FunctionalDescriptor({1,0});
458 descriptors_[14] = FunctionalDescriptor({0,1});
459 descriptors_[15] = FunctionalDescriptor({2,0});
460 descriptors_[16] = FunctionalDescriptor({1,1});
461 descriptors_[17] = FunctionalDescriptor({0,2});
462 // normal derivatives at edge midpoints
463 descriptors_[18] = FunctionalDescriptor(1);
464 descriptors_[19] = FunctionalDescriptor(1);
465 descriptors_[20] = FunctionalDescriptor(1);
466 }
467
470 template<class Element>
471 void bind( Element const& element, std::array<D, 3>const& averageVertexMeshSize, std::bitset<3>const& edgeOrientation)
472 {
473 averageVertexMeshSize_ = &averageVertexMeshSize;
474
475 auto geometry = element.geometry();
476
477 // get global Normals and midpoints
478 auto refElement = Dune::referenceElement<D, 2>(geometry.type());
479 for (std::size_t i = 0; i < 3; ++i)
480 {
481 localVertices_[i] = refElement.position(i, 2);
482
483 localMidpoints_[i] = refElement.position(i, 1);
484 std::size_t lower = (i == 2) ? 1 : 0;
485 std::size_t upper = (i == 0) ? 1 : 2;
486
487 auto edge = geometry.global(refElement.position(upper, 2))
488 - geometry.global(refElement.position(lower, 2));
489 // normalize and orient
490 edge /= edge.two_norm() * (edgeOrientation[i] ? -1. : 1.);
491 // Rotation by pi/2. Note that Kirby rotates by 3*pi/2
492 globalNormals_[i] = {-edge[1], edge[0]};
493 }
494 }
495
503 template<class F, class C>
504 void interpolate(F const& f, std::vector<C>& out) const
505 {
506 out.resize(size());
507 auto&& df = derivative(f);
508 auto&& Hf = derivative(df);
509
510 int offset = 0;
511 // iterate over vertices
512 for (int i = 0; i < 3; i++, offset += 6)
513 {
514 auto&& x = localVertices_[i];
515 auto derivativeValue = squeezeTensor(df(x));
516 auto hessianValue = squeezeTensor(Hf(x));
517 auto && h = (*averageVertexMeshSize_)[i];
518
519 out[offset ] = f(x);
520
521 out[offset + 1] = derivativeValue[0] * h;
522 out[offset + 2] = derivativeValue[1] * h;
523
524 out[offset + 3] = hessianValue[0][0] * h*h;
525 out[offset + 4] = hessianValue[0][1] * h*h;
526 out[offset + 5] = hessianValue[1][1] * h*h;
527 }
528 // iterate over edges
529 for (int i = 0; i < 3; i++)
530 out[18 + i] = squeezeTensor(df(localMidpoints_[i])).dot(globalNormals_[i]);
531
532 }
533
537 const FunctionalDescriptor& functionalDescriptor(size_type i) const
538 {
539 return descriptors_[i];
540 }
541
542 protected:
543 std::array<Dune::FieldVector<D, 2>, 3> globalNormals_;
544 std::array<Dune::FieldVector<D, 2>, 3> localMidpoints_;
545 std::array<Dune::FieldVector<D, 2>, 3> localVertices_;
546 std::array<D, 3> const* averageVertexMeshSize_;
547 std::array<FunctionalDescriptor, size()> descriptors_;
548 };
549
550 // TODO: There is a copy of this further up
551 template<class D, class R>
552 struct ArgyrisLocalBasisTraits
553 : public H2LocalBasisTraits<D, 2, Dune::FieldVector<D,2>, R, 1,
554 Dune::FieldVector<R,1>, Dune::FieldMatrix<R,1,2>, Dune::FieldMatrix<R,2,2> >
555 {};
556
566 template<class D, class R>
567 class ArgyrisLocalFiniteElement
568 : public Impl::TransformedFiniteElementMixin<ArgyrisLocalFiniteElement<D,R>, ArgyrisLocalBasisTraits<D, R> >
569 {
570 using Base = Impl::TransformedFiniteElementMixin< ArgyrisLocalFiniteElement<D,R>, ArgyrisLocalBasisTraits<D, R> >;
571 friend class Impl::TransformedLocalBasis<ArgyrisLocalFiniteElement<D,R>, ArgyrisLocalBasisTraits<D, R> >;
572 static constexpr int dim = 2;
573
574 public:
577 using size_type = std::size_t;
578 using Traits = LocalFiniteElementTraits<
579 Impl::TransformedLocalBasis<ArgyrisLocalFiniteElement<D,R>, ArgyrisLocalBasisTraits<D, R> >,
580 Impl::ArgyrisLocalCoefficients,
581 Impl::ArgyrisLocalInterpolation<D> >;
582
586 const typename Traits::LocalCoefficientsType &localCoefficients() const
587 {
588 return coefficients_;
589 }
590
593 const typename Traits::LocalInterpolationType &localInterpolation() const
594 {
595 return interpolation_;
596 }
597
600 static constexpr GeometryType type()
601 {
602 return GeometryTypes::simplex(dim);
603 }
604
607 static constexpr size_type size()
608 {
609 return Impl::ArgyrisLocalCoefficients::size();
610 }
611
614 template<class VertexMapper,class ElementMapper, class Element>
615 void bind(VertexMapper const& vertexMapper, std::vector<D> const& globalAverageVertexMeshSize,
616 ElementMapper const& elementMapper, std::vector<std::bitset<3> >const& edgeOrientations, Element const &e)
617 {
618 // Cache average mesh size for each vertex
619 for (auto i : range(dim+1))
620 averageVertexMeshSize_[i] = globalAverageVertexMeshSize[vertexMapper.subIndex(e, i, dim)];
621
622 // Cache orientation for each mesh
623 edgeOrientation_ = edgeOrientations[elementMapper.index(e)];
624
625 // Bind LocalInterpolation to updated local state
626 interpolation_.bind(e, averageVertexMeshSize_, edgeOrientation_);
627
628 // Compute local transformation matrices for each vertex
629 const auto& geometry = e.geometry();
630 const auto& refElement = ReferenceElements<typename Element::Geometry::ctype, dim>::simplex();
631 for (auto i : range(dim+1))
632 {
633 vertexJacobians_[i] = geometry.jacobian(refElement.position(i, dim));
634 }
635
636 // get geometrical information
637 std::array<FieldVector<R, 2>, 3> referenceTangents;
638
639 // get local and global Tangents
640 for (std::size_t i = 0; i < 3; ++i)
641 {
642 std::size_t lower = (i == 2) ? 1 : 0;
643 std::size_t upper = (i == 0) ? 1 : 2;
644 auto edge = refElement.position(upper, 2) - refElement.position(lower, 2);
645
646 // store normalized reference Tangent vectors
647 referenceTangents[i] = edge / edge.two_norm();
648
649 auto globalEdge = geometry.global(refElement.position(upper, 2))
650 - geometry.global(refElement.position(lower, 2));
651
652 // store length of global tangents and normalized global tangent vectors
653 l[i] = globalEdge.two_norm();
654 globalTangents[i] = globalEdge / l[i];
655
656 tau[i] = FieldVector<R, 3>{
657 globalTangents[i][0] * globalTangents[i][0],
658 2. * globalTangents[i][0] * globalTangents[i][1],
659 globalTangents[i][1] * globalTangents[i][1]
660 };
661
662 // The following variables are named as in Kirby's paper
663 // two g matrices
664 auto&& referenceG = FieldMatrix<R, 2, 2>{
665 {-referenceTangents[i][1], referenceTangents[i][0]},
666 {referenceTangents[i][0], referenceTangents[i][1]}
667 };
668
669 auto&& globalG = FieldMatrix<R, 2, 2>{
670 {-globalTangents[i][1], globalTangents[i][0]},
671 {globalTangents[i][0], globalTangents[i][1]}
672 };
673
674 //
675 b[i] = globalG * geometry.jacobian(refElement.position(i, 2)) * referenceG;
676
677 theta[i][0][0] = vertexJacobians_[i][0][0] * vertexJacobians_[i][0][0];
678 theta[i][0][1] = vertexJacobians_[i][0][0] * vertexJacobians_[i][0][1];
679 theta[i][0][2] = vertexJacobians_[i][0][1] * vertexJacobians_[i][0][1];
680
681 theta[i][1][0] = 2. * vertexJacobians_[i][0][0] * vertexJacobians_[i][1][0];
682 theta[i][1][1] = vertexJacobians_[i][0][0] * vertexJacobians_[i][1][1] + vertexJacobians_[i][0][1] * vertexJacobians_[i][1][0];
683 theta[i][1][2] = 2. * vertexJacobians_[i][0][1] * vertexJacobians_[i][1][1];
684
685 theta[i][2][0] = vertexJacobians_[i][1][0] * vertexJacobians_[i][1][0];
686 theta[i][2][1] = vertexJacobians_[i][1][0] * vertexJacobians_[i][1][1];
687 theta[i][2][2] = vertexJacobians_[i][1][1] * vertexJacobians_[i][1][1];
688 }
689 }
690
691 protected:
692
695 Impl::ArgyrisReferenceLocalBasis<D, R> const& referenceLocalBasis() const
696 {
697 return basis_;
698 }
699
704 template<class InputValues, class OutputValues>
705 void transform(InputValues const &inValues, OutputValues &outValues) const
706 {
707 using std::pow;
708 assert(inValues.size() == size());
709 assert(outValues.size() == inValues.size());
710 // compatibility with sympy code below
711 auto &[b_0, b_1, b_2] = b;
712 auto &[J_0, J_1, J_2] = vertexJacobians_;
713 auto &[theta_0, theta_1, theta_2] = theta;
714 auto & h = averageVertexMeshSize_;
715 auto & o = edgeOrientation_;
716 std::array<Dune::FieldVector<R, 2>, 3> const &t = globalTangents;
717 // This code is generated with sympy.
718 // It a matrix free implementation of the matrix V in Kirbys paper.
719 outValues[0] = -15.0/8.0*b_0[1][0]*inValues[18]/l[0] - 15.0/8.0*b_1[1][0]*inValues[19]/l[1] + inValues[0];
720 outValues[1] = (J_0[0][0]*inValues[1] + J_0[0][1]*inValues[2] - 0.4375*b_0[1][0]*inValues[18]*t[0][0] - 0.4375*b_1[1][0]*inValues[19]*t[1][0])/h[0];
721 outValues[2] = (J_0[1][0]*inValues[1] + J_0[1][1]*inValues[2] - 0.4375*b_0[1][0]*inValues[18]*t[0][1] - 0.4375*b_1[1][0]*inValues[19]*t[1][1])/h[0];
722 outValues[3] = (-1.0/32.0*b_0[1][0]*inValues[18]*l[0]*tau[0][0] - 1.0/32.0*b_1[1][0]*inValues[19]*l[1]*tau[1][0] + inValues[3]*theta_0[0][0] + inValues[4]*theta_0[0][1] + inValues[5]*theta_0[0][2])/h[0] /h[0];
723 outValues[4] = (-1.0/32.0*b_0[1][0]*inValues[18]*l[0]*tau[0][1] - 1.0/32.0*b_1[1][0]*inValues[19]*l[1]*tau[1][1] + inValues[3]*theta_0[1][0] + inValues[4]*theta_0[1][1] + inValues[5]*theta_0[1][2])/h[0] /h[0];
724 outValues[5] = (-1.0/32.0*b_0[1][0]*inValues[18]*l[0]*tau[0][2] - 1.0/32.0*b_1[1][0]*inValues[19]*l[1]*tau[1][2] + inValues[3]*theta_0[2][0] + inValues[4]*theta_0[2][1] + inValues[5]*theta_0[2][2])/h[0] /h[0];
725 outValues[6] = (15.0/8.0)*b_0[1][0]*inValues[18]/l[0] - 15.0/8.0*b_2[1][0]*inValues[20]/l[2] + inValues[6];
726 outValues[7] = (J_1[0][0]*inValues[7] + J_1[0][1]*inValues[8] - 0.4375*b_0[1][0]*inValues[18]*t[0][0] - 0.4375*b_2[1][0]*inValues[20]*t[2][0])/h[1];
727 outValues[8] = (J_1[1][0]*inValues[7] + J_1[1][1]*inValues[8] - 0.4375*b_0[1][0]*inValues[18]*t[0][1] - 0.4375*b_2[1][0]*inValues[20]*t[2][1])/h[1];
728 outValues[9] = ((1.0/32.0)*b_0[1][0]*inValues[18]*l[0]*tau[0][0] - 1.0/32.0*b_2[1][0]*inValues[20]*l[2]*tau[2][0] + inValues[9]*theta_1[0][0] + inValues[10]*theta_1[0][1] + inValues[11]*theta_1[0][2])/h[1] /h[1];
729 outValues[10] = ((1.0/32.0)*b_0[1][0]*inValues[18]*l[0]*tau[0][1] - 1.0/32.0*b_2[1][0]*inValues[20]*l[2]*tau[2][1] + inValues[9]*theta_1[1][0] + inValues[10]*theta_1[1][1] + inValues[11]*theta_1[1][2])/h[1] /h[1];
730 outValues[11] = ((1.0/32.0)*b_0[1][0]*inValues[18]*l[0]*tau[0][2] - 1.0/32.0*b_2[1][0]*inValues[20]*l[2]*tau[2][2] + inValues[9]*theta_1[2][0] + inValues[10]*theta_1[2][1] + inValues[11]*theta_1[2][2])/h[1] /h[1];
731 outValues[12] = (15.0/8.0)*b_1[1][0]*inValues[19]/l[1] + (15.0/8.0)*b_2[1][0]*inValues[20]/l[2] + inValues[12];
732 outValues[13] = (J_2[0][0]*inValues[13] + J_2[0][1]*inValues[14] - 0.4375*b_1[1][0]*inValues[19]*t[1][0] - 0.4375*b_2[1][0]*inValues[20]*t[2][0])/h[2];
733 outValues[14] = (J_2[1][0]*inValues[13] + J_2[1][1]*inValues[14] - 0.4375*b_1[1][0]*inValues[19]*t[1][1] - 0.4375*b_2[1][0]*inValues[20]*t[2][1])/h[2];
734 outValues[15] = ((1.0/32.0)*b_1[1][0]*inValues[19]*l[1]*tau[1][0] + (1.0/32.0)*b_2[1][0]*inValues[20]*l[2]*tau[2][0] + inValues[15]*theta_2[0][0] + inValues[16]*theta_2[0][1] + inValues[17]*theta_2[0][2])/h[2] /h[2];
735 outValues[16] = ((1.0/32.0)*b_1[1][0]*inValues[19]*l[1]*tau[1][1] + (1.0/32.0)*b_2[1][0]*inValues[20]*l[2]*tau[2][1] + inValues[15]*theta_2[1][0] + inValues[16]*theta_2[1][1] + inValues[17]*theta_2[1][2])/h[2] /h[2];
736 outValues[17] = ((1.0/32.0)*b_1[1][0]*inValues[19]*l[1]*tau[1][2] + (1.0/32.0)*b_2[1][0]*inValues[20]*l[2]*tau[2][2] + inValues[15]*theta_2[2][0] + inValues[16]*theta_2[2][1] + inValues[17]*theta_2[2][2])/h[2] /h[2];
737 outValues[18] = b_0[0][0]*inValues[18]*(o[0] ? -1 : 1);
738 outValues[19] = b_1[0][0]*inValues[19]*(o[1] ? -1 : 1);
739 outValues[20] = b_2[0][0]*inValues[20]*(o[2] ? -1 : 1);
740 }
741
742 private:
743 typename Impl::ArgyrisReferenceLocalBasis<D, R> basis_;
744 typename Traits::LocalCoefficientsType coefficients_;
745 typename Traits::LocalInterpolationType interpolation_;
746 // the transformation to correct the lack of affine equivalence boils down to
747 // matrix without blockstructure, because the normal derivative dofs interact nontrivially
748 // with the others, for details see Kirby's paper.
749 // The following geometric information is needed
750 // the jacobians per vertex
751 std::array<Dune::FieldMatrix<R, dim, dim>, dim+1> vertexJacobians_;
752 // a three by three matrix per vertex formalizing the rotation of the hessian in voigt notation
753 std::array<FieldMatrix<R, 3, 3>, 3> theta;
754 // the edge lengths
755 FieldVector<R, 3> l;
756 // the global tangent vectors (normalized)
757 std::array<FieldVector<R, 2>, 3> globalTangents;
758 // Geometric quantities without trivial meaning
759 std::array<FieldVector<R, 3>, 3> tau;
760 std::array<FieldMatrix<R, 2, 2>, 3> b;
761 // Additionally, we collect some global information
762 // the local state, i.e. a collection of global information restricted to this element
763 std::array<D, dim+1> averageVertexMeshSize_;
764 std::bitset<3> edgeOrientation_;
765
766 };
767
768 } // end namespace Impl
769
770
771
772 // *****************************************************************************
773 // This is the reusable part of the basis. It contains
774 //
775 // ArgyrisPreBasis
776 // ArgyrisNode
777 //
778 // The pre-basis allows to create the others and is the owner of possible shared
779 // state. These components do _not_ depend on the global basis and local view
780 // and can be used without a global basis.
781 // *****************************************************************************
782
783 template<class GV, class R>
784 class ArgyrisNode
785 : public LeafBasisNode
786 {
787 using Mapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
788
789 public:
790 using size_type = std::size_t;
791 using Element = typename GV::template Codim<0>::Entity;
792 using FiniteElement = typename Impl::ArgyrisLocalFiniteElement<typename GV::ctype, R>;
793
794 ArgyrisNode(Mapper const& vertexMapper, Mapper const& elementMapper,
795 std::vector<typename GV::ctype> const& averageVertexMeshSize,
796 std::vector<std::bitset<3> > const& edgeOrientation)
797 : element_(nullptr)
798 , vertexMapper_(&vertexMapper)
799 , elementMapper_(&elementMapper)
800 , averageVertexMeshSize_(&averageVertexMeshSize)
801 , edgeOrientation_(&edgeOrientation)
802 {}
803
805 Element const &element() const
806 {
807 return *element_;
808 }
809
815 FiniteElement const &finiteElement() const
816 {
817 return finiteElement_;
818 }
819
821 void bind(Element const &e)
822 {
823 element_ = &e;
824 finiteElement_.bind(*vertexMapper_, *averageVertexMeshSize_,
825 *elementMapper_,* edgeOrientation_,
826 *element_ );
827 this->setSize(finiteElement_.size());
828
829 }
830
832 unsigned int order() const { return finiteElement_.localBasis().order(); }
833
834 protected:
835 FiniteElement finiteElement_;
836 Element const* element_;
837 Mapper const* vertexMapper_;
838 Mapper const* elementMapper_;
839 std::vector<typename GV::ctype> const* averageVertexMeshSize_;
840 std::vector<std::bitset<3> > const* edgeOrientation_;
841 };
842
843
853 template<class GV, class R>
855 : public LeafPreBasisMapperMixin<GV>
856 {
858 using SubEntityMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GV>;
859 using Element = typename GV::template Codim<0>::Entity;
860 using D = typename GV::ctype;
861 static const std::size_t dim = GV::dimension;
862
863 // helper methods to assign each subentity the number of dofs. Used by the LeafPreBasisMapperMixin.
864 static constexpr auto ArgyrisMapperLayout(Dune::GeometryType type, int gridDim)
865 {
866 assert(gridDim == 2);
867 if (type.isVertex())
868 return 6; // one evaluation dof and two derivative dofs and three hessian dofs per vertex
869 else if (type.isLine())
870 return 1;
871 else if (type.isTriangle())
872 return 0;
873 else
874 DUNE_THROW(Dune::Exception, "Invalid Geometry type for Argyris Element!");
875
876 }
877
878 public:
880 using GridView = GV;
881
883 using size_type = std::size_t;
884
886 using Node = ArgyrisNode<GridView, R>;
887
888 public:
889
891 ArgyrisPreBasis(const GV &gv)
892 : Base(gv, ArgyrisMapperLayout)
893 , vertexMapper_({gv, mcmgVertexLayout()})
894 , elementMapper_({gv, mcmgElementLayout()})
895 {
896 averageVertexMeshSize_ = Impl::computeAverageSubEntityMeshSize<D>(vertexMapper_);
897 edgeOrientations_ = Impl::computeEdgeOrientations(elementMapper_);
898 }
899
901 void update(GridView const &gv)
902 {
903 Base::update(gv);
904 vertexMapper_.update(this->gridView());
905 elementMapper_.update(this->gridView());
906 averageVertexMeshSize_ = Impl::computeAverageSubEntityMeshSize<D>(vertexMapper_);
907 edgeOrientations_ = Impl::computeEdgeOrientations(elementMapper_);
908 }
909
912 {
913 return Node{vertexMapper_, elementMapper_, averageVertexMeshSize_, edgeOrientations_};
914 }
915
916 protected:
917
918 SubEntityMapper vertexMapper_;
919 std::vector<D> averageVertexMeshSize_;
920 SubEntityMapper elementMapper_;
921 std::vector<std::bitset<3> > edgeOrientations_;
922
923 }; // class ArgyrisPreBasis
924
925 namespace BasisFactory
926 {
927
935 template<class R = double>
936 auto argyris()
937 {
938 return [=](auto const &gridView) {
939 return ArgyrisPreBasis<std::decay_t<decltype(gridView)>, R>(gridView);
940 };
941 }
942
943 } // end namespace BasisFactory
944
945
946} // end namespace Dune::Functions
947
948#endif
A pre-basis for a Argyrisbasis.
Definition: argyrisbasis.hh:856
Node makeNode() const
Create tree node.
Definition: argyrisbasis.hh:911
GV GridView
The grid view that the FE basis is defined on.
Definition: argyrisbasis.hh:880
ArgyrisNode< GridView, R > Node
Template mapping root tree path to type of created tree node.
Definition: argyrisbasis.hh:886
void update(GridView const &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: argyrisbasis.hh:901
ArgyrisPreBasis(const GV &gv)
Constructor for a given grid view object.
Definition: argyrisbasis.hh:891
std::size_t size_type
Type used for indices and size information.
Definition: argyrisbasis.hh:883
Global basis for given pre-basis.
Definition: defaultglobalbasis.hh:53
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
void update(const GridView &gv)
Update the stored GridView.
Definition: leafprebasismappermixin.hh:101
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
Function, which evaluates all monomials up to degree maxDegree in a given coordinate.
Definition: monomialset.hh:64
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jan 9, 23:34, 2026)