Reference documentation for deal.II version 9.0.0
tensor_product_polynomials.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/tensor_product_polynomials.h>
17 #include <deal.II/base/polynomials_piecewise.h>
18 #include <deal.II/base/exceptions.h>
19 #include <deal.II/base/table.h>
20 
21 #include <boost/container/small_vector.hpp>
22 #include <array>
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 
27 
28 /* ------------------- TensorProductPolynomials -------------- */
29 
30 
31 namespace internal
32 {
33  namespace
34  {
35  template <int dim>
36  inline
37  void compute_tensor_index(const unsigned int,
38  const unsigned int,
39  const unsigned int,
40  unsigned int ( &)[dim])
41  {
42  Assert(false, ExcNotImplemented());
43  }
44 
45  inline
46  void compute_tensor_index(const unsigned int n,
47  const unsigned int,
48  const unsigned int,
49  unsigned int (&indices)[1])
50  {
51  indices[0] = n;
52  }
53 
54  inline
55  void compute_tensor_index(const unsigned int n,
56  const unsigned int n_pols_0,
57  const unsigned int,
58  unsigned int (&indices)[2])
59  {
60  indices[0] = n % n_pols_0;
61  indices[1] = n / n_pols_0;
62  }
63 
64  inline
65  void compute_tensor_index(const unsigned int n,
66  const unsigned int n_pols_0,
67  const unsigned int n_pols_1,
68  unsigned int (&indices)[3])
69  {
70  indices[0] = n % n_pols_0;
71  indices[1] = (n/n_pols_0) % n_pols_1;
72  indices[2] = n / (n_pols_0*n_pols_1);
73  }
74  }
75 }
76 
77 
78 
79 template <int dim, typename PolynomialType>
80 inline
81 void
83 compute_index (const unsigned int i,
84  unsigned int (&indices)[(dim > 0 ? dim : 1)]) const
85 {
86  Assert (i<Utilities::fixed_power<dim>(polynomials.size()),ExcInternalError());
87  internal::compute_tensor_index(index_map[i], polynomials.size(),
88  polynomials.size(), indices);
89 }
90 
91 
92 
93 template <int dim, typename PolynomialType>
94 void
96 {
97  unsigned int ix[dim];
98  for (unsigned int i=0; i<n_tensor_pols; ++i)
99  {
100  compute_index(i,ix);
101  out << i << "\t";
102  for (unsigned int d=0; d<dim; ++d)
103  out << ix[d] << " ";
104  out << std::endl;
105  }
106 }
107 
108 
109 
110 template <int dim, typename PolynomialType>
111 void
113 (const std::vector<unsigned int> &renumber)
114 {
115  Assert(renumber.size()==index_map.size(),
116  ExcDimensionMismatch(renumber.size(), index_map.size()));
117 
118  index_map=renumber;
119  for (unsigned int i=0; i<index_map.size(); ++i)
120  index_map_inverse[index_map[i]]=i;
121 }
122 
123 
124 
125 template <>
126 double
128 ::compute_value(const unsigned int,
129  const Point<0> &) const
130 {
131  Assert (false, ExcNotImplemented());
132  return 0;
133 }
134 
135 
136 
137 template <int dim, typename PolynomialType>
138 double
140 (const unsigned int i,
141  const Point<dim> &p) const
142 {
143  Assert(dim>0, ExcNotImplemented());
144 
145  unsigned int indices[dim];
146  compute_index (i, indices);
147 
148  double value=1.;
149  for (unsigned int d=0; d<dim; ++d)
150  value *= polynomials[indices[d]].value(p(d));
151 
152  return value;
153 }
154 
155 
156 
157 template <int dim, typename PolynomialType>
160  const Point<dim> &p) const
161 {
162  unsigned int indices[dim];
163  compute_index (i, indices);
164 
165  // compute values and
166  // uni-directional derivatives at
167  // the given point in each
168  // co-ordinate direction
169  double v [dim][2];
170  {
171  std::vector<double> tmp (2);
172  for (unsigned int d=0; d<dim; ++d)
173  {
174  polynomials[indices[d]].value (p(d), tmp);
175  v[d][0] = tmp[0];
176  v[d][1] = tmp[1];
177  }
178  }
179 
180  Tensor<1,dim> grad;
181  for (unsigned int d=0; d<dim; ++d)
182  {
183  grad[d] = 1.;
184  for (unsigned int x=0; x<dim; ++x)
185  grad[d] *= v[x][d==x];
186  }
187 
188  return grad;
189 }
190 
191 
192 
193 template <int dim, typename PolynomialType>
196 (const unsigned int i,
197  const Point<dim> &p) const
198 {
199  unsigned int indices[dim];
200  compute_index (i, indices);
201 
202  double v [dim][3];
203  {
204  std::vector<double> tmp (3);
205  for (unsigned int d=0; d<dim; ++d)
206  {
207  polynomials[indices[d]].value (p(d), tmp);
208  v[d][0] = tmp[0];
209  v[d][1] = tmp[1];
210  v[d][2] = tmp[2];
211  }
212  }
213 
214  Tensor<2,dim> grad_grad;
215  for (unsigned int d1=0; d1<dim; ++d1)
216  for (unsigned int d2=0; d2<dim; ++d2)
217  {
218  grad_grad[d1][d2] = 1.;
219  for (unsigned int x=0; x<dim; ++x)
220  {
221  unsigned int derivative=0;
222  if (d1==x || d2==x)
223  {
224  if (d1==d2)
225  derivative=2;
226  else
227  derivative=1;
228  }
229  grad_grad[d1][d2] *= v[x][derivative];
230  }
231  }
232 
233  return grad_grad;
234 }
235 
236 
237 
238 
239 template <int dim, typename PolynomialType>
240 void
242 compute (const Point<dim> &p,
243  std::vector<double> &values,
244  std::vector<Tensor<1,dim> > &grads,
245  std::vector<Tensor<2,dim> > &grad_grads,
246  std::vector<Tensor<3,dim> > &third_derivatives,
247  std::vector<Tensor<4,dim> > &fourth_derivatives) const
248 {
249  Assert(dim<=3, ExcNotImplemented());
250  Assert (values.size()==n_tensor_pols || values.size()==0,
251  ExcDimensionMismatch2(values.size(), n_tensor_pols, 0));
252  Assert (grads.size()==n_tensor_pols || grads.size()==0,
253  ExcDimensionMismatch2(grads.size(), n_tensor_pols, 0));
254  Assert (grad_grads.size()==n_tensor_pols|| grad_grads.size()==0,
255  ExcDimensionMismatch2(grad_grads.size(), n_tensor_pols, 0));
256  Assert (third_derivatives.size()==n_tensor_pols|| third_derivatives.size()==0,
257  ExcDimensionMismatch2(third_derivatives.size(), n_tensor_pols, 0));
258  Assert (fourth_derivatives.size()==n_tensor_pols|| fourth_derivatives.size()==0,
259  ExcDimensionMismatch2(fourth_derivatives.size(), n_tensor_pols, 0));
260 
261  const bool update_values = (values.size()==n_tensor_pols),
262  update_grads = (grads.size()==n_tensor_pols),
263  update_grad_grads = (grad_grads.size()==n_tensor_pols),
264  update_3rd_derivatives = (third_derivatives.size()==n_tensor_pols),
265  update_4th_derivatives = (fourth_derivatives.size()==n_tensor_pols);
266 
267  // check how many values/derivatives we have to compute
268  unsigned int n_values_and_derivatives = 0;
269  if (update_values)
270  n_values_and_derivatives = 1;
271  if (update_grads)
272  n_values_and_derivatives = 2;
273  if (update_grad_grads)
274  n_values_and_derivatives = 3;
276  n_values_and_derivatives = 4;
277  if (update_4th_derivatives)
278  n_values_and_derivatives = 5;
279 
280  // Compute the values (and derivatives, if necessary) of all 1D polynomials
281  // at this evaluation point. We need to compute dim*n_polynomials
282  // evaluations, involving an evaluation of each polynomial for each
283  // coordinate direction. Once we have those values, we perform the
284  // multiplications for the tensor product in the arbitrary dimension.
285  const unsigned int n_polynomials = polynomials.size();
286  boost::container::small_vector<std::array<std::array<double,5>,dim>, 20> values_1d(n_polynomials);
287  if (n_values_and_derivatives == 1)
288  for (unsigned int i=0; i<n_polynomials; ++i)
289  for (unsigned int d=0; d<dim; ++d)
290  values_1d[i][d][0] = polynomials[i].value(p(d));
291  else
292  for (unsigned int i=0; i<n_polynomials; ++i)
293  for (unsigned d=0; d<dim; ++d)
294  polynomials[i].value(p(d), n_values_and_derivatives, &values_1d[i][d][0]);
295 
296  unsigned int indices[3];
297  unsigned int ind=0;
298  for (indices[2]=0; indices[2]<(dim>2?n_polynomials:1); ++indices[2])
299  for (indices[1]=0; indices[1]<(dim>1?n_polynomials:1); ++indices[1])
300  if (n_values_and_derivatives == 1)
301  for (indices[0]=0; indices[0]<n_polynomials; ++indices[0], ++ind)
302  {
303  double value = values_1d[indices[0]][0][0];
304  for (unsigned int d=1; d<dim; ++d)
305  value *= values_1d[indices[d]][d][0];
306  values[index_map_inverse[ind]] = value;
307  }
308  else
309  for (indices[0]=0; indices[0]<n_polynomials; ++indices[0], ++ind)
310  {
311  unsigned int i = index_map_inverse[ind];
312 
313  if (update_values)
314  {
315  double value = values_1d[indices[0]][0][0];
316  for (unsigned int x=1; x<dim; ++x)
317  value *= values_1d[indices[x]][x][0];
318  values[i] = value;
319  }
320 
321  if (update_grads)
322  for (unsigned int d=0; d<dim; ++d)
323  {
324  double grad = 1.;
325  for (unsigned int x=0; x<dim; ++x)
326  grad *= values_1d[indices[x]][x][(d==x)?1:0];
327  grads[i][d] = grad;
328  }
329 
330  if (update_grad_grads)
331  for (unsigned int d1=0; d1<dim; ++d1)
332  for (unsigned int d2=0; d2<dim; ++d2)
333  {
334  double der2 = 1.;
335  for (unsigned int x=0; x<dim; ++x)
336  {
337  unsigned int derivative=0;
338  if (d1==x) ++derivative;
339  if (d2==x) ++derivative;
340 
341  der2 *= values_1d[indices[x]][x][derivative];
342  }
343  grad_grads[i][d1][d2] = der2;
344  }
345 
347  for (unsigned int d1=0; d1<dim; ++d1)
348  for (unsigned int d2=0; d2<dim; ++d2)
349  for (unsigned int d3=0; d3<dim; ++d3)
350  {
351  double der3 = 1.;
352  for (unsigned int x=0; x<dim; ++x)
353  {
354  unsigned int derivative=0;
355  if (d1==x) ++derivative;
356  if (d2==x) ++derivative;
357  if (d3==x) ++derivative;
358 
359  der3 *= values_1d[indices[x]][x][derivative];
360  }
361  third_derivatives[i][d1][d2][d3] = der3;
362  }
363 
364  if (update_4th_derivatives)
365  for (unsigned int d1=0; d1<dim; ++d1)
366  for (unsigned int d2=0; d2<dim; ++d2)
367  for (unsigned int d3=0; d3<dim; ++d3)
368  for (unsigned int d4=0; d4<dim; ++d4)
369  {
370  double der4 = 1.;
371  for (unsigned int x=0; x<dim; ++x)
372  {
373  unsigned int derivative=0;
374  if (d1==x) ++derivative;
375  if (d2==x) ++derivative;
376  if (d3==x) ++derivative;
377  if (d4==x) ++derivative;
378 
379  der4 *= values_1d[indices[x]][x][derivative];
380  }
381  fourth_derivatives[i][d1][d2][d3][d4] = der4;
382  }
383  }
384 }
385 
386 
387 
388 
389 /* ------------------- AnisotropicPolynomials -------------- */
390 
391 
392 template <int dim>
394 AnisotropicPolynomials(const std::vector<std::vector<Polynomials::Polynomial<double> > > &pols)
395  :
396  polynomials (pols),
397  n_tensor_pols(get_n_tensor_pols(pols))
398 {
399  Assert (pols.size() == dim, ExcDimensionMismatch(pols.size(), dim));
400  for (unsigned int d=0; d<dim; ++d)
401  Assert (pols[d].size() > 0,
402  ExcMessage ("The number of polynomials must be larger than zero "
403  "for all coordinate directions."));
404 }
405 
406 
407 
408 
409 template <int dim>
410 void
412 compute_index (const unsigned int i,
413  unsigned int (&indices)[dim]) const
414 {
415 #ifdef DEBUG
416  unsigned int n_poly = 1;
417  for (unsigned int d=0; d<dim; ++d)
418  n_poly *= polynomials[d].size();
419  Assert (i < n_poly, ExcInternalError());
420 #endif
421 
422  if (dim==1)
423  internal::compute_tensor_index(i, polynomials[0].size(),
424  0 /*not used*/, indices);
425  else
426  internal::compute_tensor_index(i, polynomials[0].size(),
427  polynomials[1].size(), indices);
428 }
429 
430 
431 
432 template <int dim>
433 double
435  const Point<dim> &p) const
436 {
437  unsigned int indices[dim];
438  compute_index (i, indices);
439 
440  double value=1.;
441  for (unsigned int d=0; d<dim; ++d)
442  value *= polynomials[d][indices[d]].value(p(d));
443 
444  return value;
445 }
446 
447 
448 template <int dim>
451  const Point<dim> &p) const
452 {
453  unsigned int indices[dim];
454  compute_index (i, indices);
455 
456  // compute values and
457  // uni-directional derivatives at
458  // the given point in each
459  // co-ordinate direction
460  std::vector<std::vector<double> > v(dim, std::vector<double> (2));
461  for (unsigned int d=0; d<dim; ++d)
462  polynomials[d][indices[d]].value(p(d), v[d]);
463 
464  Tensor<1,dim> grad;
465  for (unsigned int d=0; d<dim; ++d)
466  {
467  grad[d] = 1.;
468  for (unsigned int x=0; x<dim; ++x)
469  grad[d] *= v[x][d==x];
470  }
471 
472  return grad;
473 }
474 
475 
476 template <int dim>
479  const Point<dim> &p) const
480 {
481  unsigned int indices[dim];
482  compute_index (i, indices);
483 
484  std::vector<std::vector<double> > v(dim, std::vector<double> (3));
485  for (unsigned int d=0; d<dim; ++d)
486  polynomials[d][indices[d]].value(p(d), v[d]);
487 
488  Tensor<2,dim> grad_grad;
489  for (unsigned int d1=0; d1<dim; ++d1)
490  for (unsigned int d2=0; d2<dim; ++d2)
491  {
492  grad_grad[d1][d2] = 1.;
493  for (unsigned int x=0; x<dim; ++x)
494  {
495  unsigned int derivative=0;
496  if (d1==x || d2==x)
497  {
498  if (d1==d2)
499  derivative=2;
500  else
501  derivative=1;
502  }
503  grad_grad[d1][d2] *= v[x][derivative];
504  }
505  }
506 
507  return grad_grad;
508 }
509 
510 
511 
512 
513 template <int dim>
514 void
516 compute (const Point<dim> &p,
517  std::vector<double> &values,
518  std::vector<Tensor<1,dim> > &grads,
519  std::vector<Tensor<2,dim> > &grad_grads,
520  std::vector<Tensor<3,dim> > &third_derivatives,
521  std::vector<Tensor<4,dim> > &fourth_derivatives) const
522 {
523  Assert (values.size()==n_tensor_pols || values.size()==0,
524  ExcDimensionMismatch2(values.size(), n_tensor_pols, 0));
525  Assert (grads.size()==n_tensor_pols|| grads.size()==0,
526  ExcDimensionMismatch2(grads.size(), n_tensor_pols, 0));
527  Assert (grad_grads.size()==n_tensor_pols|| grad_grads.size()==0,
528  ExcDimensionMismatch2(grad_grads.size(), n_tensor_pols, 0));
529  Assert (third_derivatives.size()==n_tensor_pols|| third_derivatives.size()==0,
530  ExcDimensionMismatch2(third_derivatives.size(), n_tensor_pols, 0));
531  Assert (fourth_derivatives.size()==n_tensor_pols|| fourth_derivatives.size()==0,
532  ExcDimensionMismatch2(fourth_derivatives.size(), n_tensor_pols, 0));
533 
534  const bool update_values = (values.size() == n_tensor_pols),
535  update_grads = (grads.size()==n_tensor_pols),
536  update_grad_grads = (grad_grads.size()==n_tensor_pols),
537  update_3rd_derivatives = (third_derivatives.size()==n_tensor_pols),
538  update_4th_derivatives = (fourth_derivatives.size()==n_tensor_pols);
539 
540  // check how many
541  // values/derivatives we have to
542  // compute
543  unsigned int n_values_and_derivatives = 0;
544  if (update_values)
545  n_values_and_derivatives = 1;
546  if (update_grads)
547  n_values_and_derivatives = 2;
548  if (update_grad_grads)
549  n_values_and_derivatives = 3;
551  n_values_and_derivatives = 4;
552  if (update_4th_derivatives)
553  n_values_and_derivatives = 5;
554 
555  // compute the values (and
556  // derivatives, if necessary) of
557  // all polynomials at this
558  // evaluation point
559  std::vector<std::vector<std::vector<double> > > v(dim);
560  for (unsigned int d=0; d<dim; ++d)
561  {
562  v[d].resize (polynomials[d].size());
563  for (unsigned int i=0; i<polynomials[d].size(); ++i)
564  {
565  v[d][i].resize (n_values_and_derivatives, 0.);
566  polynomials[d][i].value(p(d), v[d][i]);
567  };
568  }
569 
570  for (unsigned int i=0; i<n_tensor_pols; ++i)
571  {
572  // first get the
573  // one-dimensional indices of
574  // this particular tensor
575  // product polynomial
576  unsigned int indices[dim];
577  compute_index (i, indices);
578 
579  if (update_values)
580  {
581  values[i] = 1;
582  for (unsigned int x=0; x<dim; ++x)
583  values[i] *= v[x][indices[x]][0];
584  }
585 
586  if (update_grads)
587  for (unsigned int d=0; d<dim; ++d)
588  {
589  grads[i][d] = 1.;
590  for (unsigned int x=0; x<dim; ++x)
591  grads[i][d] *= v[x][indices[x]][d==x ? 1 : 0];
592  }
593 
594  if (update_grad_grads)
595  for (unsigned int d1=0; d1<dim; ++d1)
596  for (unsigned int d2=0; d2<dim; ++d2)
597  {
598  grad_grads[i][d1][d2] = 1.;
599  for (unsigned int x=0; x<dim; ++x)
600  {
601  unsigned int derivative=0;
602  if (d1==x) ++derivative;
603  if (d2==x) ++derivative;
604 
605  grad_grads[i][d1][d2]
606  *= v[x][indices[x]][derivative];
607  }
608  }
609 
611  for (unsigned int d1=0; d1<dim; ++d1)
612  for (unsigned int d2=0; d2<dim; ++d2)
613  for (unsigned int d3=0; d3<dim; ++d3)
614  {
615  third_derivatives[i][d1][d2][d3] = 1.;
616  for (unsigned int x=0; x<dim; ++x)
617  {
618  unsigned int derivative=0;
619  if (d1==x) ++derivative;
620  if (d2==x) ++derivative;
621  if (d3==x) ++derivative;
622 
623  third_derivatives[i][d1][d2][d3]
624  *= v[x][indices[x]][derivative];
625  }
626  }
627 
628  if (update_4th_derivatives)
629  for (unsigned int d1=0; d1<dim; ++d1)
630  for (unsigned int d2=0; d2<dim; ++d2)
631  for (unsigned int d3=0; d3<dim; ++d3)
632  for (unsigned int d4=0; d4<dim; ++d4)
633  {
634  fourth_derivatives[i][d1][d2][d3][d4] = 1.;
635  for (unsigned int x=0; x<dim; ++x)
636  {
637  unsigned int derivative=0;
638  if (d1==x) ++derivative;
639  if (d2==x) ++derivative;
640  if (d3==x) ++derivative;
641  if (d4==x) ++derivative;
642 
643  fourth_derivatives[i][d1][d2][d3][d4]
644  *= v[x][indices[x]][derivative];
645  }
646  }
647  }
648 }
649 
650 
651 
652 template <int dim>
653 unsigned int
655 {
656  return n_tensor_pols;
657 }
658 
659 
660 template <int dim>
661 unsigned int
663 get_n_tensor_pols (const std::vector<std::vector<Polynomials::Polynomial<double> > > &pols)
664 {
665  unsigned int y = 1;
666  for (unsigned int d=0; d<dim; ++d)
667  y *= pols[d].size();
668  return y;
669 }
670 
671 
672 
673 /* ------------------- explicit instantiations -------------- */
677 
681 
682 template class AnisotropicPolynomials<1>;
683 template class AnisotropicPolynomials<2>;
684 template class AnisotropicPolynomials<3>;
685 
686 DEAL_II_NAMESPACE_CLOSE
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const
Shape function values.
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const
void compute_index(const unsigned int i, unsigned int(&indices)[(dim >0?dim:1)]) const
static ::ExceptionBase & ExcDimensionMismatch2(int arg1, int arg2, int arg3)
void output_indices(std::ostream &out) const
void set_numbering(const std::vector< unsigned int > &renumber)
void compute(const Point< dim > &unit_point, std::vector< double > &values, std::vector< Tensor< 1, dim > > &grads, std::vector< Tensor< 2, dim > > &grad_grads, std::vector< Tensor< 3, dim > > &third_derivatives, std::vector< Tensor< 4, dim > > &fourth_derivatives) const
Definition: point.h:104
void compute_index(const unsigned int i, unsigned int(&indices)[dim]) const
static unsigned int get_n_tensor_pols(const std::vector< std::vector< Polynomials::Polynomial< double > > > &pols)
static ::ExceptionBase & ExcMessage(std::string arg1)
Third derivatives of shape functions.
#define Assert(cond, exc)
Definition: exceptions.h:1142
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
void compute(const Point< dim > &unit_point, std::vector< double > &values, std::vector< Tensor< 1, dim > > &grads, std::vector< Tensor< 2, dim > > &grad_grads, std::vector< Tensor< 3, dim > > &third_derivatives, std::vector< Tensor< 4, dim > > &fourth_derivatives) const
AnisotropicPolynomials(const std::vector< std::vector< Polynomials::Polynomial< double > > > &base_polynomials)
double compute_value(const unsigned int i, const Point< dim > &p) const
static ::ExceptionBase & ExcNotImplemented()
Tensor< 2, dim > compute_grad_grad(const unsigned int i, const Point< dim > &p) const
double compute_value(const unsigned int i, const Point< dim > &p) const
Tensor< 2, dim > compute_grad_grad(const unsigned int i, const Point< dim > &p) const
static ::ExceptionBase & ExcInternalError()