Dune Core Modules (2.7.1)

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 
9 #include <dune/common/fmatrix.hh>
10 #include <dune/common/fvector.hh>
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 
20 namespace 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 
698 namespace 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:279
Lagrange finite element for cubes with arbitrary compile-time dimension and polynomial order.
Definition: lagrangecube.hh:709
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
const Traits::LocalBasisType & localBasis() const
Returns the local basis, i.e., the set of shape functions.
Definition: lagrangecube.hh:726
const Traits::LocalCoefficientsType & localCoefficients() const
Returns the assignment of the degrees of freedom to the element subentities.
Definition: lagrangecube.hh:733
static constexpr std::size_t size()
The number of shape functions.
Definition: lagrangecube.hh:746
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:775
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.80.0 (May 16, 22:29, 2024)