Dune Core Modules (unstable)

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