Reference documentation for deal.II version 8.5.1
tensor_product_polynomials.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2016 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 #include <deal.II/base/std_cxx11/array.h>
21 
22 DEAL_II_NAMESPACE_OPEN
23 
24 
25 
26 /* ------------------- TensorProductPolynomials -------------- */
27 
28 
29 namespace internal
30 {
31  namespace
32  {
33  template <int dim>
34  inline
35  void compute_tensor_index(const unsigned int,
36  const unsigned int,
37  const unsigned int,
38  unsigned int ( &)[dim])
39  {
40  Assert(false, ExcNotImplemented());
41  }
42 
43  inline
44  void compute_tensor_index(const unsigned int n,
45  const unsigned int ,
46  const unsigned int ,
47  unsigned int (&indices)[1])
48  {
49  indices[0] = n;
50  }
51 
52  inline
53  void compute_tensor_index(const unsigned int n,
54  const unsigned int n_pols_0,
55  const unsigned int ,
56  unsigned int (&indices)[2])
57  {
58  indices[0] = n % n_pols_0;
59  indices[1] = n / n_pols_0;
60  }
61 
62  inline
63  void compute_tensor_index(const unsigned int n,
64  const unsigned int n_pols_0,
65  const unsigned int n_pols_1,
66  unsigned int (&indices)[3])
67  {
68  indices[0] = n % n_pols_0;
69  indices[1] = (n/n_pols_0) % n_pols_1;
70  indices[2] = n / (n_pols_0*n_pols_1);
71  }
72  }
73 }
74 
75 
76 
77 template <int dim, typename PolynomialType>
78 inline
79 void
81 compute_index (const unsigned int i,
82  unsigned int (&indices)[(dim > 0 ? dim : 1)]) const
83 {
84  Assert (i<Utilities::fixed_power<dim>(polynomials.size()),ExcInternalError());
85  internal::compute_tensor_index(index_map[i], polynomials.size(),
86  polynomials.size(), indices);
87 }
88 
89 
90 
91 template <int dim, typename PolynomialType>
92 void
94 {
95  unsigned int ix[dim];
96  for (unsigned int i=0; i<n_tensor_pols; ++i)
97  {
98  compute_index(i,ix);
99  out << i << "\t";
100  for (unsigned int d=0; d<dim; ++d)
101  out << ix[d] << " ";
102  out << std::endl;
103  }
104 }
105 
106 
107 
108 template <int dim, typename PolynomialType>
109 void
111 (const std::vector<unsigned int> &renumber)
112 {
113  Assert(renumber.size()==index_map.size(),
114  ExcDimensionMismatch(renumber.size(), index_map.size()));
115 
116  index_map=renumber;
117  for (unsigned int i=0; i<index_map.size(); ++i)
118  index_map_inverse[index_map[i]]=i;
119 }
120 
121 
122 
123 template <>
124 double
126 ::compute_value(const unsigned int,
127  const Point<0> &) const
128 {
129  Assert (false, ExcNotImplemented());
130  return 0;
131 }
132 
133 
134 
135 template <int dim, typename PolynomialType>
136 double
138 (const unsigned int i,
139  const Point<dim> &p) const
140 {
141  Assert(dim>0, ExcNotImplemented());
142 
143  unsigned int indices[dim];
144  compute_index (i, indices);
145 
146  double value=1.;
147  for (unsigned int d=0; d<dim; ++d)
148  value *= polynomials[indices[d]].value(p(d));
149 
150  return value;
151 }
152 
153 
154 
155 template <int dim, typename PolynomialType>
158  const Point<dim> &p) const
159 {
160  unsigned int indices[dim];
161  compute_index (i, indices);
162 
163  // compute values and
164  // uni-directional derivatives at
165  // the given point in each
166  // co-ordinate direction
167  double v [dim][2];
168  {
169  std::vector<double> tmp (2);
170  for (unsigned int d=0; d<dim; ++d)
171  {
172  polynomials[indices[d]].value (p(d), tmp);
173  v[d][0] = tmp[0];
174  v[d][1] = tmp[1];
175  }
176  }
177 
178  Tensor<1,dim> grad;
179  for (unsigned int d=0; d<dim; ++d)
180  {
181  grad[d] = 1.;
182  for (unsigned int x=0; x<dim; ++x)
183  grad[d] *= v[x][d==x];
184  }
185 
186  return grad;
187 }
188 
189 
190 
191 template <int dim, typename PolynomialType>
194 (const unsigned int i,
195  const Point<dim> &p) const
196 {
197  unsigned int indices[dim];
198  compute_index (i, indices);
199 
200  double v [dim][3];
201  {
202  std::vector<double> tmp (3);
203  for (unsigned int d=0; d<dim; ++d)
204  {
205  polynomials[indices[d]].value (p(d), tmp);
206  v[d][0] = tmp[0];
207  v[d][1] = tmp[1];
208  v[d][2] = tmp[2];
209  }
210  }
211 
212  Tensor<2,dim> grad_grad;
213  for (unsigned int d1=0; d1<dim; ++d1)
214  for (unsigned int d2=0; d2<dim; ++d2)
215  {
216  grad_grad[d1][d2] = 1.;
217  for (unsigned int x=0; x<dim; ++x)
218  {
219  unsigned int derivative=0;
220  if (d1==x || d2==x)
221  {
222  if (d1==d2)
223  derivative=2;
224  else
225  derivative=1;
226  }
227  grad_grad[d1][d2] *= v[x][derivative];
228  }
229  }
230 
231  return grad_grad;
232 }
233 
234 
235 
236 
237 template <int dim, typename PolynomialType>
238 void
240 compute (const Point<dim> &p,
241  std::vector<double> &values,
242  std::vector<Tensor<1,dim> > &grads,
243  std::vector<Tensor<2,dim> > &grad_grads,
244  std::vector<Tensor<3,dim> > &third_derivatives,
245  std::vector<Tensor<4,dim> > &fourth_derivatives) const
246 {
247  Assert (values.size()==n_tensor_pols || values.size()==0,
248  ExcDimensionMismatch2(values.size(), n_tensor_pols, 0));
249  Assert (grads.size()==n_tensor_pols || grads.size()==0,
250  ExcDimensionMismatch2(grads.size(), n_tensor_pols, 0));
251  Assert (grad_grads.size()==n_tensor_pols|| grad_grads.size()==0,
252  ExcDimensionMismatch2(grad_grads.size(), n_tensor_pols, 0));
253  Assert (third_derivatives.size()==n_tensor_pols|| third_derivatives.size()==0,
254  ExcDimensionMismatch2(third_derivatives.size(), n_tensor_pols, 0));
255  Assert (fourth_derivatives.size()==n_tensor_pols|| fourth_derivatives.size()==0,
256  ExcDimensionMismatch2(fourth_derivatives.size(), n_tensor_pols, 0));
257 
258  const bool update_values = (values.size()==n_tensor_pols),
259  update_grads = (grads.size()==n_tensor_pols),
260  update_grad_grads = (grad_grads.size()==n_tensor_pols),
261  update_3rd_derivatives = (third_derivatives.size()==n_tensor_pols),
262  update_4th_derivatives = (fourth_derivatives.size()==n_tensor_pols);
263 
264  // check how many
265  // values/derivatives we have to
266  // compute
267  unsigned int n_values_and_derivatives = 0;
268  if (update_values)
269  n_values_and_derivatives = 1;
270  if (update_grads)
271  n_values_and_derivatives = 2;
272  if (update_grad_grads)
273  n_values_and_derivatives = 3;
275  n_values_and_derivatives = 4;
276  if (update_4th_derivatives)
277  n_values_and_derivatives = 5;
278 
279  // Provide a shortcut if only values are requested. For this case usually the
280  // temporary memory allocation below does not pay off. Also we loop over all
281  // tensor polynomials in a peculiar way to avoid all dynamic memory allocation.
282  // We need to evaluate the polynomial value n_polynomials*dim times, and
283  // need to compute n_polynomials^dim tensor polynomials. Therefore we can split
284  // the loop over the tensor polynomials into one loop over n_polynomials,
285  // evaluate this polynomial for each dimension and multiply it with the
286  // associated n_polynomials^(dim-1) tensor polynomials before moving to the
287  // next polynomial.
288  if (n_values_and_derivatives == 1)
289  {
290  const unsigned int n_polynomials = polynomials.size();
291  const unsigned int factor = n_tensor_pols/n_polynomials;
292 
293  std::fill(values.begin(),values.end(),1.0);
294 
295  for (unsigned int polynomial=0; polynomial<n_polynomials; ++polynomial)
296  {
297  for (unsigned int d=0; d<dim; ++d)
298  {
299  const double value = polynomials[polynomial].value(p(d));
300 
301  for (unsigned int f=0; f<factor; ++f)
302  {
303  unsigned int index = 0;
304  switch (d)
305  {
306  case 0:
307  index = polynomial+f*n_polynomials;
308  break;
309  case 1:
310  index = polynomial*n_polynomials + (f/n_polynomials)*n_polynomials*n_polynomials + f%n_polynomials;
311  break;
312  case 2:
313  index = polynomial*factor + f;
314  break;
315  default:
316  AssertThrow(false, ExcNotImplemented());
317  }
318 
319  const unsigned int i = index_map_inverse[index];
320  values[i] *= value;
321  }
322  }
323  }
324  return;
325  }
326 
327 
328  // Compute the values (and derivatives, if
329  // necessary) of all polynomials at this
330  // evaluation point. To avoid expensive memory allocation,
331  // we use a small amount of memory on the stack, and store the
332  // result in an array (that has enough
333  // fields for any evaluation of values and
334  // derivatives, up to the 4th derivative, for up to 20 polynomials).
335  // If someone uses a larger number of
336  // polynomials, we need to allocate more memory on the heap.
337  std_cxx11::array<std_cxx11::array<double,5>, dim> *v;
338  std_cxx11::array<std_cxx11::array<std_cxx11::array<double,5>, dim>, 20> small_array;
339  std::vector<std_cxx11::array<std_cxx11::array<double,5>, dim> > large_array;
340 
341  const unsigned int n_polynomials = polynomials.size();
342  if (n_polynomials > 20)
343  {
344  large_array.resize(n_polynomials);
345  v = &large_array[0];
346  }
347  else
348  v = &small_array[0];
349 
350  for (unsigned int i=0; i<n_polynomials; ++i)
351  for (unsigned int d=0; d<dim; ++d)
352  polynomials[i].value(p(d), n_values_and_derivatives, &v[i][d][0]);
353 
354  for (unsigned int i=0; i<n_tensor_pols; ++i)
355  {
356  // first get the
357  // one-dimensional indices of
358  // this particular tensor
359  // product polynomial
360  unsigned int indices[dim];
361  compute_index (i, indices);
362 
363  if (update_values)
364  {
365  values[i] = 1;
366  for (unsigned int x=0; x<dim; ++x)
367  values[i] *= v[indices[x]][x][0];
368  }
369 
370  if (update_grads)
371  for (unsigned int d=0; d<dim; ++d)
372  {
373  grads[i][d] = 1.;
374  for (unsigned int x=0; x<dim; ++x)
375  grads[i][d] *= v[indices[x]][x][d==x];
376  }
377 
378  if (update_grad_grads)
379  for (unsigned int d1=0; d1<dim; ++d1)
380  for (unsigned int d2=0; d2<dim; ++d2)
381  {
382  grad_grads[i][d1][d2] = 1.;
383  for (unsigned int x=0; x<dim; ++x)
384  {
385  unsigned int derivative=0;
386  if (d1==x) ++derivative;
387  if (d2==x) ++derivative;
388 
389  grad_grads[i][d1][d2]
390  *= v[indices[x]][x][derivative];
391  }
392  }
393 
395  for (unsigned int d1=0; d1<dim; ++d1)
396  for (unsigned int d2=0; d2<dim; ++d2)
397  for (unsigned int d3=0; d3<dim; ++d3)
398  {
399  third_derivatives[i][d1][d2][d3] = 1.;
400  for (unsigned int x=0; x<dim; ++x)
401  {
402  unsigned int derivative=0;
403  if (d1==x) ++derivative;
404  if (d2==x) ++derivative;
405  if (d3==x) ++derivative;
406 
407  third_derivatives[i][d1][d2][d3]
408  *= v[indices[x]][x][derivative];
409  }
410  }
411 
412  if (update_4th_derivatives)
413  for (unsigned int d1=0; d1<dim; ++d1)
414  for (unsigned int d2=0; d2<dim; ++d2)
415  for (unsigned int d3=0; d3<dim; ++d3)
416  for (unsigned int d4=0; d4<dim; ++d4)
417  {
418  fourth_derivatives[i][d1][d2][d3][d4] = 1.;
419  for (unsigned int x=0; x<dim; ++x)
420  {
421  unsigned int derivative=0;
422  if (d1==x) ++derivative;
423  if (d2==x) ++derivative;
424  if (d3==x) ++derivative;
425  if (d4==x) ++derivative;
426 
427  fourth_derivatives[i][d1][d2][d3][d4]
428  *= v[indices[x]][x][derivative];
429  }
430  }
431  }
432 }
433 
434 
435 
436 
437 /* ------------------- AnisotropicPolynomials -------------- */
438 
439 
440 template <int dim>
442 AnisotropicPolynomials(const std::vector<std::vector<Polynomials::Polynomial<double> > > &pols)
443  :
444  polynomials (pols),
445  n_tensor_pols(get_n_tensor_pols(pols))
446 {
447  Assert (pols.size() == dim, ExcDimensionMismatch(pols.size(), dim));
448  for (unsigned int d=0; d<dim; ++d)
449  Assert (pols[d].size() > 0,
450  ExcMessage ("The number of polynomials must be larger than zero "
451  "for all coordinate directions."));
452 }
453 
454 
455 
456 
457 template <int dim>
458 void
460 compute_index (const unsigned int i,
461  unsigned int (&indices)[dim]) const
462 {
463 #ifdef DEBUG
464  unsigned int n_poly = 1;
465  for (unsigned int d=0; d<dim; ++d)
466  n_poly *= polynomials[d].size();
467  Assert (i < n_poly, ExcInternalError());
468 #endif
469 
470  if (dim==1)
471  internal::compute_tensor_index(i, polynomials[0].size(),
472  0 /*not used*/, indices);
473  else
474  internal::compute_tensor_index(i, polynomials[0].size(),
475  polynomials[1].size(), indices);
476 }
477 
478 
479 
480 template <int dim>
481 double
483  const Point<dim> &p) const
484 {
485  unsigned int indices[dim];
486  compute_index (i, indices);
487 
488  double value=1.;
489  for (unsigned int d=0; d<dim; ++d)
490  value *= polynomials[d][indices[d]].value(p(d));
491 
492  return value;
493 }
494 
495 
496 template <int dim>
499  const Point<dim> &p) const
500 {
501  unsigned int indices[dim];
502  compute_index (i, indices);
503 
504  // compute values and
505  // uni-directional derivatives at
506  // the given point in each
507  // co-ordinate direction
508  std::vector<std::vector<double> > v(dim, std::vector<double> (2));
509  for (unsigned int d=0; d<dim; ++d)
510  polynomials[d][indices[d]].value(p(d), v[d]);
511 
512  Tensor<1,dim> grad;
513  for (unsigned int d=0; d<dim; ++d)
514  {
515  grad[d] = 1.;
516  for (unsigned int x=0; x<dim; ++x)
517  grad[d] *= v[x][d==x];
518  }
519 
520  return grad;
521 }
522 
523 
524 template <int dim>
527  const Point<dim> &p) const
528 {
529  unsigned int indices[dim];
530  compute_index (i, indices);
531 
532  std::vector<std::vector<double> > v(dim, std::vector<double> (3));
533  for (unsigned int d=0; d<dim; ++d)
534  polynomials[d][indices[d]].value(p(d), v[d]);
535 
536  Tensor<2,dim> grad_grad;
537  for (unsigned int d1=0; d1<dim; ++d1)
538  for (unsigned int d2=0; d2<dim; ++d2)
539  {
540  grad_grad[d1][d2] = 1.;
541  for (unsigned int x=0; x<dim; ++x)
542  {
543  unsigned int derivative=0;
544  if (d1==x || d2==x)
545  {
546  if (d1==d2)
547  derivative=2;
548  else
549  derivative=1;
550  }
551  grad_grad[d1][d2] *= v[x][derivative];
552  }
553  }
554 
555  return grad_grad;
556 }
557 
558 
559 
560 
561 template <int dim>
562 void
564 compute (const Point<dim> &p,
565  std::vector<double> &values,
566  std::vector<Tensor<1,dim> > &grads,
567  std::vector<Tensor<2,dim> > &grad_grads,
568  std::vector<Tensor<3,dim> > &third_derivatives,
569  std::vector<Tensor<4,dim> > &fourth_derivatives) const
570 {
571  Assert (values.size()==n_tensor_pols || values.size()==0,
572  ExcDimensionMismatch2(values.size(), n_tensor_pols, 0));
573  Assert (grads.size()==n_tensor_pols|| grads.size()==0,
574  ExcDimensionMismatch2(grads.size(), n_tensor_pols, 0));
575  Assert (grad_grads.size()==n_tensor_pols|| grad_grads.size()==0,
576  ExcDimensionMismatch2(grad_grads.size(), n_tensor_pols, 0));
577  Assert (third_derivatives.size()==n_tensor_pols|| third_derivatives.size()==0,
578  ExcDimensionMismatch2(third_derivatives.size(), n_tensor_pols, 0));
579  Assert (fourth_derivatives.size()==n_tensor_pols|| fourth_derivatives.size()==0,
580  ExcDimensionMismatch2(fourth_derivatives.size(), n_tensor_pols, 0));
581 
582  const bool update_values = (values.size() == n_tensor_pols),
583  update_grads = (grads.size()==n_tensor_pols),
584  update_grad_grads = (grad_grads.size()==n_tensor_pols),
585  update_3rd_derivatives = (third_derivatives.size()==n_tensor_pols),
586  update_4th_derivatives = (fourth_derivatives.size()==n_tensor_pols);
587 
588  // check how many
589  // values/derivatives we have to
590  // compute
591  unsigned int n_values_and_derivatives = 0;
592  if (update_values)
593  n_values_and_derivatives = 1;
594  if (update_grads)
595  n_values_and_derivatives = 2;
596  if (update_grad_grads)
597  n_values_and_derivatives = 3;
599  n_values_and_derivatives = 4;
600  if (update_4th_derivatives)
601  n_values_and_derivatives = 5;
602 
603  // compute the values (and
604  // derivatives, if necessary) of
605  // all polynomials at this
606  // evaluation point
607  std::vector<std::vector<std::vector<double> > > v(dim);
608  for (unsigned int d=0; d<dim; ++d)
609  {
610  v[d].resize (polynomials[d].size());
611  for (unsigned int i=0; i<polynomials[d].size(); ++i)
612  {
613  v[d][i].resize (n_values_and_derivatives, 0.);
614  polynomials[d][i].value(p(d), v[d][i]);
615  };
616  }
617 
618  for (unsigned int i=0; i<n_tensor_pols; ++i)
619  {
620  // first get the
621  // one-dimensional indices of
622  // this particular tensor
623  // product polynomial
624  unsigned int indices[dim];
625  compute_index (i, indices);
626 
627  if (update_values)
628  {
629  values[i] = 1;
630  for (unsigned int x=0; x<dim; ++x)
631  values[i] *= v[x][indices[x]][0];
632  }
633 
634  if (update_grads)
635  for (unsigned int d=0; d<dim; ++d)
636  {
637  grads[i][d] = 1.;
638  for (unsigned int x=0; x<dim; ++x)
639  grads[i][d] *= v[x][indices[x]][d==x ? 1 : 0];
640  }
641 
642  if (update_grad_grads)
643  for (unsigned int d1=0; d1<dim; ++d1)
644  for (unsigned int d2=0; d2<dim; ++d2)
645  {
646  grad_grads[i][d1][d2] = 1.;
647  for (unsigned int x=0; x<dim; ++x)
648  {
649  unsigned int derivative=0;
650  if (d1==x) ++derivative;
651  if (d2==x) ++derivative;
652 
653  grad_grads[i][d1][d2]
654  *= v[x][indices[x]][derivative];
655  }
656  }
657 
659  for (unsigned int d1=0; d1<dim; ++d1)
660  for (unsigned int d2=0; d2<dim; ++d2)
661  for (unsigned int d3=0; d3<dim; ++d3)
662  {
663  third_derivatives[i][d1][d2][d3] = 1.;
664  for (unsigned int x=0; x<dim; ++x)
665  {
666  unsigned int derivative=0;
667  if (d1==x) ++derivative;
668  if (d2==x) ++derivative;
669  if (d3==x) ++derivative;
670 
671  third_derivatives[i][d1][d2][d3]
672  *= v[x][indices[x]][derivative];
673  }
674  }
675 
676  if (update_4th_derivatives)
677  for (unsigned int d1=0; d1<dim; ++d1)
678  for (unsigned int d2=0; d2<dim; ++d2)
679  for (unsigned int d3=0; d3<dim; ++d3)
680  for (unsigned int d4=0; d4<dim; ++d4)
681  {
682  fourth_derivatives[i][d1][d2][d3][d4] = 1.;
683  for (unsigned int x=0; x<dim; ++x)
684  {
685  unsigned int derivative=0;
686  if (d1==x) ++derivative;
687  if (d2==x) ++derivative;
688  if (d3==x) ++derivative;
689  if (d4==x) ++derivative;
690 
691  fourth_derivatives[i][d1][d2][d3][d4]
692  *= v[x][indices[x]][derivative];
693  }
694  }
695  }
696 }
697 
698 
699 
700 template<int dim>
701 unsigned int
703 {
704  return n_tensor_pols;
705 }
706 
707 
708 template <int dim>
709 unsigned int
711 get_n_tensor_pols (const std::vector<std::vector<Polynomials::Polynomial<double> > > &pols)
712 {
713  unsigned int y = 1;
714  for (unsigned int d=0; d<dim; ++d)
715  y *= pols[d].size();
716  return y;
717 }
718 
719 
720 
721 /* ------------------- explicit instantiations -------------- */
725 
729 
730 template class AnisotropicPolynomials<1>;
731 template class AnisotropicPolynomials<2>;
732 template class AnisotropicPolynomials<3>;
733 
734 DEAL_II_NAMESPACE_CLOSE
Tensor< 1, dim > compute_grad(const unsigned int i, const Point< dim > &p) const
Shape function values.
AnisotropicPolynomials(const std::vector< std::vector< Polynomials::Polynomial< double > > > &pols)
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
#define AssertThrow(cond, exc)
Definition: exceptions.h:369
Definition: point.h:89
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:313
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
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()