DUNE PDELab (2.7)

lagrangecube.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_LOCALFUNCTIONS_LAGRANGE_LAGRANGECUBE_HH
4#define DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGECUBE_HH
5
6#include <array>
7#include <numeric>
8
11#include <dune/common/math.hh>
12
13#include <dune/geometry/referenceelements.hh>
14
15#include <dune/localfunctions/common/localbasis.hh>
16#include <dune/localfunctions/common/localfiniteelementtraits.hh>
17#include <dune/localfunctions/common/localinterpolation.hh>
18#include <dune/localfunctions/common/localkey.hh>
19
20namespace Dune { namespace Impl
21{
22 // Forward declaration
23 template<class LocalBasis>
24 class LagrangeCubeLocalInterpolation;
25
36 template<class D, class R, unsigned int dim, unsigned int k>
37 class LagrangeCubeLocalBasis
38 {
39 friend class LagrangeCubeLocalInterpolation<LagrangeCubeLocalBasis<D,R,dim,k> >;
40
41 // i-th Lagrange polynomial of degree k in one dimension
42 static R p(unsigned int i, D x)
43 {
44 R result(1.0);
45 for (unsigned int j=0; j<=k; j++)
46 if (j!=i) result *= (k*x-j)/((int)i-(int)j);
47 return result;
48 }
49
50 // derivative of ith Lagrange polynomial of degree k in one dimension
51 static R dp(unsigned int i, D x)
52 {
53 R result(0.0);
54
55 for (unsigned int j=0; j<=k; j++)
56 {
57 if (j!=i)
58 {
59 R prod( (k*1.0)/((int)i-(int)j) );
60 for (unsigned int l=0; l<=k; l++)
61 if (l!=i && l!=j)
62 prod *= (k*x-l)/((int)i-(int)l);
63 result += prod;
64 }
65 }
66 return result;
67 }
68
69 // Second derivative of j-th Lagrange polynomial of degree k in one dimension
70 // Formula and notation taken from https://en.wikipedia.org/wiki/Lagrange_polynomial#Derivatives
71 static R ddp(unsigned int j, D x)
72 {
73 R result(0.0);
74
75 for (unsigned int i=0; i<=k; i++)
76 {
77 if (i==j)
78 continue;
79
80 R sum(0);
81
82 for (unsigned int m=0; m<=k; m++)
83 {
84 if (m==i || m==j)
85 continue;
86
87 R prod( (k*1.0)/((int)j-(int)m) );
88 for (unsigned int l=0; l<=k; l++)
89 if (l!=i && l!=j && l!=m)
90 prod *= (k*x-l)/((int)j-(int)l);
91 sum += prod;
92 }
93
94 result += sum * ( (k*1.0)/((int)j-(int)i) );
95 }
96
97 return result;
98 }
99
100 // Return i as a d-digit number in the (k+1)-nary system
101 static std::array<unsigned int,dim> multiindex (unsigned int i)
102 {
103 std::array<unsigned int,dim> alpha;
104 for (unsigned int j=0; j<dim; j++)
105 {
106 alpha[j] = i % (k+1);
107 i = i/(k+1);
108 }
109 return alpha;
110 }
111
112 public:
113 using Traits = LocalBasisTraits<D,dim,FieldVector<D,dim>,R,1,FieldVector<R,1>,FieldMatrix<R,1,dim> >;
114
117 static constexpr unsigned int size ()
118 {
119 return power(k+1, dim);
120 }
121
123 void evaluateFunction(const typename Traits::DomainType& x,
124 std::vector<typename Traits::RangeType>& out) const
125 {
126 out.resize(size());
127
128 // Specialization for zero-order case
129 if (k==0)
130 {
131 out[0] = 1;
132 return;
133 }
134
135 if (k==1)
136 {
137 for (size_t i=0; i<size(); i++)
138 {
139 out[i] = 1;
140
141 for (unsigned int j=0; j<dim; j++)
142 // if j-th bit of i is set multiply with x[j], else with 1-x[j]
143 out[i] *= (i & (1<<j)) ? x[j] : 1-x[j];
144 }
145 return;
146 }
147
148 // General case
149 for (size_t i=0; i<size(); i++)
150 {
151 // convert index i to multiindex
152 std::array<unsigned int,dim> alpha(multiindex(i));
153
154 // initialize product
155 out[i] = 1.0;
156
157 // dimension by dimension
158 for (unsigned int j=0; j<dim; j++)
159 out[i] *= p(alpha[j],x[j]);
160 }
161 }
162
168 void evaluateJacobian(const typename Traits::DomainType& x,
169 std::vector<typename Traits::JacobianType>& out) const
170 {
171 out.resize(size());
172
173 // Specialization for k==0
174 if (k==0)
175 {
176 std::fill(out[0][0].begin(), out[0][0].end(), 0);
177 return;
178 }
179
180 // Specialization for k==1
181 if (k==1)
182 {
183 // Loop over all shape functions
184 for (size_t i=0; i<size(); i++)
185 {
186 // Loop over all coordinate directions
187 for (unsigned int j=0; j<dim; j++)
188 {
189 // Initialize: the overall expression is a product
190 // if j-th bit of i is set to 1, else -11
191 out[i][0][j] = (i & (1<<j)) ? 1 : -1;
192
193 for (unsigned int l=0; l<dim; l++)
194 {
195 if (j!=l)
196 // if l-th bit of i is set multiply with x[l], else with 1-x[l]
197 out[i][0][j] *= (i & (1<<l)) ? x[l] : 1-x[l];
198 }
199 }
200 }
201 return;
202 }
203
204 // The general case
205
206 // Loop over all shape functions
207 for (size_t i=0; i<size(); i++)
208 {
209 // convert index i to multiindex
210 std::array<unsigned int,dim> alpha(multiindex(i));
211
212 // Loop over all coordinate directions
213 for (unsigned int j=0; j<dim; j++)
214 {
215 // Initialize: the overall expression is a product
216 // if j-th bit of i is set to -1, else 1
217 out[i][0][j] = dp(alpha[j],x[j]);
218
219 // rest of the product
220 for (unsigned int l=0; l<dim; l++)
221 if (l!=j)
222 out[i][0][j] *= p(alpha[l],x[l]);
223 }
224 }
225 }
226
233 void partial(const std::array<unsigned int,dim>& order,
234 const typename Traits::DomainType& in,
235 std::vector<typename Traits::RangeType>& out) const
236 {
237 auto totalOrder = std::accumulate(order.begin(), order.end(), 0);
238
239 out.resize(size());
240
241 if (k==0)
242 {
243 out[0] = (totalOrder==0);
244 return;
245 }
246
247 if (k==1)
248 {
249 if (totalOrder == 0)
250 {
251 evaluateFunction(in, out);
252 }
253 else if (totalOrder == 1)
254 {
255 out.resize(size());
256
257 auto direction = std::distance(order.begin(), std::find(order.begin(), order.end(), 1));
258 if (direction >= dim)
259 DUNE_THROW(RangeError, "Direction of partial derivative not found!");
260
261 // Loop over all shape functions
262 for (std::size_t i = 0; i < size(); ++i)
263 {
264 // Initialize: the overall expression is a product
265 // if j-th bit of i is set to 1, otherwise to -1
266 out[i] = (i & (1<<direction)) ? 1 : -1;
267
268 for (unsigned int j = 0; j < dim; ++j)
269 {
270 if (direction != j)
271 // if j-th bit of i is set multiply with in[j], else with 1-in[j]
272 out[i] *= (i & (1<<j)) ? in[j] : 1-in[j];
273 }
274 }
275 }
276 else if (totalOrder == 2)
277 {
278
279 for (size_t i=0; i<size(); i++)
280 {
281 // convert index i to multiindex
282 std::array<unsigned int,dim> alpha(multiindex(i));
283
284 // Initialize: the overall expression is a product
285 out[i][0] = 1.0;
286
287 // rest of the product
288 for (std::size_t l=0; l<dim; l++)
289 {
290 switch (order[l])
291 {
292 case 0:
293 out[i][0] *= p(alpha[l],in[l]);
294 break;
295 case 1:
296 //std::cout << "dp: " << dp(alpha[l],in[l]) << std::endl;
297 out[i][0] *= dp(alpha[l],in[l]);
298 break;
299 case 2:
300 out[i][0] *= 0;
301 break;
302 default:
303 DUNE_THROW(NotImplemented, "Desired derivative order is not implemented");
304 }
305 }
306 }
307 }
308 else
309 DUNE_THROW(NotImplemented, "Partial derivative of order " << totalOrder << " is not implemented!");
310
311 return;
312 }
313
314 // The case k>1
315
316 // Loop over all shape functions
317 for (size_t i=0; i<size(); i++)
318 {
319 // convert index i to multiindex
320 std::array<unsigned int,dim> alpha(multiindex(i));
321
322 // Initialize: the overall expression is a product
323 out[i][0] = 1.0;
324
325 // rest of the product
326 for (std::size_t l=0; l<dim; l++)
327 {
328 switch (order[l])
329 {
330 case 0:
331 out[i][0] *= p(alpha[l],in[l]);
332 break;
333 case 1:
334 out[i][0] *= dp(alpha[l],in[l]);
335 break;
336 case 2:
337 out[i][0] *= ddp(alpha[l],in[l]);
338 break;
339 default:
340 DUNE_THROW(NotImplemented, "Desired derivative order is not implemented");
341 }
342 }
343 }
344 }
345
347 static constexpr unsigned int order ()
348 {
349 return k;
350 }
351 };
352
358 template<unsigned int dim, unsigned int k>
359 class LagrangeCubeLocalCoefficients
360 {
361 // Return i as a d-digit number in the (k+1)-nary system
362 static std::array<unsigned int,dim> multiindex (unsigned int i)
363 {
364 std::array<unsigned int,dim> alpha;
365 for (unsigned int j=0; j<dim; j++)
366 {
367 alpha[j] = i % (k+1);
368 i = i/(k+1);
369 }
370 return alpha;
371 }
372
374 void setup1d(std::vector<unsigned int>& subEntity)
375 {
376 assert(k>0);
377
378 unsigned lastIndex=0;
379
380 /* edge and vertex numbering
381 0----0----1
382 */
383
384 // edge (0)
385 subEntity[lastIndex++] = 0; // corner 0
386 for (unsigned i = 0; i < k - 1; ++i)
387 subEntity[lastIndex++] = 0; // inner dofs of element (0)
388
389 subEntity[lastIndex++] = 1; // corner 1
390
391 assert(power(k+1,dim)==lastIndex);
392 }
393
394 void setup2d(std::vector<unsigned int>& subEntity)
395 {
396 assert(k>0);
397
398 unsigned lastIndex=0;
399
400 // LocalKey: entity number, entity codim, dof indices within each entity
401 /* edge and vertex numbering
402 2----3----3
403 | |
404 | |
405 0 1
406 | |
407 | |
408 0----2----1
409 */
410
411 // lower edge (2)
412 subEntity[lastIndex++] = 0; // corner 0
413 for (unsigned i = 0; i < k - 1; ++i)
414 subEntity[lastIndex++] = 2; // inner dofs of lower edge (2)
415
416 subEntity[lastIndex++] = 1; // corner 1
417
418 // iterate from bottom to top over inner edge dofs
419 for (unsigned e = 0; e < k - 1; ++e) {
420 subEntity[lastIndex++] = 0; // left edge (0)
421 for (unsigned i = 0; i < k - 1; ++i)
422 subEntity[lastIndex++] = 0; // face dofs
423 subEntity[lastIndex++] = 1; // right edge (1)
424 }
425
426 // upper edge (3)
427 subEntity[lastIndex++] = 2; // corner 2
428 for (unsigned i = 0; i < k - 1; ++i)
429 subEntity[lastIndex++] = 3; // inner dofs of upper edge (3)
430
431 subEntity[lastIndex++] = 3; // corner 3
432
433 assert(power(k+1,dim)==lastIndex);
434 }
435
436 void setup3d(std::vector<unsigned int>& subEntity)
437 {
438 assert(k>0);
439
440 unsigned lastIndex=0;
441#ifndef NDEBUG
442 const unsigned numIndices = power(k+1,dim);
443 const unsigned numFaceIndices = power(k+1,dim-1);
444#endif
445 const unsigned numInnerEdgeDofs = k-1;
446
447 // LocalKey: entity number, entity codim, dof indices within each entity
448 /* edge and vertex numbering
449
450 6---(11)--7 6---------7
451 /| /| /| (5) /|
452 (8)| (9)| / | top / |
453 / (2) / (3) / |(3)bac/k |
454 4---(10)--5 | 4---------5 |
455 | | | | left|(0)| |(1)|right
456 | 2--(7)|---3 | 2-----|---3
457 (0) / (1) / |(2)front | /
458 |(4) |(5) | / (4) | /
459 |/ |/ |/ bottom |/
460 0---(6)---1 0---------1
461 */
462
463 // bottom face (4)
464 lastIndex=0;
465 // lower edge (6)
466 subEntity[lastIndex++] = 0; // corner 0
467 for (unsigned i = 0; i < numInnerEdgeDofs; ++i)
468 subEntity[lastIndex++] = 6; // inner dofs of lower edge (6)
469
470 subEntity[lastIndex++] = 1; // corner 1
471
472 // iterate from bottom to top over inner edge dofs
473 for (unsigned e = 0; e < numInnerEdgeDofs; ++e) {
474 subEntity[lastIndex++] = 4; // left edge (4)
475 for (unsigned i = 0; i < numInnerEdgeDofs; ++i)
476 subEntity[lastIndex++] = 4; // inner face dofs
477 subEntity[lastIndex++] = 5; // right edge (5)
478 }
479
480 // upper edge (7)
481 subEntity[lastIndex++] = 2; // corner 2
482 for (unsigned i = 0; i < k - 1; ++i)
483 subEntity[lastIndex++] = 7; // inner dofs of upper edge (7)
484 subEntity[lastIndex++] = 3; // corner 3
485
486 assert(numFaceIndices==lastIndex); // added 1 face so far
488
490 for(unsigned f = 0; f < numInnerEdgeDofs; ++f) {
491
492 // lower edge (connecting edges 0 and 1)
493 subEntity[lastIndex++] = 0; // dof on edge 0
494 for (unsigned i = 0; i < numInnerEdgeDofs; ++i)
495 subEntity[lastIndex++] = 2; // dof in front face
496 subEntity[lastIndex++] = 1; // dof on edge 1
497
498 // iterate from bottom to top over inner edge dofs
499 for (unsigned e = 0; e < numInnerEdgeDofs; ++e) {
500 subEntity[lastIndex++] = 0; // on left face (0)
501 for (unsigned i = 0; i < numInnerEdgeDofs; ++i)
502 subEntity[lastIndex++] = 0; // volume dofs
503 subEntity[lastIndex++] = 1; // right face (1)
504 }
505
506 // upper edge (connecting edges 0 and 1)
507 subEntity[lastIndex++] = 2; // dof on edge 2
508 for (unsigned i = 0; i < numInnerEdgeDofs; ++i)
509 subEntity[lastIndex++] = 3; // dof on rear face (3)
510 subEntity[lastIndex++] = 3; // dof on edge 3
511
512 assert(lastIndex==(f+1+1)*numFaceIndices);
513 }
514
516 // lower edge (10)
517 subEntity[lastIndex++] = 4; // corner 4
518 for (unsigned i = 0; i < k - 1; ++i)
519 subEntity[lastIndex++] = 10; // inner dofs on lower edge (10)
520 subEntity[lastIndex++] = 5; // corner 5
521
522 // iterate from bottom to top over inner edge dofs
523 for (unsigned e = 0; e < k - 1; ++e) {
524 subEntity[lastIndex++] = 8; // left edge (8)
525 for (unsigned i = 0; i < k - 1; ++i)
526 subEntity[lastIndex++] = 5; // face dofs
527 subEntity[lastIndex++] = 9; // right edge (9)
528 }
529
530 // upper edge (11)
531 subEntity[lastIndex++] = 6; // corner 6
532 for (unsigned i = 0; i < k - 1; ++i)
533 subEntity[lastIndex++] = 11; // inner dofs of upper edge (11)
534 subEntity[lastIndex++] = 7; // corner 7
535
536 assert(numIndices==lastIndex);
537 }
538
539 public:
541 LagrangeCubeLocalCoefficients ()
542 : localKeys_(size())
543 {
544 if (k==0)
545 {
546 localKeys_[0] = LocalKey(0,0,0);
547 return;
548 }
549
550 if (k==1)
551 {
552 for (std::size_t i=0; i<size(); i++)
553 localKeys_[i] = LocalKey(i,dim,0);
554 return;
555 }
556
557 // Now: the general case
558
559 // Set up array of codimension-per-dof-number
560 std::vector<unsigned int> codim(size());
561
562 for (std::size_t i=0; i<codim.size(); i++)
563 {
564 codim[i] = 0;
565
566 // Codimension gets increased by 1 for each coordinate direction
567 // where dof is on boundary
568 std::array<unsigned int,dim> mIdx = multiindex(i);
569 for (unsigned int j=0; j<dim; j++)
570 if (mIdx[j]==0 or mIdx[j]==k)
571 codim[i]++;
572 }
573
574 // Set up index vector (the index of the dof in the set of dofs of a given subentity)
575 // Algorithm: the 'index' has the same ordering as the dof number 'i'.
576 // To make it consecutive we interpret 'i' in the (k+1)-adic system, omit all digits
577 // that correspond to axes where the dof is on the element boundary, and transform the
578 // rest to the (k-1)-adic system.
579 std::vector<unsigned int> index(size());
580
581 for (std::size_t i=0; i<size(); i++)
582 {
583 index[i] = 0;
584
585 std::array<unsigned int,dim> mIdx = multiindex(i);
586
587 for (int j=dim-1; j>=0; j--)
588 if (mIdx[j]>0 && mIdx[j]<k)
589 index[i] = (k-1)*index[i] + (mIdx[j]-1);
590 }
591
592 // Set up entity and dof numbers for each (supported) dimension separately
593 std::vector<unsigned int> subEntity(size());
594
595 if (dim==1) {
596
597 setup1d(subEntity);
598
599 } else if (dim==2) {
600
601 setup2d(subEntity);
602
603 } else if (dim==3) {
604
605 setup3d(subEntity);
606
607 } else
608 DUNE_THROW(Dune::NotImplemented, "LagrangeCubeLocalCoefficients for order " << k << " and dim == " << dim);
609
610 for (size_t i=0; i<size(); i++)
611 localKeys_[i] = LocalKey(subEntity[i], codim[i], index[i]);
612 }
613
615 static constexpr std::size_t size ()
616 {
617 return power(k+1,dim);
618 }
619
621 const LocalKey& localKey (std::size_t i) const
622 {
623 return localKeys_[i];
624 }
625
626 private:
627 std::vector<LocalKey> localKeys_;
628 };
629
634 template<class LocalBasis>
635 class LagrangeCubeLocalInterpolation
636 {
637 public:
638
646 template<typename F, typename C>
647 void interpolate (const F& ff, std::vector<C>& out) const
648 {
649 constexpr auto dim = LocalBasis::Traits::dimDomain;
650 constexpr auto k = LocalBasis::order();
651 using D = typename LocalBasis::Traits::DomainFieldType;
652
653 typename LocalBasis::Traits::DomainType x;
654 auto&& f = Impl::makeFunctionWithCallOperator<typename LocalBasis::Traits::DomainType>(ff);
655
656 out.resize(LocalBasis::size());
657
658 // Specialization for zero-order case
659 if (k==0)
660 {
661 auto center = ReferenceElements<D,dim>::cube().position(0,0);
662 out[0] = f(center);
663 return;
664 }
665
666 // Specialization for first-order case
667 if (k==1)
668 {
669 for (unsigned int i=0; i<LocalBasis::size(); i++)
670 {
671 // Generate coordinate of the i-th corner of the reference cube
672 for (int j=0; j<dim; j++)
673 x[j] = (i & (1<<j)) ? 1.0 : 0.0;
674
675 out[i] = f(x);
676 }
677 return;
678 }
679
680 // The general case
681 for (unsigned int i=0; i<LocalBasis::size(); i++)
682 {
683 // convert index i to multiindex
684 std::array<unsigned int,dim> alpha(LocalBasis::multiindex(i));
685
686 // Generate coordinate of the i-th Lagrange point
687 for (unsigned int j=0; j<dim; j++)
688 x[j] = (1.0*alpha[j])/k;
689
690 out[i] = f(x);
691 }
692 }
693
694 };
695
696} } // namespace Dune::Impl
697
698namespace Dune
699{
707 template<class D, class R, int dim, int k>
709 {
710 public:
714 Impl::LagrangeCubeLocalCoefficients<dim,k>,
715 Impl::LagrangeCubeLocalInterpolation<Impl::LagrangeCubeLocalBasis<D,R,dim,k> > >;
716
723
726 const typename Traits::LocalBasisType& localBasis () const
727 {
728 return basis_;
729 }
730
734 {
735 return coefficients_;
736 }
737
741 {
742 return interpolation_;
743 }
744
746 static constexpr std::size_t size ()
747 {
748 return power(k+1,dim);
749 }
750
753 static constexpr GeometryType type ()
754 {
755 return GeometryTypes::cube(dim);
756 }
757
758 private:
759 Impl::LagrangeCubeLocalBasis<D,R,dim,k> basis_;
760 Impl::LagrangeCubeLocalCoefficients<dim,k> coefficients_;
761 Impl::LagrangeCubeLocalInterpolation<Impl::LagrangeCubeLocalBasis<D,R,dim,k> > interpolation_;
762 };
763
764} // namespace Dune
765
766#endif // DUNE_LOCALFUNCTIONS_LAGRANGE_LAGRANGECUBE_HH
Unique label for each type of entities that can occur in DUNE grids.
Definition: type.hh:280
Lagrange finite element for cubes with arbitrary compile-time dimension and polynomial order.
Definition: lagrangecube.hh:709
const Traits::LocalBasisType & localBasis() const
Returns the local basis, i.e., the set of shape functions.
Definition: lagrangecube.hh:726
LagrangeCubeLocalFiniteElement()
Default constructor.
Definition: lagrangecube.hh:722
const Traits::LocalInterpolationType & localInterpolation() const
Returns object that evaluates degrees of freedom.
Definition: lagrangecube.hh:740
static constexpr GeometryType type()
The reference element that the local finite element is defined on.
Definition: lagrangecube.hh:753
static constexpr std::size_t size()
The number of shape functions.
Definition: lagrangecube.hh:746
const Traits::LocalCoefficientsType & localCoefficients() const
Returns the assignment of the degrees of freedom to the element subentities.
Definition: lagrangecube.hh:733
Default exception for dummy implementations.
Definition: exceptions.hh:261
Implements a matrix constructed from a given type representing a field and compile-time given number ...
Implements a vector constructed from a given type representing a field and a compile-time given size.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
constexpr GeometryType cube(unsigned int dim)
Returns a GeometryType representing a hypercube of dimension dim.
Definition: type.hh:776
void interpolate(const F &f, const GFS &gfs, XG &xg)
interpolation from a given grid function
Definition: interpolate.hh:174
T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:290
Some useful basic math stuff.
Dune namespace.
Definition: alignedallocator.hh:14
constexpr Mantissa power(Mantissa m, Exponent p)
Power method for integer exponents.
Definition: math.hh:73
static const ReferenceElement & cube()
get hypercube reference elements
Definition: referenceelements.hh:208
D DomainType
domain type
Definition: localbasis.hh:43
traits helper struct
Definition: localfiniteelementtraits.hh:11
LB LocalBasisType
Definition: localfiniteelementtraits.hh:14
LC LocalCoefficientsType
Definition: localfiniteelementtraits.hh:18
LI LocalInterpolationType
Definition: localfiniteelementtraits.hh:22
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)