Reference documentation for deal.II version 8.4.2
mapping_q_generic.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2015 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 
17 #include <deal.II/base/derivative_form.h>
18 #include <deal.II/base/quadrature.h>
19 #include <deal.II/base/qprojector.h>
20 #include <deal.II/base/quadrature_lib.h>
21 #include <deal.II/base/tensor_product_polynomials.h>
22 #include <deal.II/base/memory_consumption.h>
23 #include <deal.II/base/std_cxx11/array.h>
24 #include <deal.II/base/std_cxx11/unique_ptr.h>
25 #include <deal.II/lac/full_matrix.h>
26 #include <deal.II/grid/tria.h>
27 #include <deal.II/grid/tria_iterator.h>
28 #include <deal.II/grid/tria_boundary.h>
29 #include <deal.II/dofs/dof_accessor.h>
30 #include <deal.II/fe/fe_tools.h>
31 #include <deal.II/fe/fe.h>
32 #include <deal.II/fe/fe_values.h>
33 #include <deal.II/fe/mapping_q_generic.h>
34 #include <deal.II/fe/mapping_q1.h>
35 
36 #include <cmath>
37 #include <algorithm>
38 #include <numeric>
39 
40 
41 DEAL_II_NAMESPACE_OPEN
42 
43 namespace internal
44 {
45  namespace MappingQ1
46  {
47  namespace
48  {
49 
50  // These are left as templates on the spatial dimension (even though dim
51  // == spacedim must be true for them to make sense) because templates are
52  // expanded before the compiler eliminates code due to the 'if (dim ==
53  // spacedim)' statement (see the body of the general
54  // transform_real_to_unit_cell).
55  template<int spacedim>
56  Point<1>
57  transform_real_to_unit_cell
58  (const std_cxx11::array<Point<spacedim>, GeometryInfo<1>::vertices_per_cell> &vertices,
59  const Point<spacedim> &p)
60  {
61  Assert(spacedim == 1, ExcInternalError());
62  return Point<1>((p[0] - vertices[0](0))/(vertices[1](0) - vertices[0](0)));
63  }
64 
65 
66 
67  template<int spacedim>
68  Point<2>
69  transform_real_to_unit_cell
70  (const std_cxx11::array<Point<spacedim>, GeometryInfo<2>::vertices_per_cell> &vertices,
71  const Point<spacedim> &p)
72  {
73  Assert(spacedim == 2, ExcInternalError());
74  const double x = p(0);
75  const double y = p(1);
76 
77  const double x0 = vertices[0](0);
78  const double x1 = vertices[1](0);
79  const double x2 = vertices[2](0);
80  const double x3 = vertices[3](0);
81 
82  const double y0 = vertices[0](1);
83  const double y1 = vertices[1](1);
84  const double y2 = vertices[2](1);
85  const double y3 = vertices[3](1);
86 
87  const double a = (x1 - x3)*(y0 - y2) - (x0 - x2)*(y1 - y3);
88  const double b = -(x0 - x1 - x2 + x3)*y + (x - 2*x1 + x3)*y0 - (x - 2*x0 + x2)*y1
89  - (x - x1)*y2 + (x - x0)*y3;
90  const double c = (x0 - x1)*y - (x - x1)*y0 + (x - x0)*y1;
91 
92  const double discriminant = b*b - 4*a*c;
93  // exit if the point is not in the cell (this is the only case where the
94  // discriminant is negative)
95  if (discriminant < 0.0)
96  {
97  AssertThrow (false,
99  }
100 
101  double eta1;
102  double eta2;
103  // special case #1: if a is zero, then use the linear formula
104  if (a == 0.0 && b != 0.0)
105  {
106  eta1 = -c/b;
107  eta2 = -c/b;
108  }
109  // special case #2: if c is very small or the square root of the
110  // discriminant is nearly b.
111  else if (std::abs(c) < 1e-12*std::abs(b)
112  || std::abs(std::sqrt(discriminant) - b) <= 1e-14*std::abs(b))
113  {
114  eta1 = (-b - std::sqrt(discriminant)) / (2*a);
115  eta2 = (-b + std::sqrt(discriminant)) / (2*a);
116  }
117  // finally, use the numerically stable version of the quadratic formula:
118  else
119  {
120  eta1 = 2*c / (-b - std::sqrt(discriminant));
121  eta2 = 2*c / (-b + std::sqrt(discriminant));
122  }
123  // pick the one closer to the center of the cell.
124  const double eta = (std::abs(eta1 - 0.5) < std::abs(eta2 - 0.5)) ? eta1 : eta2;
125 
126  /*
127  * There are two ways to compute xi from eta, but either one may have a
128  * zero denominator.
129  */
130  const double subexpr0 = -eta*x2 + x0*(eta - 1);
131  const double xi_denominator0 = eta*x3 - x1*(eta - 1) + subexpr0;
132  const double max_x = std::max(std::max(std::abs(x0), std::abs(x1)),
133  std::max(std::abs(x2), std::abs(x3)));
134 
135  if (std::abs(xi_denominator0) > 1e-10*max_x)
136  {
137  const double xi = (x + subexpr0)/xi_denominator0;
138  return Point<2>(xi, eta);
139  }
140  else
141  {
142  const double max_y = std::max(std::max(std::abs(y0), std::abs(y1)),
143  std::max(std::abs(y2), std::abs(y3)));
144  const double subexpr1 = -eta*y2 + y0*(eta - 1);
145  const double xi_denominator1 = eta*y3 - y1*(eta - 1) + subexpr1;
146  if (std::abs(xi_denominator1) > 1e-10*max_y)
147  {
148  const double xi = (subexpr1 + y)/xi_denominator1;
149  return Point<2>(xi, eta);
150  }
151  else // give up and try Newton iteration
152  {
153  AssertThrow (false,
155  }
156  }
157  // bogus return to placate compiler. It should not be possible to get
158  // here.
159  Assert(false, ExcInternalError());
160  return Point<2>(std::numeric_limits<double>::quiet_NaN(),
161  std::numeric_limits<double>::quiet_NaN());
162  }
163 
164 
165 
166  template<int spacedim>
167  Point<3>
168  transform_real_to_unit_cell
169  (const std_cxx11::array<Point<spacedim>, GeometryInfo<3>::vertices_per_cell> &/*vertices*/,
170  const Point<spacedim> &/*p*/)
171  {
172  // It should not be possible to get here
173  Assert(false, ExcInternalError());
174  return Point<3>();
175  }
176 
177 
178 
206  template <int dim>
207  struct TransformR2UInitialGuess
208  {
209  static const double KA[GeometryInfo<dim>::vertices_per_cell][dim];
210  static const double Kb[GeometryInfo<dim>::vertices_per_cell];
211  };
212 
213 
214  /*
215  Octave code:
216  M=[0 1; 1 1];
217  K1 = transpose(M) * inverse (M*transpose(M));
218  printf ("{%f, %f},\n", K1' );
219  */
220  template <>
221  const double
222  TransformR2UInitialGuess<1>::
224  {
225  {-1.000000},
226  {1.000000}
227  };
228 
229  template <>
230  const double
231  TransformR2UInitialGuess<1>::
232  Kb[GeometryInfo<1>::vertices_per_cell] = {1.000000, 0.000000};
233 
234 
235  /*
236  Octave code:
237  M=[0 1 0 1;0 0 1 1;1 1 1 1];
238  K2 = transpose(M) * inverse (M*transpose(M));
239  printf ("{%f, %f, %f},\n", K2' );
240  */
241  template <>
242  const double
243  TransformR2UInitialGuess<2>::
245  {
246  {-0.500000, -0.500000},
247  { 0.500000, -0.500000},
248  {-0.500000, 0.500000},
249  { 0.500000, 0.500000}
250  };
251 
252  /*
253  Octave code:
254  M=[0 1 0 1 0 1 0 1;0 0 1 1 0 0 1 1; 0 0 0 0 1 1 1 1; 1 1 1 1 1 1 1 1];
255  K3 = transpose(M) * inverse (M*transpose(M))
256  printf ("{%f, %f, %f, %f},\n", K3' );
257  */
258  template <>
259  const double
260  TransformR2UInitialGuess<2>::
262  {0.750000,0.250000,0.250000,-0.250000 };
263 
264 
265  template <>
266  const double
267  TransformR2UInitialGuess<3>::
269  {
270  {-0.250000, -0.250000, -0.250000},
271  { 0.250000, -0.250000, -0.250000},
272  {-0.250000, 0.250000, -0.250000},
273  { 0.250000, 0.250000, -0.250000},
274  {-0.250000, -0.250000, 0.250000},
275  { 0.250000, -0.250000, 0.250000},
276  {-0.250000, 0.250000, 0.250000},
277  { 0.250000, 0.250000, 0.250000}
278 
279  };
280 
281 
282  template <>
283  const double
284  TransformR2UInitialGuess<3>::
286  {0.500000,0.250000,0.250000,0.000000,0.250000,0.000000,0.000000,-0.250000};
287 
288  template<int dim, int spacedim>
289  Point<dim>
290  transform_real_to_unit_cell_initial_guess (const std::vector<Point<spacedim> > &vertex,
291  const Point<spacedim> &p)
292  {
293  Point<dim> p_unit;
294 
297 
298  KA.fill( (double *)(TransformR2UInitialGuess<dim>::KA) );
299  for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i)
300  Kb(i) = TransformR2UInitialGuess<dim>::Kb[i];
301 
303  for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; v++)
304  for (unsigned int i=0; i<spacedim; ++i)
305  Y(i,v) = vertex[v][i];
306 
307  FullMatrix<double> A(spacedim,dim);
308  Y.mmult(A,KA); // A = Y*KA
309  ::Vector<double> b(spacedim);
310  Y.vmult(b,Kb); // b = Y*Kb
311 
312  for (unsigned int i=0; i<spacedim; ++i)
313  b(i) -= p[i];
314  b*=-1;
315 
316  ::Vector<double> dest(dim);
317 
318  FullMatrix<double> A_1(dim,spacedim);
319  if (dim<spacedim)
320  A_1.left_invert(A);
321  else
322  A_1.invert(A);
323 
324  A_1.vmult(dest,b); //A^{-1}*b
325 
326  for (unsigned int i=0; i<dim; ++i)
327  p_unit[i]=dest(i);
328 
329  return p_unit;
330  }
331  template <int spacedim>
332  void
333  compute_shape_function_values (const unsigned int n_shape_functions,
334  const std::vector<Point<1> > &unit_points,
335  typename ::MappingQGeneric<1,spacedim>::InternalData &data)
336  {
337  (void)n_shape_functions;
338  const unsigned int n_points=unit_points.size();
339  for (unsigned int k = 0 ; k < n_points ; ++k)
340  {
341  double x = unit_points[k](0);
342 
343  if (data.shape_values.size()!=0)
344  {
345  Assert(data.shape_values.size()==n_shape_functions*n_points,
346  ExcInternalError());
347  data.shape(k,0) = 1.-x;
348  data.shape(k,1) = x;
349  }
350  if (data.shape_derivatives.size()!=0)
351  {
352  Assert(data.shape_derivatives.size()==n_shape_functions*n_points,
353  ExcInternalError());
354  data.derivative(k,0)[0] = -1.;
355  data.derivative(k,1)[0] = 1.;
356  }
357  if (data.shape_second_derivatives.size()!=0)
358  {
359  // the following may or may not
360  // work if dim != spacedim
361  Assert (spacedim == 1, ExcNotImplemented());
362 
363  Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
364  ExcInternalError());
365  data.second_derivative(k,0)[0][0] = 0;
366  data.second_derivative(k,1)[0][0] = 0;
367  }
368  if (data.shape_third_derivatives.size()!=0)
369  {
370  // if lower order derivative don't work, neither should this
371  Assert (spacedim == 1, ExcNotImplemented());
372 
373  Assert(data.shape_third_derivatives.size()==n_shape_functions*n_points,
374  ExcInternalError());
375 
376  Tensor<3,1> zero;
377  data.third_derivative(k,0) = zero;
378  data.third_derivative(k,1) = zero;
379  }
380  if (data.shape_fourth_derivatives.size()!=0)
381  {
382  // if lower order derivative don't work, neither should this
383  Assert (spacedim == 1, ExcNotImplemented());
384 
385  Assert(data.shape_fourth_derivatives.size()==n_shape_functions*n_points,
386  ExcInternalError());
387 
388  Tensor<4,1> zero;
389  data.fourth_derivative(k,0) = zero;
390  data.fourth_derivative(k,1) = zero;
391  }
392  }
393  }
394 
395 
396  template <int spacedim>
397  void
398  compute_shape_function_values (const unsigned int n_shape_functions,
399  const std::vector<Point<2> > &unit_points,
400  typename ::MappingQGeneric<2,spacedim>::InternalData &data)
401  {
402  (void)n_shape_functions;
403  const unsigned int n_points=unit_points.size();
404  for (unsigned int k = 0 ; k < n_points ; ++k)
405  {
406  double x = unit_points[k](0);
407  double y = unit_points[k](1);
408 
409  if (data.shape_values.size()!=0)
410  {
411  Assert(data.shape_values.size()==n_shape_functions*n_points,
412  ExcInternalError());
413  data.shape(k,0) = (1.-x)*(1.-y);
414  data.shape(k,1) = x*(1.-y);
415  data.shape(k,2) = (1.-x)*y;
416  data.shape(k,3) = x*y;
417  }
418  if (data.shape_derivatives.size()!=0)
419  {
420  Assert(data.shape_derivatives.size()==n_shape_functions*n_points,
421  ExcInternalError());
422  data.derivative(k,0)[0] = (y-1.);
423  data.derivative(k,1)[0] = (1.-y);
424  data.derivative(k,2)[0] = -y;
425  data.derivative(k,3)[0] = y;
426  data.derivative(k,0)[1] = (x-1.);
427  data.derivative(k,1)[1] = -x;
428  data.derivative(k,2)[1] = (1.-x);
429  data.derivative(k,3)[1] = x;
430  }
431  if (data.shape_second_derivatives.size()!=0)
432  {
433  Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
434  ExcInternalError());
435  data.second_derivative(k,0)[0][0] = 0;
436  data.second_derivative(k,1)[0][0] = 0;
437  data.second_derivative(k,2)[0][0] = 0;
438  data.second_derivative(k,3)[0][0] = 0;
439  data.second_derivative(k,0)[0][1] = 1.;
440  data.second_derivative(k,1)[0][1] = -1.;
441  data.second_derivative(k,2)[0][1] = -1.;
442  data.second_derivative(k,3)[0][1] = 1.;
443  data.second_derivative(k,0)[1][0] = 1.;
444  data.second_derivative(k,1)[1][0] = -1.;
445  data.second_derivative(k,2)[1][0] = -1.;
446  data.second_derivative(k,3)[1][0] = 1.;
447  data.second_derivative(k,0)[1][1] = 0;
448  data.second_derivative(k,1)[1][1] = 0;
449  data.second_derivative(k,2)[1][1] = 0;
450  data.second_derivative(k,3)[1][1] = 0;
451  }
452  if (data.shape_third_derivatives.size()!=0)
453  {
454  Assert(data.shape_third_derivatives.size()==n_shape_functions*n_points,
455  ExcInternalError());
456 
457  Tensor<3,2> zero;
458  for (unsigned int i=0; i<4; ++i)
459  data.third_derivative(k,i) = zero;
460  }
461  if (data.shape_fourth_derivatives.size()!=0)
462  {
463  Assert(data.shape_fourth_derivatives.size()==n_shape_functions*n_points,
464  ExcInternalError());
465  Tensor<4,2> zero;
466  for (unsigned int i=0; i<4; ++i)
467  data.fourth_derivative(k,i) = zero;
468  }
469  }
470  }
471 
472 
473 
474  template <int spacedim>
475  void
476  compute_shape_function_values (const unsigned int n_shape_functions,
477  const std::vector<Point<3> > &unit_points,
478  typename ::MappingQGeneric<3,spacedim>::InternalData &data)
479  {
480  (void)n_shape_functions;
481  const unsigned int n_points=unit_points.size();
482  for (unsigned int k = 0 ; k < n_points ; ++k)
483  {
484  double x = unit_points[k](0);
485  double y = unit_points[k](1);
486  double z = unit_points[k](2);
487 
488  if (data.shape_values.size()!=0)
489  {
490  Assert(data.shape_values.size()==n_shape_functions*n_points,
491  ExcInternalError());
492  data.shape(k,0) = (1.-x)*(1.-y)*(1.-z);
493  data.shape(k,1) = x*(1.-y)*(1.-z);
494  data.shape(k,2) = (1.-x)*y*(1.-z);
495  data.shape(k,3) = x*y*(1.-z);
496  data.shape(k,4) = (1.-x)*(1.-y)*z;
497  data.shape(k,5) = x*(1.-y)*z;
498  data.shape(k,6) = (1.-x)*y*z;
499  data.shape(k,7) = x*y*z;
500  }
501  if (data.shape_derivatives.size()!=0)
502  {
503  Assert(data.shape_derivatives.size()==n_shape_functions*n_points,
504  ExcInternalError());
505  data.derivative(k,0)[0] = (y-1.)*(1.-z);
506  data.derivative(k,1)[0] = (1.-y)*(1.-z);
507  data.derivative(k,2)[0] = -y*(1.-z);
508  data.derivative(k,3)[0] = y*(1.-z);
509  data.derivative(k,4)[0] = (y-1.)*z;
510  data.derivative(k,5)[0] = (1.-y)*z;
511  data.derivative(k,6)[0] = -y*z;
512  data.derivative(k,7)[0] = y*z;
513  data.derivative(k,0)[1] = (x-1.)*(1.-z);
514  data.derivative(k,1)[1] = -x*(1.-z);
515  data.derivative(k,2)[1] = (1.-x)*(1.-z);
516  data.derivative(k,3)[1] = x*(1.-z);
517  data.derivative(k,4)[1] = (x-1.)*z;
518  data.derivative(k,5)[1] = -x*z;
519  data.derivative(k,6)[1] = (1.-x)*z;
520  data.derivative(k,7)[1] = x*z;
521  data.derivative(k,0)[2] = (x-1)*(1.-y);
522  data.derivative(k,1)[2] = x*(y-1.);
523  data.derivative(k,2)[2] = (x-1.)*y;
524  data.derivative(k,3)[2] = -x*y;
525  data.derivative(k,4)[2] = (1.-x)*(1.-y);
526  data.derivative(k,5)[2] = x*(1.-y);
527  data.derivative(k,6)[2] = (1.-x)*y;
528  data.derivative(k,7)[2] = x*y;
529  }
530  if (data.shape_second_derivatives.size()!=0)
531  {
532  // the following may or may not
533  // work if dim != spacedim
534  Assert (spacedim == 3, ExcNotImplemented());
535 
536  Assert(data.shape_second_derivatives.size()==n_shape_functions*n_points,
537  ExcInternalError());
538  data.second_derivative(k,0)[0][0] = 0;
539  data.second_derivative(k,1)[0][0] = 0;
540  data.second_derivative(k,2)[0][0] = 0;
541  data.second_derivative(k,3)[0][0] = 0;
542  data.second_derivative(k,4)[0][0] = 0;
543  data.second_derivative(k,5)[0][0] = 0;
544  data.second_derivative(k,6)[0][0] = 0;
545  data.second_derivative(k,7)[0][0] = 0;
546  data.second_derivative(k,0)[1][1] = 0;
547  data.second_derivative(k,1)[1][1] = 0;
548  data.second_derivative(k,2)[1][1] = 0;
549  data.second_derivative(k,3)[1][1] = 0;
550  data.second_derivative(k,4)[1][1] = 0;
551  data.second_derivative(k,5)[1][1] = 0;
552  data.second_derivative(k,6)[1][1] = 0;
553  data.second_derivative(k,7)[1][1] = 0;
554  data.second_derivative(k,0)[2][2] = 0;
555  data.second_derivative(k,1)[2][2] = 0;
556  data.second_derivative(k,2)[2][2] = 0;
557  data.second_derivative(k,3)[2][2] = 0;
558  data.second_derivative(k,4)[2][2] = 0;
559  data.second_derivative(k,5)[2][2] = 0;
560  data.second_derivative(k,6)[2][2] = 0;
561  data.second_derivative(k,7)[2][2] = 0;
562 
563  data.second_derivative(k,0)[0][1] = (1.-z);
564  data.second_derivative(k,1)[0][1] = -(1.-z);
565  data.second_derivative(k,2)[0][1] = -(1.-z);
566  data.second_derivative(k,3)[0][1] = (1.-z);
567  data.second_derivative(k,4)[0][1] = z;
568  data.second_derivative(k,5)[0][1] = -z;
569  data.second_derivative(k,6)[0][1] = -z;
570  data.second_derivative(k,7)[0][1] = z;
571  data.second_derivative(k,0)[1][0] = (1.-z);
572  data.second_derivative(k,1)[1][0] = -(1.-z);
573  data.second_derivative(k,2)[1][0] = -(1.-z);
574  data.second_derivative(k,3)[1][0] = (1.-z);
575  data.second_derivative(k,4)[1][0] = z;
576  data.second_derivative(k,5)[1][0] = -z;
577  data.second_derivative(k,6)[1][0] = -z;
578  data.second_derivative(k,7)[1][0] = z;
579 
580  data.second_derivative(k,0)[0][2] = (1.-y);
581  data.second_derivative(k,1)[0][2] = -(1.-y);
582  data.second_derivative(k,2)[0][2] = y;
583  data.second_derivative(k,3)[0][2] = -y;
584  data.second_derivative(k,4)[0][2] = -(1.-y);
585  data.second_derivative(k,5)[0][2] = (1.-y);
586  data.second_derivative(k,6)[0][2] = -y;
587  data.second_derivative(k,7)[0][2] = y;
588  data.second_derivative(k,0)[2][0] = (1.-y);
589  data.second_derivative(k,1)[2][0] = -(1.-y);
590  data.second_derivative(k,2)[2][0] = y;
591  data.second_derivative(k,3)[2][0] = -y;
592  data.second_derivative(k,4)[2][0] = -(1.-y);
593  data.second_derivative(k,5)[2][0] = (1.-y);
594  data.second_derivative(k,6)[2][0] = -y;
595  data.second_derivative(k,7)[2][0] = y;
596 
597  data.second_derivative(k,0)[1][2] = (1.-x);
598  data.second_derivative(k,1)[1][2] = x;
599  data.second_derivative(k,2)[1][2] = -(1.-x);
600  data.second_derivative(k,3)[1][2] = -x;
601  data.second_derivative(k,4)[1][2] = -(1.-x);
602  data.second_derivative(k,5)[1][2] = -x;
603  data.second_derivative(k,6)[1][2] = (1.-x);
604  data.second_derivative(k,7)[1][2] = x;
605  data.second_derivative(k,0)[2][1] = (1.-x);
606  data.second_derivative(k,1)[2][1] = x;
607  data.second_derivative(k,2)[2][1] = -(1.-x);
608  data.second_derivative(k,3)[2][1] = -x;
609  data.second_derivative(k,4)[2][1] = -(1.-x);
610  data.second_derivative(k,5)[2][1] = -x;
611  data.second_derivative(k,6)[2][1] = (1.-x);
612  data.second_derivative(k,7)[2][1] = x;
613  }
614  if (data.shape_third_derivatives.size()!=0)
615  {
616  // if lower order derivative don't work, neither should this
617  Assert (spacedim == 3, ExcNotImplemented());
618 
619  Assert(data.shape_third_derivatives.size()==n_shape_functions*n_points,
620  ExcInternalError());
621 
622  for (unsigned int i=0; i<3; ++i)
623  for (unsigned int j=0; j<3; ++j)
624  for (unsigned int l=0; l<3; ++l)
625  if ((i==j)||(j==l)||(l==i))
626  {
627  for (unsigned int m=0; m<8; ++m)
628  data.third_derivative(k,m)[i][j][l] = 0;
629  }
630  else
631  {
632  data.third_derivative(k,0)[i][j][l] = -1.;
633  data.third_derivative(k,1)[i][j][l] = 1.;
634  data.third_derivative(k,2)[i][j][l] = 1.;
635  data.third_derivative(k,3)[i][j][l] = -1.;
636  data.third_derivative(k,4)[i][j][l] = 1.;
637  data.third_derivative(k,5)[i][j][l] = -1.;
638  data.third_derivative(k,6)[i][j][l] = -1.;
639  data.third_derivative(k,7)[i][j][l] = 1.;
640  }
641 
642  }
643  if (data.shape_fourth_derivatives.size()!=0)
644  {
645  // if lower order derivative don't work, neither should this
646  Assert (spacedim == 3, ExcNotImplemented());
647 
648  Assert(data.shape_fourth_derivatives.size()==n_shape_functions*n_points,
649  ExcInternalError());
650  Tensor<4,3> zero;
651  for (unsigned int i=0; i<8; ++i)
652  data.fourth_derivative(k,i) = zero;
653  }
654  }
655  }
656  }
657  }
658 }
659 
660 
661 
662 
663 
664 template<int dim, int spacedim>
665 MappingQGeneric<dim,spacedim>::InternalData::InternalData (const unsigned int polynomial_degree)
666  :
667  polynomial_degree (polynomial_degree),
668  n_shape_functions (Utilities::fixed_power<dim>(polynomial_degree+1))
669 {}
670 
671 
672 
673 template<int dim, int spacedim>
674 std::size_t
676 {
688  MemoryConsumption::memory_consumption (n_shape_functions));
689 }
690 
691 
692 template <int dim, int spacedim>
693 void
695 initialize (const UpdateFlags update_flags,
696  const Quadrature<dim> &q,
697  const unsigned int n_original_q_points)
698 {
699  // store the flags in the internal data object so we can access them
700  // in fill_fe_*_values()
701  this->update_each = update_flags;
702 
703  const unsigned int n_q_points = q.size();
704 
705  // see if we need the (transformation) shape function values
706  // and/or gradients and resize the necessary arrays
708  shape_values.resize(n_shape_functions * n_q_points);
709 
723  shape_derivatives.resize(n_shape_functions * n_q_points);
724 
726  covariant.resize(n_original_q_points);
727 
729  contravariant.resize(n_original_q_points);
730 
732  volume_elements.resize(n_original_q_points);
733 
734  if (this->update_each &
736  shape_second_derivatives.resize(n_shape_functions * n_q_points);
737 
738  if (this->update_each &
740  shape_third_derivatives.resize(n_shape_functions * n_q_points);
741 
742  if (this->update_each &
744  shape_fourth_derivatives.resize(n_shape_functions * n_q_points);
745 
746  // now also fill the various fields with their correct values
748 }
749 
750 
751 
752 template <int dim, int spacedim>
753 void
755 initialize_face (const UpdateFlags update_flags,
756  const Quadrature<dim> &q,
757  const unsigned int n_original_q_points)
758 {
759  initialize (update_flags, q, n_original_q_points);
760 
761  if (dim > 1)
762  {
764  {
765  aux.resize (dim-1, std::vector<Tensor<1,spacedim> > (n_original_q_points));
766 
767  // Compute tangentials to the
768  // unit cell.
769  const unsigned int nfaces = GeometryInfo<dim>::faces_per_cell;
770  unit_tangentials.resize (nfaces*(dim-1),
771  std::vector<Tensor<1,dim> > (n_original_q_points));
772  if (dim==2)
773  {
774  // ensure a counterclockwise
775  // orientation of tangentials
776  static const int tangential_orientation[4]= {-1,1,1,-1};
777  for (unsigned int i=0; i<nfaces; ++i)
778  {
779  Tensor<1,dim> tang;
780  tang[1-i/2]=tangential_orientation[i];
781  std::fill (unit_tangentials[i].begin(),
782  unit_tangentials[i].end(), tang);
783  }
784  }
785  else if (dim==3)
786  {
787  for (unsigned int i=0; i<nfaces; ++i)
788  {
789  Tensor<1,dim> tang1, tang2;
790 
791  const unsigned int nd=
793 
794  // first tangential
795  // vector in direction
796  // of the (nd+1)%3 axis
797  // and inverted in case
798  // of unit inward normal
799  tang1[(nd+1)%dim]=GeometryInfo<dim>::unit_normal_orientation[i];
800  // second tangential
801  // vector in direction
802  // of the (nd+2)%3 axis
803  tang2[(nd+2)%dim]=1.;
804 
805  // same unit tangents
806  // for all quadrature
807  // points on this face
808  std::fill (unit_tangentials[i].begin(),
809  unit_tangentials[i].end(), tang1);
810  std::fill (unit_tangentials[nfaces+i].begin(),
811  unit_tangentials[nfaces+i].end(), tang2);
812  }
813  }
814  }
815  }
816 }
817 
818 
819 
820 namespace
821 {
822  template <int dim>
823  std::vector<unsigned int>
824  get_dpo_vector (const unsigned int degree)
825  {
826  std::vector<unsigned int> dpo(dim+1, 1U);
827  for (unsigned int i=1; i<dpo.size(); ++i)
828  dpo[i]=dpo[i-1]*(degree-1);
829  return dpo;
830  }
831 }
832 
833 
834 
835 template<int dim, int spacedim>
836 void
838 compute_shape_function_values (const std::vector<Point<dim> > &unit_points)
839 {
840  // if the polynomial degree is one, then we can simplify code a bit
841  // by using hard-coded shape functions.
842  if ((polynomial_degree == 1)
843  &&
844  (dim == spacedim))
845  internal::MappingQ1::compute_shape_function_values<spacedim> (n_shape_functions,
846  unit_points, *this);
847  else
848  // otherwise ask an object that describes the polynomial space
849  {
850  const unsigned int n_points=unit_points.size();
851 
852  // Construct the tensor product polynomials used as shape functions for the
853  // Qp mapping of cells at the boundary.
854  const QGaussLobatto<1> line_support_points (polynomial_degree + 1);
856  tensor_pols (Polynomials::generate_complete_Lagrange_basis(line_support_points.get_points()));
857  Assert (n_shape_functions==tensor_pols.n(),
858  ExcInternalError());
859 
860  // then also construct the mapping from lexicographic to the Qp shape function numbering
861  const std::vector<unsigned int>
862  renumber (FETools::
863  lexicographic_to_hierarchic_numbering (
864  FiniteElementData<dim> (get_dpo_vector<dim>(polynomial_degree), 1,
866 
867  std::vector<double> values;
868  std::vector<Tensor<1,dim> > grads;
869  if (shape_values.size()!=0)
870  {
871  Assert(shape_values.size()==n_shape_functions*n_points,
872  ExcInternalError());
873  values.resize(n_shape_functions);
874  }
875  if (shape_derivatives.size()!=0)
876  {
877  Assert(shape_derivatives.size()==n_shape_functions*n_points,
878  ExcInternalError());
879  grads.resize(n_shape_functions);
880  }
881 
882  std::vector<Tensor<2,dim> > grad2;
883  if (shape_second_derivatives.size()!=0)
884  {
885  Assert(shape_second_derivatives.size()==n_shape_functions*n_points,
886  ExcInternalError());
887  grad2.resize(n_shape_functions);
888  }
889 
890  std::vector<Tensor<3,dim> > grad3;
891  if (shape_third_derivatives.size()!=0)
892  {
893  Assert(shape_third_derivatives.size()==n_shape_functions*n_points,
894  ExcInternalError());
895  grad3.resize(n_shape_functions);
896  }
897 
898  std::vector<Tensor<4,dim> > grad4;
899  if (shape_fourth_derivatives.size()!=0)
900  {
901  Assert(shape_fourth_derivatives.size()==n_shape_functions*n_points,
902  ExcInternalError());
903  grad4.resize(n_shape_functions);
904  }
905 
906 
907  if (shape_values.size()!=0 ||
908  shape_derivatives.size()!=0 ||
909  shape_second_derivatives.size()!=0 ||
910  shape_third_derivatives.size()!=0 ||
911  shape_fourth_derivatives.size()!=0 )
912  for (unsigned int point=0; point<n_points; ++point)
913  {
914  tensor_pols.compute(unit_points[point], values, grads, grad2, grad3, grad4);
915 
916  if (shape_values.size()!=0)
917  for (unsigned int i=0; i<n_shape_functions; ++i)
918  shape(point,renumber[i]) = values[i];
919 
920  if (shape_derivatives.size()!=0)
921  for (unsigned int i=0; i<n_shape_functions; ++i)
922  derivative(point,renumber[i]) = grads[i];
923 
924  if (shape_second_derivatives.size()!=0)
925  for (unsigned int i=0; i<n_shape_functions; ++i)
926  second_derivative(point,renumber[i]) = grad2[i];
927 
928  if (shape_third_derivatives.size()!=0)
929  for (unsigned int i=0; i<n_shape_functions; ++i)
930  third_derivative(point,renumber[i]) = grad3[i];
931 
932  if (shape_fourth_derivatives.size()!=0)
933  for (unsigned int i=0; i<n_shape_functions; ++i)
934  fourth_derivative(point,renumber[i]) = grad4[i];
935  }
936  }
937 }
938 
939 
940 namespace
941 {
951  template<int dim>
953  compute_laplace_vector(const unsigned int polynomial_degree)
954  {
955  Table<2,double> lvs;
956 
957  Assert(lvs.n_rows()==0, ExcInternalError());
958  Assert(dim==2 || dim==3, ExcNotImplemented());
959 
960  // for degree==1, we shouldn't have to compute any support points, since all
961  // of them are on the vertices
962  Assert(polynomial_degree>1, ExcInternalError());
963 
964  const unsigned int n_inner = Utilities::fixed_power<dim>(polynomial_degree-1);
965  const unsigned int n_outer = (dim==1) ? 2 :
966  ((dim==2) ?
967  4+4*(polynomial_degree-1) :
968  8+12*(polynomial_degree-1)+6*(polynomial_degree-1)*(polynomial_degree-1));
969 
970 
971  // compute the shape gradients at the quadrature points on the unit cell
972  const QGauss<dim> quadrature(polynomial_degree+1);
973  const unsigned int n_q_points=quadrature.size();
974 
975  typename MappingQGeneric<dim>::InternalData quadrature_data(polynomial_degree);
976  quadrature_data.shape_derivatives.resize(quadrature_data.n_shape_functions *
977  n_q_points);
978  quadrature_data.compute_shape_function_values(quadrature.get_points());
979 
980  // Compute the stiffness matrix of the inner dofs
981  FullMatrix<long double> S(n_inner);
982  for (unsigned int point=0; point<n_q_points; ++point)
983  for (unsigned int i=0; i<n_inner; ++i)
984  for (unsigned int j=0; j<n_inner; ++j)
985  {
986  long double res = 0.;
987  for (unsigned int l=0; l<dim; ++l)
988  res += (long double)quadrature_data.derivative(point, n_outer+i)[l] *
989  (long double)quadrature_data.derivative(point, n_outer+j)[l];
990 
991  S(i,j) += res * (long double)quadrature.weight(point);
992  }
993 
994  // Compute the components of T to be the product of gradients of inner and
995  // outer shape functions.
996  FullMatrix<long double> T(n_inner, n_outer);
997  for (unsigned int point=0; point<n_q_points; ++point)
998  for (unsigned int i=0; i<n_inner; ++i)
999  for (unsigned int k=0; k<n_outer; ++k)
1000  {
1001  long double res = 0.;
1002  for (unsigned int l=0; l<dim; ++l)
1003  res += (long double)quadrature_data.derivative(point, n_outer+i)[l] *
1004  (long double)quadrature_data.derivative(point, k)[l];
1005 
1006  T(i,k) += res *(long double)quadrature.weight(point);
1007  }
1008 
1009  FullMatrix<long double> S_1(n_inner);
1010  S_1.invert(S);
1011 
1012  FullMatrix<long double> S_1_T(n_inner, n_outer);
1013 
1014  // S:=S_1*T
1015  S_1.mmult(S_1_T,T);
1016 
1017  // Resize and initialize the lvs
1018  lvs.reinit (n_inner, n_outer);
1019  for (unsigned int i=0; i<n_inner; ++i)
1020  for (unsigned int k=0; k<n_outer; ++k)
1021  lvs(i,k) = -S_1_T(i,k);
1022 
1023  return lvs;
1024  }
1025 
1026 
1038  template<int dim>
1040  compute_support_point_weights_on_quad(const unsigned int polynomial_degree)
1041  {
1042  Table<2,double> loqvs;
1043 
1044  // in 1d, there are no quads, so return an empty object
1045  if (dim == 1)
1046  return loqvs;
1047 
1048  // we are asked to compute weights for interior support points, but
1049  // there are no interior points if degree==1
1050  if (polynomial_degree == 1)
1051  return loqvs;
1052 
1053  const unsigned int n_inner_2d=(polynomial_degree-1)*(polynomial_degree-1);
1054  const unsigned int n_outer_2d=4+4*(polynomial_degree-1);
1055 
1056  // first check whether we have precomputed the values for some polynomial
1057  // degree; the sizes of arrays is n_inner_2d*n_outer_2d
1058  if (polynomial_degree == 2)
1059  {
1060  // (checked these values against the output of compute_laplace_vector
1061  // again, and found they're indeed right -- just in case someone wonders
1062  // where they come from -- WB)
1063  static const double loqv2[1*8]
1064  = {1/16., 1/16., 1/16., 1/16., 3/16., 3/16., 3/16., 3/16.};
1065  Assert (sizeof(loqv2)/sizeof(loqv2[0]) ==
1066  n_inner_2d * n_outer_2d,
1067  ExcInternalError());
1068 
1069  // copy and return
1070  loqvs.reinit(n_inner_2d, n_outer_2d);
1071  for (unsigned int unit_point=0; unit_point<n_inner_2d; ++unit_point)
1072  for (unsigned int k=0; k<n_outer_2d; ++k)
1073  loqvs[unit_point][k] = loqv2[unit_point*n_outer_2d+k];
1074  }
1075  else
1076  {
1077  // not precomputed, then do so now
1078  loqvs = compute_laplace_vector<2>(polynomial_degree);
1079  }
1080 
1081  // the sum of weights of the points at the outer rim should be one. check
1082  // this
1083  for (unsigned int unit_point=0; unit_point<loqvs.n_rows(); ++unit_point)
1084  Assert(std::fabs(std::accumulate(loqvs[unit_point].begin(),
1085  loqvs[unit_point].end(),0.)-1)<1e-13*polynomial_degree,
1086  ExcInternalError());
1087 
1088  return loqvs;
1089  }
1090 
1091 
1092 
1102  template <int dim>
1104  compute_support_point_weights_on_hex(const unsigned int polynomial_degree)
1105  {
1106  Table<2,double> lohvs;
1107 
1108  // in 1d and 2d, there are no hexes, so return an empty object
1109  if (dim < 3)
1110  return lohvs;
1111 
1112  // we are asked to compute weights for interior support points, but
1113  // there are no interior points if degree==1
1114  if (polynomial_degree == 1)
1115  return lohvs;
1116 
1117  const unsigned int n_inner = Utilities::fixed_power<dim>(polynomial_degree-1);
1118  const unsigned int n_outer = 8+12*(polynomial_degree-1)+6*(polynomial_degree-1)*(polynomial_degree-1);
1119 
1120  // first check whether we have precomputed the values for some polynomial
1121  // degree; the sizes of arrays is n_inner_2d*n_outer_2d
1122  if (polynomial_degree == 2)
1123  {
1124  static const double lohv2[26]
1125  = {1/128., 1/128., 1/128., 1/128., 1/128., 1/128., 1/128., 1/128.,
1126  7/192., 7/192., 7/192., 7/192., 7/192., 7/192., 7/192., 7/192.,
1127  7/192., 7/192., 7/192., 7/192.,
1128  1/12., 1/12., 1/12., 1/12., 1/12., 1/12.
1129  };
1130 
1131  // copy and return
1132  lohvs.reinit(n_inner, n_outer);
1133  for (unsigned int unit_point=0; unit_point<n_inner; ++unit_point)
1134  for (unsigned int k=0; k<n_outer; ++k)
1135  lohvs[unit_point][k] = lohv2[unit_point*n_outer+k];
1136  }
1137  else
1138  {
1139  // not precomputed, then do so now
1140  lohvs = compute_laplace_vector<dim>(polynomial_degree);
1141  }
1142 
1143  // the sum of weights of the points at the outer rim should be one. check
1144  // this
1145  for (unsigned int unit_point=0; unit_point<n_inner; ++unit_point)
1146  Assert(std::fabs(std::accumulate(lohvs[unit_point].begin(),
1147  lohvs[unit_point].end(),0.) - 1)<1e-13*polynomial_degree,
1148  ExcInternalError());
1149 
1150  return lohvs;
1151  }
1152 }
1153 
1154 
1155 
1156 
1157 template<int dim, int spacedim>
1159  :
1160  polynomial_degree(p),
1161  line_support_points(this->polynomial_degree+1),
1162  fe_q(dim == 3 ? new FE_Q<dim>(this->polynomial_degree) : 0),
1163  support_point_weights_on_quad (compute_support_point_weights_on_quad<dim>(this->polynomial_degree)),
1164  support_point_weights_on_hex (compute_support_point_weights_on_hex<dim>(this->polynomial_degree))
1165 {
1166  Assert (p >= 1, ExcMessage ("It only makes sense to create polynomial mappings "
1167  "with a polynomial degree greater or equal to one."));
1168 }
1169 
1170 
1171 
1172 template<int dim, int spacedim>
1174  :
1176  line_support_points(mapping.line_support_points),
1177  fe_q(dim == 3 ? new FE_Q<dim>(*mapping.fe_q) : 0),
1180 {}
1181 
1182 
1183 
1184 
1185 template<int dim, int spacedim>
1188 {
1189  return new MappingQGeneric<dim,spacedim>(*this);
1190 }
1191 
1192 
1193 
1194 
1195 template<int dim, int spacedim>
1196 unsigned int
1198 {
1199  return polynomial_degree;
1200 }
1201 
1202 
1203 
1204 template<int dim, int spacedim>
1208  const Point<dim> &p) const
1209 {
1210  // set up the polynomial space
1211  const QGaussLobatto<1> line_support_points (polynomial_degree + 1);
1213  tensor_pols (Polynomials::generate_complete_Lagrange_basis(line_support_points.get_points()));
1214  Assert (tensor_pols.n() == Utilities::fixed_power<dim>(polynomial_degree+1),
1215  ExcInternalError());
1216 
1217  // then also construct the mapping from lexicographic to the Qp shape function numbering
1218  const std::vector<unsigned int>
1219  renumber (FETools::
1220  lexicographic_to_hierarchic_numbering (
1221  FiniteElementData<dim> (get_dpo_vector<dim>(polynomial_degree), 1,
1222  polynomial_degree)));
1223 
1224  const std::vector<Point<spacedim> > support_points
1225  = this->compute_mapping_support_points(cell);
1226 
1227  Point<spacedim> mapped_point;
1228  for (unsigned int i=0; i<tensor_pols.n(); ++i)
1229  mapped_point += support_points[renumber[i]] * tensor_pols.compute_value (i, p);
1230 
1231  return mapped_point;
1232 }
1233 
1234 
1235 // In the code below, GCC tries to instantiate MappingQGeneric<3,4> when
1236 // seeing which of the overloaded versions of
1237 // do_transform_real_to_unit_cell_internal() to call. This leads to bad
1238 // error messages and, generally, nothing very good. Avoid this by ensuring
1239 // that this class exists, but does not have an inner InternalData
1240 // type, thereby ruling out the codim-1 version of the function
1241 // below when doing overload resolution.
1242 template <>
1243 class MappingQGeneric<3,4>
1244 {};
1245 
1246 namespace
1247 {
1255  template<int dim, int spacedim>
1257  compute_mapped_location_of_point (const typename MappingQGeneric<dim,spacedim>::InternalData &data)
1258  {
1259  AssertDimension (data.shape_values.size(),
1260  data.mapping_support_points.size());
1261 
1262  // use now the InternalData to compute the point in real space.
1263  Point<spacedim> p_real;
1264  for (unsigned int i=0; i<data.mapping_support_points.size(); ++i)
1265  p_real += data.mapping_support_points[i] * data.shape(0,i);
1266 
1267  return p_real;
1268  }
1269 
1270 
1274  template <int dim>
1275  Point<dim>
1276  do_transform_real_to_unit_cell_internal
1277  (const typename Triangulation<dim,dim>::cell_iterator &cell,
1278  const Point<dim> &p,
1279  const Point<dim> &initial_p_unit,
1281  {
1282  const unsigned int spacedim = dim;
1283 
1284  const unsigned int n_shapes=mdata.shape_values.size();
1285  (void)n_shapes;
1286  Assert(n_shapes!=0, ExcInternalError());
1287  AssertDimension (mdata.shape_derivatives.size(), n_shapes);
1288 
1289  std::vector<Point<spacedim> > &points=mdata.mapping_support_points;
1290  AssertDimension (points.size(), n_shapes);
1291 
1292 
1293  // Newton iteration to solve
1294  // f(x)=p(x)-p=0
1295  // where we are looking for 'x' and p(x) is the forward transformation
1296  // from unit to real cell. We solve this using a Newton iteration
1297  // x_{n+1}=x_n-[f'(x)]^{-1}f(x)
1298  // The start value is set to be the linear approximation to the cell
1299 
1300  // The shape values and derivatives of the mapping at this point are
1301  // previously computed.
1302 
1303  Point<dim> p_unit = initial_p_unit;
1304 
1305  mdata.compute_shape_function_values(std::vector<Point<dim> > (1, p_unit));
1306 
1307  Point<spacedim> p_real = compute_mapped_location_of_point<dim,spacedim>(mdata);
1308  Tensor<1,spacedim> f = p_real-p;
1309 
1310  // early out if we already have our point
1311  if (f.norm_square() < 1e-24 * cell->diameter() * cell->diameter())
1312  return p_unit;
1313 
1314  // we need to compare the position of the computed p(x) against the given
1315  // point 'p'. We will terminate the iteration and return 'x' if they are
1316  // less than eps apart. The question is how to choose eps -- or, put maybe
1317  // more generally: in which norm we want these 'p' and 'p(x)' to be eps
1318  // apart.
1319  //
1320  // the question is difficult since we may have to deal with very elongated
1321  // cells where we may achieve 1e-12*h for the distance of these two points
1322  // in the 'long' direction, but achieving this tolerance in the 'short'
1323  // direction of the cell may not be possible
1324  //
1325  // what we do instead is then to terminate iterations if
1326  // \| p(x) - p \|_A < eps
1327  // where the A-norm is somehow induced by the transformation of the cell.
1328  // in particular, we want to measure distances relative to the sizes of
1329  // the cell in its principal directions.
1330  //
1331  // to define what exactly A should be, note that to first order we have
1332  // the following (assuming that x* is the solution of the problem, i.e.,
1333  // p(x*)=p):
1334  // p(x) - p = p(x) - p(x*)
1335  // = -grad p(x) * (x*-x) + higher order terms
1336  // This suggest to measure with a norm that corresponds to
1337  // A = {[grad p(x]^T [grad p(x)]}^{-1}
1338  // because then
1339  // \| p(x) - p \|_A \approx \| x - x* \|
1340  // Consequently, we will try to enforce that
1341  // \| p(x) - p \|_A = \| f \| <= eps
1342  //
1343  // Note that using this norm is a bit dangerous since the norm changes
1344  // in every iteration (A isn't fixed by depends on xk). However, if the
1345  // cell is not too deformed (it may be stretched, but not twisted) then
1346  // the mapping is almost linear and A is indeed constant or nearly so.
1347  const double eps = 1.e-11;
1348  const unsigned int newton_iteration_limit = 20;
1349 
1350  unsigned int newton_iteration = 0;
1351  double last_f_weighted_norm;
1352  do
1353  {
1354 #ifdef DEBUG_TRANSFORM_REAL_TO_UNIT_CELL
1355  std::cout << "Newton iteration " << newton_iteration << std::endl;
1356 #endif
1357 
1358  // f'(x)
1359  Tensor<2,spacedim> df;
1360  for (unsigned int k=0; k<mdata.n_shape_functions; ++k)
1361  {
1362  const Tensor<1,dim> &grad_transform=mdata.derivative(0,k);
1363  const Point<spacedim> &point=points[k];
1364 
1365  for (unsigned int i=0; i<spacedim; ++i)
1366  for (unsigned int j=0; j<dim; ++j)
1367  df[i][j]+=point[i]*grad_transform[j];
1368  }
1369 
1370  // Solve [f'(x)]d=f(x)
1371  Tensor<2,spacedim> df_inverse = invert(df);
1372  const Tensor<1,spacedim> delta = df_inverse * static_cast<const Tensor<1,spacedim>&>(f);
1373 
1374 #ifdef DEBUG_TRANSFORM_REAL_TO_UNIT_CELL
1375  std::cout << " delta=" << delta << std::endl;
1376 #endif
1377 
1378  // do a line search
1379  double step_length = 1;
1380  do
1381  {
1382  // update of p_unit. The spacedim-th component of transformed point
1383  // is simply ignored in codimension one case. When this component is
1384  // not zero, then we are projecting the point to the surface or
1385  // curve identified by the cell.
1386  Point<dim> p_unit_trial = p_unit;
1387  for (unsigned int i=0; i<dim; ++i)
1388  p_unit_trial[i] -= step_length * delta[i];
1389 
1390  // shape values and derivatives
1391  // at new p_unit point
1392  mdata.compute_shape_function_values(std::vector<Point<dim> > (1, p_unit_trial));
1393 
1394  // f(x)
1395  Point<spacedim> p_real_trial = compute_mapped_location_of_point<dim,spacedim>(mdata);
1396  const Tensor<1,spacedim> f_trial = p_real_trial-p;
1397 
1398 #ifdef DEBUG_TRANSFORM_REAL_TO_UNIT_CELL
1399  std::cout << " step_length=" << step_length << std::endl
1400  << " ||f || =" << f.norm() << std::endl
1401  << " ||f*|| =" << f_trial.norm() << std::endl
1402  << " ||f*||_A =" << (df_inverse * f_trial).norm() << std::endl;
1403 #endif
1404 
1405  // see if we are making progress with the current step length
1406  // and if not, reduce it by a factor of two and try again
1407  //
1408  // strictly speaking, we should probably use the same norm as we use
1409  // for the outer algorithm. in practice, line search is just a
1410  // crutch to find a "reasonable" step length, and so using the l2
1411  // norm is probably just fine
1412  if (f_trial.norm() < f.norm())
1413  {
1414  p_real = p_real_trial;
1415  p_unit = p_unit_trial;
1416  f = f_trial;
1417  break;
1418  }
1419  else if (step_length > 0.05)
1420  step_length /= 2;
1421  else
1422  AssertThrow (false,
1424  }
1425  while (true);
1426 
1427  ++newton_iteration;
1428  if (newton_iteration > newton_iteration_limit)
1429  AssertThrow (false,
1431  last_f_weighted_norm = (df_inverse * f).norm();
1432  }
1433  while (last_f_weighted_norm > eps);
1434 
1435  return p_unit;
1436  }
1437 
1438 
1439 
1443  template <int dim>
1444  Point<dim>
1445  do_transform_real_to_unit_cell_internal_codim1
1446  (const typename Triangulation<dim,dim+1>::cell_iterator &cell,
1447  const Point<dim+1> &p,
1448  const Point<dim> &initial_p_unit,
1450  {
1451  const unsigned int spacedim = dim+1;
1452 
1453  const unsigned int n_shapes=mdata.shape_values.size();
1454  (void)n_shapes;
1455  Assert(n_shapes!=0, ExcInternalError());
1456  Assert(mdata.shape_derivatives.size()==n_shapes, ExcInternalError());
1457  Assert(mdata.shape_second_derivatives.size()==n_shapes, ExcInternalError());
1458 
1459  std::vector<Point<spacedim> > &points=mdata.mapping_support_points;
1460  Assert(points.size()==n_shapes, ExcInternalError());
1461 
1462  Point<spacedim> p_minus_F;
1463 
1464  Tensor<1,spacedim> DF[dim];
1465  Tensor<1,spacedim> D2F[dim][dim];
1466 
1467  Point<dim> p_unit = initial_p_unit;
1468  Point<dim> f;
1469  Tensor<2,dim> df;
1470 
1471  // Evaluate first and second derivatives
1472  mdata.compute_shape_function_values(std::vector<Point<dim> > (1, p_unit));
1473 
1474  for (unsigned int k=0; k<mdata.n_shape_functions; ++k)
1475  {
1476  const Tensor<1,dim> &grad_phi_k = mdata.derivative(0,k);
1477  const Tensor<2,dim> &hessian_k = mdata.second_derivative(0,k);
1478  const Point<spacedim> &point_k = points[k];
1479 
1480  for (unsigned int j=0; j<dim; ++j)
1481  {
1482  DF[j] += grad_phi_k[j] * point_k;
1483  for (unsigned int l=0; l<dim; ++l)
1484  D2F[j][l] += hessian_k[j][l] * point_k;
1485  }
1486  }
1487 
1488  p_minus_F = p;
1489  p_minus_F -= compute_mapped_location_of_point<dim,spacedim>(mdata);
1490 
1491 
1492  for (unsigned int j=0; j<dim; ++j)
1493  f[j] = DF[j] * p_minus_F;
1494 
1495  for (unsigned int j=0; j<dim; ++j)
1496  {
1497  f[j] = DF[j] * p_minus_F;
1498  for (unsigned int l=0; l<dim; ++l)
1499  df[j][l] = -DF[j]*DF[l] + D2F[j][l] * p_minus_F;
1500  }
1501 
1502 
1503  const double eps = 1.e-12*cell->diameter();
1504  const unsigned int loop_limit = 10;
1505 
1506  unsigned int loop=0;
1507 
1508  while (f.norm()>eps && loop++<loop_limit)
1509  {
1510  // Solve [df(x)]d=f(x)
1511  const Tensor<1,dim> d = invert(df) * static_cast<const Tensor<1,dim>&>(f);
1512  p_unit -= d;
1513 
1514  for (unsigned int j=0; j<dim; ++j)
1515  {
1516  DF[j].clear();
1517  for (unsigned int l=0; l<dim; ++l)
1518  D2F[j][l].clear();
1519  }
1520 
1521  mdata.compute_shape_function_values(std::vector<Point<dim> > (1, p_unit));
1522 
1523  for (unsigned int k=0; k<mdata.n_shape_functions; ++k)
1524  {
1525  const Tensor<1,dim> &grad_phi_k = mdata.derivative(0,k);
1526  const Tensor<2,dim> &hessian_k = mdata.second_derivative(0,k);
1527  const Point<spacedim> &point_k = points[k];
1528 
1529  for (unsigned int j=0; j<dim; ++j)
1530  {
1531  DF[j] += grad_phi_k[j] * point_k;
1532  for (unsigned int l=0; l<dim; ++l)
1533  D2F[j][l] += hessian_k[j][l] * point_k;
1534  }
1535  }
1536 
1537  //TODO: implement a line search here in much the same way as for
1538  // the corresponding function above that does so for dim==spacedim
1539  p_minus_F = p;
1540  p_minus_F -= compute_mapped_location_of_point<dim,spacedim>(mdata);
1541 
1542  for (unsigned int j=0; j<dim; ++j)
1543  {
1544  f[j] = DF[j] * p_minus_F;
1545  for (unsigned int l=0; l<dim; ++l)
1546  df[j][l] = -DF[j]*DF[l] + D2F[j][l] * p_minus_F;
1547  }
1548 
1549  }
1550 
1551 
1552  // Here we check that in the last execution of while the first
1553  // condition was already wrong, meaning the residual was below
1554  // eps. Only if the first condition failed, loop will have been
1555  // increased and tested, and thus have reached the limit.
1556  AssertThrow (loop<loop_limit, (typename Mapping<dim,spacedim>::ExcTransformationFailed()));
1557 
1558  return p_unit;
1559  }
1560 
1561 
1562 }
1563 
1564 
1565 
1566 // visual studio freaks out when trying to determine if
1567 // do_transform_real_to_unit_cell_internal with dim=3 and spacedim=4 is a good
1568 // candidate. So instead of letting the compiler pick the correct overload, we
1569 // use template specialization to make sure we pick up the right function to
1570 // call:
1571 
1572 template<int dim, int spacedim>
1573 Point<dim>
1577  const Point<spacedim> &,
1578  const Point<dim> &) const
1579 {
1580  // default implementation (should never be called)
1581  Assert(false, ExcInternalError());
1582  return Point<dim>();
1583 }
1584 
1585 template<>
1586 Point<1>
1590  const Point<1> &p,
1591  const Point<1> &initial_p_unit) const
1592 {
1593  const int dim = 1;
1594  const int spacedim = 1;
1595 
1596  const Quadrature<dim> point_quadrature(initial_p_unit);
1597 
1599  if (spacedim>dim)
1600  update_flags |= update_jacobian_grads;
1601  std_cxx11::unique_ptr<InternalData> mdata (get_data(update_flags,
1602  point_quadrature));
1603 
1605 
1606  // dispatch to the various specializations for spacedim=dim,
1607  // spacedim=dim+1, etc
1608  return do_transform_real_to_unit_cell_internal<1>(cell, p, initial_p_unit, *mdata);
1609 }
1610 
1611 template<>
1612 Point<2>
1616  const Point<2> &p,
1617  const Point<2> &initial_p_unit) const
1618 {
1619  const int dim = 2;
1620  const int spacedim = 2;
1621 
1622  const Quadrature<dim> point_quadrature(initial_p_unit);
1623 
1625  if (spacedim>dim)
1626  update_flags |= update_jacobian_grads;
1627  std_cxx11::unique_ptr<InternalData> mdata (get_data(update_flags,
1628  point_quadrature));
1629 
1631 
1632  // dispatch to the various specializations for spacedim=dim,
1633  // spacedim=dim+1, etc
1634  return do_transform_real_to_unit_cell_internal<2>(cell, p, initial_p_unit, *mdata);
1635 }
1636 
1637 template<>
1638 Point<3>
1642  const Point<3> &p,
1643  const Point<3> &initial_p_unit) const
1644 {
1645  const int dim = 3;
1646  const int spacedim = 3;
1647 
1648  const Quadrature<dim> point_quadrature(initial_p_unit);
1649 
1651  if (spacedim>dim)
1652  update_flags |= update_jacobian_grads;
1653  std_cxx11::unique_ptr<InternalData> mdata (get_data(update_flags,
1654  point_quadrature));
1655 
1657 
1658  // dispatch to the various specializations for spacedim=dim,
1659  // spacedim=dim+1, etc
1660  return do_transform_real_to_unit_cell_internal<3>(cell, p, initial_p_unit, *mdata);
1661 }
1662 
1663 template<>
1664 Point<1>
1668  const Point<2> &p,
1669  const Point<1> &initial_p_unit) const
1670 {
1671  const int dim = 1;
1672  const int spacedim = 2;
1673 
1674  const Quadrature<dim> point_quadrature(initial_p_unit);
1675 
1677  if (spacedim>dim)
1678  update_flags |= update_jacobian_grads;
1679  std_cxx11::unique_ptr<InternalData> mdata (get_data(update_flags,
1680  point_quadrature));
1681 
1683 
1684  // dispatch to the various specializations for spacedim=dim,
1685  // spacedim=dim+1, etc
1686  return do_transform_real_to_unit_cell_internal_codim1<1>(cell, p, initial_p_unit, *mdata);
1687 }
1688 
1689 template<>
1690 Point<2>
1694  const Point<3> &p,
1695  const Point<2> &initial_p_unit) const
1696 {
1697  const int dim = 2;
1698  const int spacedim = 3;
1699 
1700  const Quadrature<dim> point_quadrature(initial_p_unit);
1701 
1703  if (spacedim>dim)
1704  update_flags |= update_jacobian_grads;
1705  std_cxx11::unique_ptr<InternalData> mdata (get_data(update_flags,
1706  point_quadrature));
1707 
1709 
1710  // dispatch to the various specializations for spacedim=dim,
1711  // spacedim=dim+1, etc
1712  return do_transform_real_to_unit_cell_internal_codim1<2>(cell, p, initial_p_unit, *mdata);
1713 }
1714 
1715 template<>
1716 Point<1>
1720  const Point<3> &,
1721  const Point<1> &) const
1722 {
1723  Assert (false, ExcNotImplemented());
1724  return Point<1>();
1725 }
1726 
1727 
1728 
1729 template<int dim, int spacedim>
1730 Point<dim>
1733  const Point<spacedim> &p) const
1734 {
1735  // Use an exact formula if one is available. this is only the case
1736  // for Q1 mappings in 1d, and in 2d if dim==spacedim
1737  if ((polynomial_degree == 1) &&
1738  ((dim == 1)
1739  ||
1740  ((dim == 2) && (dim == spacedim))))
1741  {
1742  // The dimension-dependent algorithms are much faster (about 25-45x in
1743  // 2D) but fail most of the time when the given point (p) is not in the
1744  // cell. The dimension-independent Newton algorithm given below is
1745  // slower, but more robust (though it still sometimes fails). Therefore
1746  // this function implements the following strategy based on the
1747  // p's dimension:
1748  //
1749  // * In 1D this mapping is linear, so the mapping is always invertible
1750  // (and the exact formula is known) as long as the cell has non-zero
1751  // length.
1752  // * In 2D the exact (quadratic) formula is called first. If either the
1753  // exact formula does not succeed (negative discriminant in the
1754  // quadratic formula) or succeeds but finds a solution outside of the
1755  // unit cell, then the Newton solver is called. The rationale for the
1756  // second choice is that the exact formula may provide two different
1757  // answers when mapping a point outside of the real cell, but the
1758  // Newton solver (if it converges) will only return one answer.
1759  // Otherwise the exact formula successfully found a point in the unit
1760  // cell and that value is returned.
1761  // * In 3D there is no (known to the authors) exact formula, so the Newton
1762  // algorithm is used.
1763  const std_cxx11::array<Point<spacedim>, GeometryInfo<dim>::vertices_per_cell>
1764  vertices = this->get_vertices(cell);
1765  try
1766  {
1767  switch (dim)
1768  {
1769  case 1:
1770  {
1771  // formula not subject to any issues in 1d
1772  if (spacedim == 1)
1773  return internal::MappingQ1::transform_real_to_unit_cell(vertices, p);
1774  else
1775  {
1776  const std::vector<Point<spacedim> > a (vertices.begin(),
1777  vertices.end());
1778  return internal::MappingQ1::transform_real_to_unit_cell_initial_guess<dim,spacedim>(a,p);
1779  }
1780  }
1781 
1782  case 2:
1783  {
1784  const Point<dim> point
1785  = internal::MappingQ1::transform_real_to_unit_cell(vertices, p);
1786 
1787  // formula not guaranteed to work for points outside of
1788  // the cell. only take the computed point if it lies
1789  // inside the reference cell
1790  const double eps = 1e-15;
1791  if (-eps <= point(1) && point(1) <= 1 + eps &&
1792  -eps <= point(0) && point(0) <= 1 + eps)
1793  {
1794  return point;
1795  }
1796  else
1797  break;
1798  }
1799 
1800  default:
1801  {
1802  // we should get here, based on the if-condition at the top
1803  Assert(false, ExcInternalError());
1804  }
1805  }
1806  }
1808  {
1809  // simply fall through and continue on to the standard Newton code
1810  }
1811  }
1812  else
1813  {
1814  // we can't use an explicit formula,
1815  }
1816 
1817 
1818  Point<dim> initial_p_unit;
1819  if (polynomial_degree == 1)
1820  {
1821  // Find the initial value for the Newton iteration by a normal
1822  // projection to the least square plane determined by the vertices
1823  // of the cell
1824  const std::vector<Point<spacedim> > a
1825  = this->compute_mapping_support_points (cell);
1827  ExcInternalError());
1828  initial_p_unit = internal::MappingQ1::transform_real_to_unit_cell_initial_guess<dim,spacedim>(a,p);
1829  }
1830  else
1831  {
1832  try
1833  {
1834  // Find the initial value for the Newton iteration by a normal
1835  // projection to the least square plane determined by the vertices
1836  // of the cell
1837  //
1838  // we do this by first getting all support points, then
1839  // throwing away all but the vertices, and finally calling
1840  // the same function as above
1841  std::vector<Point<spacedim> > a
1842  = this->compute_mapping_support_points (cell);
1844  initial_p_unit = internal::MappingQ1::transform_real_to_unit_cell_initial_guess<dim,spacedim>(a,p);
1845  }
1846  catch (const typename Mapping<dim,spacedim>::ExcTransformationFailed &)
1847  {
1848  for (unsigned int d=0; d<dim; ++d)
1849  initial_p_unit[d] = 0.5;
1850  }
1851 
1852  // in case the function above should have given us something
1853  // back that lies outside the unit cell (that might happen
1854  // because we may have given a point 'p' that lies inside the
1855  // cell with the higher order mapping, but outside the Q1-mapped
1856  // reference cell), then project it back into the reference cell
1857  // in hopes that this gives a better starting point to the
1858  // following iteration
1859  initial_p_unit = GeometryInfo<dim>::project_to_unit_cell(initial_p_unit);
1860  }
1861 
1862  // perform the Newton iteration and return the result. note that
1863  // this statement may throw an exception, which we simply pass up to
1864  // the caller
1865  return this->transform_real_to_unit_cell_internal(cell, p, initial_p_unit);
1866 }
1867 
1868 
1869 
1870 template<int dim, int spacedim>
1873 {
1874  // add flags if the respective quantities are necessary to compute
1875  // what we need. note that some flags appear in both the conditions
1876  // and in subsequent set operations. this leads to some circular
1877  // logic. the only way to treat this is to iterate. since there are
1878  // 5 if-clauses in the loop, it will take at most 5 iterations to
1879  // converge. do them:
1880  UpdateFlags out = in;
1881  for (unsigned int i=0; i<5; ++i)
1882  {
1883  // The following is a little incorrect:
1884  // If not applied on a face,
1885  // update_boundary_forms does not
1886  // make sense. On the other hand,
1887  // it is necessary on a
1888  // face. Currently,
1889  // update_boundary_forms is simply
1890  // ignored for the interior of a
1891  // cell.
1892  if (out & (update_JxW_values
1894  out |= update_boundary_forms;
1895 
1903 
1904  if (out & (update_inverse_jacobians
1909 
1910  // The contravariant transformation
1911  // used in the Piola transformation, which
1912  // requires the determinant of the
1913  // Jacobi matrix of the transformation.
1914  // Because we have no way of knowing here whether the finite
1915  // elements wants to use the contravariant of the Piola
1916  // transforms, we add the JxW values to the list of flags to be
1917  // updated for each cell.
1919  out |= update_JxW_values;
1920 
1921  if (out & update_normal_vectors)
1922  out |= update_JxW_values;
1923  }
1924 
1925  return out;
1926 }
1927 
1928 
1929 
1930 template<int dim, int spacedim>
1933  const Quadrature<dim> &q) const
1934 {
1936  data->initialize (this->requires_update_flags(update_flags), q, q.size());
1937 
1938  return data;
1939 }
1940 
1941 
1942 
1943 template<int dim, int spacedim>
1946  const Quadrature<dim-1> &quadrature) const
1947 {
1949  data->initialize_face (this->requires_update_flags(update_flags),
1951  quadrature.size());
1952 
1953  return data;
1954 }
1955 
1956 
1957 
1958 template<int dim, int spacedim>
1961  const Quadrature<dim-1>& quadrature) const
1962 {
1964  data->initialize_face (this->requires_update_flags(update_flags),
1966  quadrature.size());
1967 
1968  return data;
1969 }
1970 
1971 
1972 
1973 namespace internal
1974 {
1975  namespace
1976  {
1983  template <int dim, int spacedim>
1984  void
1985  maybe_compute_q_points (const typename QProjector<dim>::DataSetDescriptor data_set,
1986  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
1987  std::vector<Point<spacedim> > &quadrature_points)
1988  {
1989  const UpdateFlags update_flags = data.update_each;
1990 
1991  if (update_flags & update_quadrature_points)
1992  {
1993  for (unsigned int point=0; point<quadrature_points.size(); ++point)
1994  {
1995  const double *shape = &data.shape(point+data_set,0);
1996  Point<spacedim> result = (shape[0] *
1997  data.mapping_support_points[0]);
1998  for (unsigned int k=1; k<data.n_shape_functions; ++k)
1999  for (unsigned int i=0; i<spacedim; ++i)
2000  result[i] += shape[k] * data.mapping_support_points[k][i];
2001  quadrature_points[point] = result;
2002  }
2003  }
2004  }
2005 
2006 
2014  template <int dim, int spacedim>
2015  void
2016  maybe_update_Jacobians (const CellSimilarity::Similarity cell_similarity,
2017  const typename ::QProjector<dim>::DataSetDescriptor data_set,
2018  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data)
2019  {
2020  const UpdateFlags update_flags = data.update_each;
2021 
2022  if (update_flags & update_contravariant_transformation)
2023  // if the current cell is just a
2024  // translation of the previous one, no
2025  // need to recompute jacobians...
2026  if (cell_similarity != CellSimilarity::translation)
2027  {
2028  const unsigned int n_q_points = data.contravariant.size();
2029 
2030  std::fill(data.contravariant.begin(), data.contravariant.end(),
2032 
2033  Assert (data.n_shape_functions > 0, ExcInternalError());
2034  const Tensor<1,spacedim> *supp_pts =
2035  &data.mapping_support_points[0];
2036 
2037  for (unsigned int point=0; point<n_q_points; ++point)
2038  {
2039  const Tensor<1,dim> *data_derv =
2040  &data.derivative(point+data_set, 0);
2041 
2042  double result [spacedim][dim];
2043 
2044  // peel away part of sum to avoid zeroing the
2045  // entries and adding for the first time
2046  for (unsigned int i=0; i<spacedim; ++i)
2047  for (unsigned int j=0; j<dim; ++j)
2048  result[i][j] = data_derv[0][j] * supp_pts[0][i];
2049  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2050  for (unsigned int i=0; i<spacedim; ++i)
2051  for (unsigned int j=0; j<dim; ++j)
2052  result[i][j] += data_derv[k][j] * supp_pts[k][i];
2053 
2054  // write result into contravariant data. for
2055  // j=dim in the case dim<spacedim, there will
2056  // never be any nonzero data that arrives in
2057  // here, so it is ok anyway because it was
2058  // initialized to zero at the initialization
2059  for (unsigned int i=0; i<spacedim; ++i)
2060  for (unsigned int j=0; j<dim; ++j)
2061  data.contravariant[point][i][j] = result[i][j];
2062  }
2063  }
2064 
2065  if (update_flags & update_covariant_transformation)
2066  if (cell_similarity != CellSimilarity::translation)
2067  {
2068  const unsigned int n_q_points = data.contravariant.size();
2069  for (unsigned int point=0; point<n_q_points; ++point)
2070  {
2071  data.covariant[point] = (data.contravariant[point]).covariant_form();
2072  }
2073  }
2074 
2075  if (update_flags & update_volume_elements)
2076  if (cell_similarity != CellSimilarity::translation)
2077  {
2078  const unsigned int n_q_points = data.contravariant.size();
2079  for (unsigned int point=0; point<n_q_points; ++point)
2080  data.volume_elements[point] = data.contravariant[point].determinant();
2081  }
2082 
2083  }
2084 
2091  template <int dim, int spacedim>
2092  void
2093  maybe_update_jacobian_grads (const CellSimilarity::Similarity cell_similarity,
2094  const typename QProjector<dim>::DataSetDescriptor data_set,
2095  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2096  std::vector<DerivativeForm<2,dim,spacedim> > &jacobian_grads)
2097  {
2098  const UpdateFlags update_flags = data.update_each;
2099  if (update_flags & update_jacobian_grads)
2100  {
2101  const unsigned int n_q_points = jacobian_grads.size();
2102 
2103  if (cell_similarity != CellSimilarity::translation)
2104  {
2105  for (unsigned int point=0; point<n_q_points; ++point)
2106  {
2107  const Tensor<2,dim> *second =
2108  &data.second_derivative(point+data_set, 0);
2109  double result [spacedim][dim][dim];
2110  for (unsigned int i=0; i<spacedim; ++i)
2111  for (unsigned int j=0; j<dim; ++j)
2112  for (unsigned int l=0; l<dim; ++l)
2113  result[i][j][l] = (second[0][j][l] *
2114  data.mapping_support_points[0][i]);
2115  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2116  for (unsigned int i=0; i<spacedim; ++i)
2117  for (unsigned int j=0; j<dim; ++j)
2118  for (unsigned int l=0; l<dim; ++l)
2119  result[i][j][l]
2120  += (second[k][j][l]
2121  *
2122  data.mapping_support_points[k][i]);
2123 
2124  for (unsigned int i=0; i<spacedim; ++i)
2125  for (unsigned int j=0; j<dim; ++j)
2126  for (unsigned int l=0; l<dim; ++l)
2127  jacobian_grads[point][i][j][l] = result[i][j][l];
2128  }
2129  }
2130  }
2131  }
2132 
2139  template <int dim, int spacedim>
2140  void
2141  maybe_update_jacobian_pushed_forward_grads (const CellSimilarity::Similarity cell_similarity,
2142  const typename QProjector<dim>::DataSetDescriptor data_set,
2143  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2144  std::vector<Tensor<3,spacedim> > &jacobian_pushed_forward_grads)
2145  {
2146  const UpdateFlags update_flags = data.update_each;
2147  if (update_flags & update_jacobian_pushed_forward_grads)
2148  {
2149  const unsigned int n_q_points = jacobian_pushed_forward_grads.size();
2150 
2151  if (cell_similarity != CellSimilarity::translation)
2152  {
2153  double tmp[spacedim][spacedim][spacedim];
2154  for (unsigned int point=0; point<n_q_points; ++point)
2155  {
2156  const Tensor<2,dim> *second =
2157  &data.second_derivative(point+data_set, 0);
2158  double result [spacedim][dim][dim];
2159  for (unsigned int i=0; i<spacedim; ++i)
2160  for (unsigned int j=0; j<dim; ++j)
2161  for (unsigned int l=0; l<dim; ++l)
2162  result[i][j][l] = (second[0][j][l] *
2163  data.mapping_support_points[0][i]);
2164  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2165  for (unsigned int i=0; i<spacedim; ++i)
2166  for (unsigned int j=0; j<dim; ++j)
2167  for (unsigned int l=0; l<dim; ++l)
2168  result[i][j][l]
2169  += (second[k][j][l]
2170  *
2171  data.mapping_support_points[k][i]);
2172 
2173  // first push forward the j-components
2174  for (unsigned int i=0; i<spacedim; ++i)
2175  for (unsigned int j=0; j<spacedim; ++j)
2176  for (unsigned int l=0; l<dim; ++l)
2177  {
2178  tmp[i][j][l] = result[i][0][l] *
2179  data.covariant[point][j][0];
2180  for (unsigned int jr=1; jr<dim; ++jr)
2181  {
2182  tmp[i][j][l] += result[i][jr][l] *
2183  data.covariant[point][j][jr];
2184  }
2185  }
2186 
2187  // now, pushing forward the l-components
2188  for (unsigned int i=0; i<spacedim; ++i)
2189  for (unsigned int j=0; j<spacedim; ++j)
2190  for (unsigned int l=0; l<spacedim; ++l)
2191  {
2192  jacobian_pushed_forward_grads[point][i][j][l] = tmp[i][j][0] *
2193  data.covariant[point][l][0];
2194  for (unsigned int lr=1; lr<dim; ++lr)
2195  {
2196  jacobian_pushed_forward_grads[point][i][j][l] += tmp[i][j][lr] *
2197  data.covariant[point][l][lr];
2198  }
2199 
2200  }
2201  }
2202  }
2203  }
2204  }
2205 
2212  template <int dim, int spacedim>
2213  void
2214  maybe_update_jacobian_2nd_derivatives (const CellSimilarity::Similarity cell_similarity,
2215  const typename QProjector<dim>::DataSetDescriptor data_set,
2216  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2217  std::vector<DerivativeForm<3,dim,spacedim> > &jacobian_2nd_derivatives)
2218  {
2219  const UpdateFlags update_flags = data.update_each;
2220  if (update_flags & update_jacobian_2nd_derivatives)
2221  {
2222  const unsigned int n_q_points = jacobian_2nd_derivatives.size();
2223 
2224  if (cell_similarity != CellSimilarity::translation)
2225  {
2226  for (unsigned int point=0; point<n_q_points; ++point)
2227  {
2228  const Tensor<3,dim> *third =
2229  &data.third_derivative(point+data_set, 0);
2230  double result [spacedim][dim][dim][dim];
2231  for (unsigned int i=0; i<spacedim; ++i)
2232  for (unsigned int j=0; j<dim; ++j)
2233  for (unsigned int l=0; l<dim; ++l)
2234  for (unsigned int m=0; m<dim; ++m)
2235  result[i][j][l][m] = (third[0][j][l][m] *
2236  data.mapping_support_points[0][i]);
2237  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2238  for (unsigned int i=0; i<spacedim; ++i)
2239  for (unsigned int j=0; j<dim; ++j)
2240  for (unsigned int l=0; l<dim; ++l)
2241  for (unsigned int m=0; m<dim; ++m)
2242  result[i][j][l][m]
2243  += (third[k][j][l][m]
2244  *
2245  data.mapping_support_points[k][i]);
2246 
2247  for (unsigned int i=0; i<spacedim; ++i)
2248  for (unsigned int j=0; j<dim; ++j)
2249  for (unsigned int l=0; l<dim; ++l)
2250  for (unsigned int m=0; m<dim; ++m)
2251  jacobian_2nd_derivatives[point][i][j][l][m] = result[i][j][l][m];
2252  }
2253  }
2254  }
2255  }
2256 
2264  template <int dim, int spacedim>
2265  void
2266  maybe_update_jacobian_pushed_forward_2nd_derivatives (const CellSimilarity::Similarity cell_similarity,
2267  const typename QProjector<dim>::DataSetDescriptor data_set,
2268  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2269  std::vector<Tensor<4,spacedim> > &jacobian_pushed_forward_2nd_derivatives)
2270  {
2271  const UpdateFlags update_flags = data.update_each;
2273  {
2274  const unsigned int n_q_points = jacobian_pushed_forward_2nd_derivatives.size();
2275 
2276  if (cell_similarity != CellSimilarity::translation)
2277  {
2278  double tmp[spacedim][spacedim][spacedim][spacedim];
2279  for (unsigned int point=0; point<n_q_points; ++point)
2280  {
2281  const Tensor<3,dim> *third =
2282  &data.third_derivative(point+data_set, 0);
2283  double result [spacedim][dim][dim][dim];
2284  for (unsigned int i=0; i<spacedim; ++i)
2285  for (unsigned int j=0; j<dim; ++j)
2286  for (unsigned int l=0; l<dim; ++l)
2287  for (unsigned int m=0; m<dim; ++m)
2288  result[i][j][l][m] = (third[0][j][l][m] *
2289  data.mapping_support_points[0][i]);
2290  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2291  for (unsigned int i=0; i<spacedim; ++i)
2292  for (unsigned int j=0; j<dim; ++j)
2293  for (unsigned int l=0; l<dim; ++l)
2294  for (unsigned int m=0; m<dim; ++m)
2295  result[i][j][l][m]
2296  += (third[k][j][l][m]
2297  *
2298  data.mapping_support_points[k][i]);
2299 
2300  // push forward the j-coordinate
2301  for (unsigned int i=0; i<spacedim; ++i)
2302  for (unsigned int j=0; j<spacedim; ++j)
2303  for (unsigned int l=0; l<dim; ++l)
2304  for (unsigned int m=0; m<dim; ++m)
2305  {
2306  jacobian_pushed_forward_2nd_derivatives[point][i][j][l][m]
2307  = result[i][0][l][m]*
2308  data.covariant[point][j][0];
2309  for (unsigned int jr=1; jr<dim; ++jr)
2310  jacobian_pushed_forward_2nd_derivatives[point][i][j][l][m]
2311  += result[i][jr][l][m]*
2312  data.covariant[point][j][jr];
2313  }
2314 
2315  // push forward the l-coordinate
2316  for (unsigned int i=0; i<spacedim; ++i)
2317  for (unsigned int j=0; j<spacedim; ++j)
2318  for (unsigned int l=0; l<spacedim; ++l)
2319  for (unsigned int m=0; m<dim; ++m)
2320  {
2321  tmp[i][j][l][m]
2322  = jacobian_pushed_forward_2nd_derivatives[point][i][j][0][m]*
2323  data.covariant[point][l][0];
2324  for (unsigned int lr=1; lr<dim; ++lr)
2325  tmp[i][j][l][m]
2326  += jacobian_pushed_forward_2nd_derivatives[point][i][j][lr][m]*
2327  data.covariant[point][l][lr];
2328  }
2329 
2330  // push forward the m-coordinate
2331  for (unsigned int i=0; i<spacedim; ++i)
2332  for (unsigned int j=0; j<spacedim; ++j)
2333  for (unsigned int l=0; l<spacedim; ++l)
2334  for (unsigned int m=0; m<spacedim; ++m)
2335  {
2336  jacobian_pushed_forward_2nd_derivatives[point][i][j][l][m]
2337  = tmp[i][j][l][0]*
2338  data.covariant[point][m][0];
2339  for (unsigned int mr=1; mr<dim; ++mr)
2340  jacobian_pushed_forward_2nd_derivatives[point][i][j][l][m]
2341  += tmp[i][j][l][mr]*
2342  data.covariant[point][m][mr];
2343  }
2344  }
2345  }
2346  }
2347  }
2348 
2355  template <int dim, int spacedim>
2356  void
2357  maybe_update_jacobian_3rd_derivatives (const CellSimilarity::Similarity cell_similarity,
2358  const typename QProjector<dim>::DataSetDescriptor data_set,
2359  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2360  std::vector<DerivativeForm<4,dim,spacedim> > &jacobian_3rd_derivatives)
2361  {
2362  const UpdateFlags update_flags = data.update_each;
2363  if (update_flags & update_jacobian_3rd_derivatives)
2364  {
2365  const unsigned int n_q_points = jacobian_3rd_derivatives.size();
2366 
2367  if (cell_similarity != CellSimilarity::translation)
2368  {
2369  for (unsigned int point=0; point<n_q_points; ++point)
2370  {
2371  const Tensor<4,dim> *fourth =
2372  &data.fourth_derivative(point+data_set, 0);
2373  double result [spacedim][dim][dim][dim][dim];
2374  for (unsigned int i=0; i<spacedim; ++i)
2375  for (unsigned int j=0; j<dim; ++j)
2376  for (unsigned int l=0; l<dim; ++l)
2377  for (unsigned int m=0; m<dim; ++m)
2378  for (unsigned int n=0; n<dim; ++n)
2379  result[i][j][l][m][n] = (fourth[0][j][l][m][n] *
2380  data.mapping_support_points[0][i]);
2381  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2382  for (unsigned int i=0; i<spacedim; ++i)
2383  for (unsigned int j=0; j<dim; ++j)
2384  for (unsigned int l=0; l<dim; ++l)
2385  for (unsigned int m=0; m<dim; ++m)
2386  for (unsigned int n=0; n<dim; ++n)
2387  result[i][j][l][m][n]
2388  += (fourth[k][j][l][m][n]
2389  *
2390  data.mapping_support_points[k][i]);
2391 
2392  for (unsigned int i=0; i<spacedim; ++i)
2393  for (unsigned int j=0; j<dim; ++j)
2394  for (unsigned int l=0; l<dim; ++l)
2395  for (unsigned int m=0; m<dim; ++m)
2396  for (unsigned int n=0; n<dim; ++n)
2397  jacobian_3rd_derivatives[point][i][j][l][m][n] = result[i][j][l][m][n];
2398  }
2399  }
2400  }
2401  }
2402 
2409  template <int dim, int spacedim>
2410  void
2411  maybe_update_jacobian_pushed_forward_3rd_derivatives (const CellSimilarity::Similarity cell_similarity,
2412  const typename QProjector<dim>::DataSetDescriptor data_set,
2413  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2414  std::vector<Tensor<5,spacedim> > &jacobian_pushed_forward_3rd_derivatives)
2415  {
2416  const UpdateFlags update_flags = data.update_each;
2418  {
2419  const unsigned int n_q_points = jacobian_pushed_forward_3rd_derivatives.size();
2420 
2421  if (cell_similarity != CellSimilarity::translation)
2422  {
2423  double tmp[spacedim][spacedim][spacedim][spacedim][spacedim];
2424  for (unsigned int point=0; point<n_q_points; ++point)
2425  {
2426  const Tensor<4,dim> *fourth =
2427  &data.fourth_derivative(point+data_set, 0);
2428  double result [spacedim][dim][dim][dim][dim];
2429  for (unsigned int i=0; i<spacedim; ++i)
2430  for (unsigned int j=0; j<dim; ++j)
2431  for (unsigned int l=0; l<dim; ++l)
2432  for (unsigned int m=0; m<dim; ++m)
2433  for (unsigned int n=0; n<dim; ++n)
2434  result[i][j][l][m][n] = (fourth[0][j][l][m][n] *
2435  data.mapping_support_points[0][i]);
2436  for (unsigned int k=1; k<data.n_shape_functions; ++k)
2437  for (unsigned int i=0; i<spacedim; ++i)
2438  for (unsigned int j=0; j<dim; ++j)
2439  for (unsigned int l=0; l<dim; ++l)
2440  for (unsigned int m=0; m<dim; ++m)
2441  for (unsigned int n=0; n<dim; ++n)
2442  result[i][j][l][m][n]
2443  += (fourth[k][j][l][m][n]
2444  *
2445  data.mapping_support_points[k][i]);
2446 
2447  // push-forward the j-coordinate
2448  for (unsigned int i=0; i<spacedim; ++i)
2449  for (unsigned int j=0; j<spacedim; ++j)
2450  for (unsigned int l=0; l<dim; ++l)
2451  for (unsigned int m=0; m<dim; ++m)
2452  for (unsigned int n=0; n<dim; ++n)
2453  {
2454  tmp[i][j][l][m][n] = result[i][0][l][m][n] *
2455  data.covariant[point][j][0];
2456  for (unsigned int jr=1; jr<dim; ++jr)
2457  tmp[i][j][l][m][n] += result[i][jr][l][m][n] *
2458  data.covariant[point][j][jr];
2459  }
2460 
2461  // push-forward the l-coordinate
2462  for (unsigned int i=0; i<spacedim; ++i)
2463  for (unsigned int j=0; j<spacedim; ++j)
2464  for (unsigned int l=0; l<spacedim; ++l)
2465  for (unsigned int m=0; m<dim; ++m)
2466  for (unsigned int n=0; n<dim; ++n)
2467  {
2468  jacobian_pushed_forward_3rd_derivatives[point][i][j][l][m][n]
2469  = tmp[i][j][0][m][n] *
2470  data.covariant[point][l][0];
2471  for (unsigned int lr=1; lr<dim; ++lr)
2472  jacobian_pushed_forward_3rd_derivatives[point][i][j][l][m][n]
2473  += tmp[i][j][lr][m][n] *
2474  data.covariant[point][l][lr];
2475  }
2476 
2477  // push-forward the m-coordinate
2478  for (unsigned int i=0; i<spacedim; ++i)
2479  for (unsigned int j=0; j<spacedim; ++j)
2480  for (unsigned int l=0; l<spacedim; ++l)
2481  for (unsigned int m=0; m<spacedim; ++m)
2482  for (unsigned int n=0; n<dim; ++n)
2483  {
2484  tmp[i][j][l][m][n]
2485  = jacobian_pushed_forward_3rd_derivatives[point][i][j][l][0][n] *
2486  data.covariant[point][m][0];
2487  for (unsigned int mr=1; mr<dim; ++mr)
2488  tmp[i][j][l][m][n]
2489  += jacobian_pushed_forward_3rd_derivatives[point][i][j][l][mr][n] *
2490  data.covariant[point][m][mr];
2491  }
2492 
2493  // push-forward the n-coordinate
2494  for (unsigned int i=0; i<spacedim; ++i)
2495  for (unsigned int j=0; j<spacedim; ++j)
2496  for (unsigned int l=0; l<spacedim; ++l)
2497  for (unsigned int m=0; m<spacedim; ++m)
2498  for (unsigned int n=0; n<spacedim; ++n)
2499  {
2500  jacobian_pushed_forward_3rd_derivatives[point][i][j][l][m][n]
2501  = tmp[i][j][l][m][0] *
2502  data.covariant[point][n][0];
2503  for (unsigned int nr=1; nr<dim; ++nr)
2504  jacobian_pushed_forward_3rd_derivatives[point][i][j][l][m][n]
2505  += tmp[i][j][l][m][nr] *
2506  data.covariant[point][n][nr];
2507  }
2508  }
2509  }
2510  }
2511  }
2512  }
2513 }
2514 
2515 
2516 
2517 
2518 template<int dim, int spacedim>
2519 CellSimilarity::Similarity
2522  const CellSimilarity::Similarity cell_similarity,
2523  const Quadrature<dim> &quadrature,
2524  const typename Mapping<dim,spacedim>::InternalDataBase &internal_data,
2526 {
2527  // ensure that the following static_cast is really correct:
2528  Assert (dynamic_cast<const InternalData *>(&internal_data) != 0,
2529  ExcInternalError());
2530  const InternalData &data = static_cast<const InternalData &>(internal_data);
2531 
2532  const unsigned int n_q_points=quadrature.size();
2533 
2534  // if necessary, recompute the support points of the transformation of this cell
2535  // (note that we need to first check the triangulation pointer, since otherwise
2536  // the second test might trigger an exception if the triangulations are not the
2537  // same)
2538  if ((data.mapping_support_points.size() == 0)
2539  ||
2540  (&cell->get_triangulation() !=
2541  &data.cell_of_current_support_points->get_triangulation())
2542  ||
2543  (cell != data.cell_of_current_support_points))
2544  {
2546  data.cell_of_current_support_points = cell;
2547  }
2548 
2549  internal::maybe_compute_q_points<dim,spacedim> (QProjector<dim>::DataSetDescriptor::cell (),
2550  data,
2551  output_data.quadrature_points);
2552  internal::maybe_update_Jacobians<dim,spacedim> (cell_similarity,
2554  data);
2555 
2556  const UpdateFlags update_flags = data.update_each;
2557  const std::vector<double> &weights=quadrature.get_weights();
2558 
2559  // Multiply quadrature weights by absolute value of Jacobian determinants or
2560  // the area element g=sqrt(DX^t DX) in case of codim > 0
2561 
2562  if (update_flags & (update_normal_vectors
2563  | update_JxW_values))
2564  {
2565  AssertDimension (output_data.JxW_values.size(), n_q_points);
2566 
2567  Assert( !(update_flags & update_normal_vectors ) ||
2568  (output_data.normal_vectors.size() == n_q_points),
2569  ExcDimensionMismatch(output_data.normal_vectors.size(), n_q_points));
2570 
2571 
2572  if (cell_similarity != CellSimilarity::translation)
2573  for (unsigned int point=0; point<n_q_points; ++point)
2574  {
2575 
2576  if (dim == spacedim)
2577  {
2578  const double det = data.contravariant[point].determinant();
2579 
2580  // check for distorted cells.
2581 
2582  // TODO: this allows for anisotropies of up to 1e6 in 3D and
2583  // 1e12 in 2D. might want to find a finer
2584  // (dimension-independent) criterion
2585  Assert (det > 1e-12*Utilities::fixed_power<dim>(cell->diameter()/
2586  std::sqrt(double(dim))),
2587  (typename Mapping<dim,spacedim>::ExcDistortedMappedCell(cell->center(), det, point)));
2588 
2589  output_data.JxW_values[point] = weights[point] * det;
2590  }
2591  // if dim==spacedim, then there is no cell normal to
2592  // compute. since this is for FEValues (and not FEFaceValues),
2593  // there are also no face normals to compute
2594  else //codim>0 case
2595  {
2596  Tensor<1, spacedim> DX_t [dim];
2597  for (unsigned int i=0; i<spacedim; ++i)
2598  for (unsigned int j=0; j<dim; ++j)
2599  DX_t[j][i] = data.contravariant[point][i][j];
2600 
2601  Tensor<2, dim> G; //First fundamental form
2602  for (unsigned int i=0; i<dim; ++i)
2603  for (unsigned int j=0; j<dim; ++j)
2604  G[i][j] = DX_t[i] * DX_t[j];
2605 
2606  output_data.JxW_values[point]
2607  = sqrt(determinant(G)) * weights[point];
2608 
2609  if (cell_similarity == CellSimilarity::inverted_translation)
2610  {
2611  // we only need to flip the normal
2612  if (update_flags & update_normal_vectors)
2613  output_data.normal_vectors[point] *= -1.;
2614  }
2615  else
2616  {
2617  const unsigned int codim = spacedim-dim;
2618  (void)codim;
2619 
2620  if (update_flags & update_normal_vectors)
2621  {
2622  Assert( codim==1 , ExcMessage("There is no cell normal in codim 2."));
2623 
2624  if (dim==1)
2625  output_data.normal_vectors[point] =
2626  cross_product_2d(-DX_t[0]);
2627  else //dim == 2
2628  output_data.normal_vectors[point] =
2629  cross_product_3d(DX_t[0], DX_t[1]);
2630 
2631  output_data.normal_vectors[point] /= output_data.normal_vectors[point].norm();
2632 
2633  if (cell->direction_flag() == false)
2634  output_data.normal_vectors[point] *= -1.;
2635  }
2636 
2637  }
2638  } //codim>0 case
2639 
2640  }
2641  }
2642 
2643 
2644 
2645  // copy values from InternalData to vector given by reference
2646  if (update_flags & update_jacobians)
2647  {
2648  AssertDimension (output_data.jacobians.size(), n_q_points);
2649  if (cell_similarity != CellSimilarity::translation)
2650  for (unsigned int point=0; point<n_q_points; ++point)
2651  output_data.jacobians[point] = data.contravariant[point];
2652  }
2653 
2654  // copy values from InternalData to vector given by reference
2655  if (update_flags & update_inverse_jacobians)
2656  {
2657  AssertDimension (output_data.inverse_jacobians.size(), n_q_points);
2658  if (cell_similarity != CellSimilarity::translation)
2659  for (unsigned int point=0; point<n_q_points; ++point)
2660  output_data.inverse_jacobians[point] = data.covariant[point].transpose();
2661  }
2662 
2663  internal::maybe_update_jacobian_grads<dim,spacedim> (cell_similarity,
2665  data,
2666  output_data.jacobian_grads);
2667 
2668  internal::maybe_update_jacobian_pushed_forward_grads<dim,spacedim> (cell_similarity,
2670  data,
2671  output_data.jacobian_pushed_forward_grads);
2672 
2673  internal::maybe_update_jacobian_2nd_derivatives<dim,spacedim> (cell_similarity,
2675  data,
2676  output_data.jacobian_2nd_derivatives);
2677 
2678  internal::maybe_update_jacobian_pushed_forward_2nd_derivatives<dim,spacedim> (cell_similarity,
2680  data,
2682 
2683  internal::maybe_update_jacobian_3rd_derivatives<dim,spacedim> (cell_similarity,
2685  data,
2686  output_data.jacobian_3rd_derivatives);
2687 
2688  internal::maybe_update_jacobian_pushed_forward_3rd_derivatives<dim,spacedim> (cell_similarity,
2690  data,
2692 
2693  return cell_similarity;
2694 }
2695 
2696 
2697 
2698 
2699 
2700 
2701 namespace internal
2702 {
2703  namespace
2704  {
2714  template <int dim, int spacedim>
2715  void
2716  maybe_compute_face_data (const ::MappingQGeneric<dim,spacedim> &mapping,
2717  const typename ::Triangulation<dim,spacedim>::cell_iterator &cell,
2718  const unsigned int face_no,
2719  const unsigned int subface_no,
2720  const unsigned int n_q_points,
2721  const std::vector<double> &weights,
2722  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2724  {
2725  const UpdateFlags update_flags = data.update_each;
2726 
2727  if (update_flags & update_boundary_forms)
2728  {
2729  AssertDimension (output_data.boundary_forms.size(), n_q_points);
2730  if (update_flags & update_normal_vectors)
2731  AssertDimension (output_data.normal_vectors.size(), n_q_points);
2732  if (update_flags & update_JxW_values)
2733  AssertDimension (output_data.JxW_values.size(), n_q_points);
2734 
2735  // map the unit tangentials to the real cell. checking for d!=dim-1
2736  // eliminates compiler warnings regarding unsigned int expressions <
2737  // 0.
2738  for (unsigned int d=0; d!=dim-1; ++d)
2739  {
2741  data.unit_tangentials.size(),
2742  ExcInternalError());
2743  Assert (data.aux[d].size() <=
2744  data.unit_tangentials[face_no+GeometryInfo<dim>::faces_per_cell*d].size(),
2745  ExcInternalError());
2746 
2747  mapping.transform (make_array_view(data.unit_tangentials[face_no+GeometryInfo<dim>::faces_per_cell*d]),
2749  data,
2750  make_array_view(data.aux[d]));
2751  }
2752 
2753  // if dim==spacedim, we can use the unit tangentials to compute the
2754  // boundary form by simply taking the cross product
2755  if (dim == spacedim)
2756  {
2757  for (unsigned int i=0; i<n_q_points; ++i)
2758  switch (dim)
2759  {
2760  case 1:
2761  // in 1d, we don't have access to any of the data.aux
2762  // fields (because it has only dim-1 components), but we
2763  // can still compute the boundary form by simply
2764  // looking at the number of the face
2765  output_data.boundary_forms[i][0] = (face_no == 0 ?
2766  -1 : +1);
2767  break;
2768  case 2:
2769  output_data.boundary_forms[i] =
2770  cross_product_2d(data.aux[0][i]);
2771  break;
2772  case 3:
2773  output_data.boundary_forms[i] =
2774  cross_product_3d(data.aux[0][i], data.aux[1][i]);
2775  break;
2776  default:
2777  Assert(false, ExcNotImplemented());
2778  }
2779  }
2780  else //(dim < spacedim)
2781  {
2782  // in the codim-one case, the boundary form results from the
2783  // cross product of all the face tangential vectors and the cell
2784  // normal vector
2785  //
2786  // to compute the cell normal, use the same method used in
2787  // fill_fe_values for cells above
2788  AssertDimension (data.contravariant.size(), n_q_points);
2789 
2790  for (unsigned int point=0; point<n_q_points; ++point)
2791  {
2792  if (dim==1)
2793  {
2794  // J is a tangent vector
2795  output_data.boundary_forms[point] = data.contravariant[point].transpose()[0];
2796  output_data.boundary_forms[point] /=
2797  (face_no == 0 ? -1. : +1.) * output_data.boundary_forms[point].norm();
2798  }
2799 
2800  if (dim==2)
2801  {
2802  const DerivativeForm<1,spacedim,dim> DX_t =
2803  data.contravariant[point].transpose();
2804 
2805  Tensor<1, spacedim> cell_normal =
2806  cross_product_3d(DX_t[0], DX_t[1]);
2807  cell_normal /= cell_normal.norm();
2808 
2809  // then compute the face normal from the face tangent
2810  // and the cell normal:
2811  output_data.boundary_forms[point] =
2812  cross_product_3d(data.aux[0][point], cell_normal);
2813  }
2814  }
2815  }
2816 
2817  if (update_flags & (update_normal_vectors
2818  | update_JxW_values))
2819  for (unsigned int i=0; i<output_data.boundary_forms.size(); ++i)
2820  {
2821  if (update_flags & update_JxW_values)
2822  {
2823  output_data.JxW_values[i] = output_data.boundary_forms[i].norm() * weights[i];
2824 
2825  if (subface_no!=numbers::invalid_unsigned_int)
2826  {
2827  const double area_ratio=GeometryInfo<dim>::subface_ratio(
2828  cell->subface_case(face_no), subface_no);
2829  output_data.JxW_values[i] *= area_ratio;
2830  }
2831  }
2832 
2833  if (update_flags & update_normal_vectors)
2834  output_data.normal_vectors[i] = Point<spacedim>(output_data.boundary_forms[i] /
2835  output_data.boundary_forms[i].norm());
2836  }
2837 
2838  if (update_flags & update_jacobians)
2839  for (unsigned int point=0; point<n_q_points; ++point)
2840  output_data.jacobians[point] = data.contravariant[point];
2841 
2842  if (update_flags & update_inverse_jacobians)
2843  for (unsigned int point=0; point<n_q_points; ++point)
2844  output_data.inverse_jacobians[point] = data.covariant[point].transpose();
2845  }
2846  }
2847 
2848 
2855  template<int dim, int spacedim>
2856  void
2857  do_fill_fe_face_values (const ::MappingQGeneric<dim,spacedim> &mapping,
2858  const typename ::Triangulation<dim,spacedim>::cell_iterator &cell,
2859  const unsigned int face_no,
2860  const unsigned int subface_no,
2861  const typename QProjector<dim>::DataSetDescriptor data_set,
2862  const Quadrature<dim-1> &quadrature,
2863  const typename ::MappingQGeneric<dim,spacedim>::InternalData &data,
2865  {
2866  maybe_compute_q_points<dim,spacedim> (data_set,
2867  data,
2868  output_data.quadrature_points);
2869  maybe_update_Jacobians<dim,spacedim> (CellSimilarity::none,
2870  data_set,
2871  data);
2872  maybe_update_jacobian_grads<dim,spacedim> (CellSimilarity::none,
2873  data_set,
2874  data,
2875  output_data.jacobian_grads);
2876  maybe_update_jacobian_pushed_forward_grads<dim,spacedim> (CellSimilarity::none,
2877  data_set,
2878  data,
2879  output_data.jacobian_pushed_forward_grads);
2880  maybe_update_jacobian_2nd_derivatives<dim,spacedim> (CellSimilarity::none,
2881  data_set,
2882  data,
2883  output_data.jacobian_2nd_derivatives);
2884  maybe_update_jacobian_pushed_forward_2nd_derivatives<dim,spacedim> (CellSimilarity::none,
2885  data_set,
2886  data,
2888  maybe_update_jacobian_3rd_derivatives<dim,spacedim> (CellSimilarity::none,
2889  data_set,
2890  data,
2891  output_data.jacobian_3rd_derivatives);
2892  maybe_update_jacobian_pushed_forward_3rd_derivatives<dim,spacedim> (CellSimilarity::none,
2893  data_set,
2894  data,
2896 
2897  maybe_compute_face_data (mapping,
2898  cell, face_no, subface_no, quadrature.size(),
2899  quadrature.get_weights(), data,
2900  output_data);
2901  }
2902  }
2903 }
2904 
2905 
2906 
2907 template<int dim, int spacedim>
2908 void
2911  const unsigned int face_no,
2912  const Quadrature<dim-1> &quadrature,
2913  const typename Mapping<dim,spacedim>::InternalDataBase &internal_data,
2915 {
2916  // ensure that the following cast is really correct:
2917  Assert ((dynamic_cast<const InternalData *>(&internal_data) != 0),
2918  ExcInternalError());
2919  const InternalData &data
2920  = static_cast<const InternalData &>(internal_data);
2921 
2922  // if necessary, recompute the support points of the transformation of this cell
2923  // (note that we need to first check the triangulation pointer, since otherwise
2924  // the second test might trigger an exception if the triangulations are not the
2925  // same)
2926  if ((data.mapping_support_points.size() == 0)
2927  ||
2928  (&cell->get_triangulation() !=
2929  &data.cell_of_current_support_points->get_triangulation())
2930  ||
2931  (cell != data.cell_of_current_support_points))
2932  {
2934  data.cell_of_current_support_points = cell;
2935  }
2936 
2938  cell, face_no, numbers::invalid_unsigned_int,
2940  cell->face_orientation(face_no),
2941  cell->face_flip(face_no),
2942  cell->face_rotation(face_no),
2943  quadrature.size()),
2944  quadrature,
2945  data,
2946  output_data);
2947 }
2948 
2949 
2950 
2951 template<int dim, int spacedim>
2952 void
2955  const unsigned int face_no,
2956  const unsigned int subface_no,
2957  const Quadrature<dim-1> &quadrature,
2958  const typename Mapping<dim,spacedim>::InternalDataBase &internal_data,
2960 {
2961  // ensure that the following cast is really correct:
2962  Assert ((dynamic_cast<const InternalData *>(&internal_data) != 0),
2963  ExcInternalError());
2964  const InternalData &data
2965  = static_cast<const InternalData &>(internal_data);
2966 
2967  // if necessary, recompute the support points of the transformation of this cell
2968  // (note that we need to first check the triangulation pointer, since otherwise
2969  // the second test might trigger an exception if the triangulations are not the
2970  // same)
2971  if ((data.mapping_support_points.size() == 0)
2972  ||
2973  (&cell->get_triangulation() !=
2974  &data.cell_of_current_support_points->get_triangulation())
2975  ||
2976  (cell != data.cell_of_current_support_points))
2977  {
2979  data.cell_of_current_support_points = cell;
2980  }
2981 
2983  cell, face_no, subface_no,
2984  QProjector<dim>::DataSetDescriptor::subface (face_no, subface_no,
2985  cell->face_orientation(face_no),
2986  cell->face_flip(face_no),
2987  cell->face_rotation(face_no),
2988  quadrature.size(),
2989  cell->subface_case(face_no)),
2990  quadrature,
2991  data,
2992  output_data);
2993 }
2994 
2995 
2996 
2997 namespace
2998 {
2999  template <int dim, int spacedim, int rank>
3000  void
3001  transform_fields(const ArrayView<const Tensor<rank,dim> > &input,
3002  const MappingType mapping_type,
3003  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3004  const ArrayView<Tensor<rank,spacedim> > &output)
3005  {
3006  AssertDimension (input.size(), output.size());
3007  Assert ((dynamic_cast<const typename MappingQGeneric<dim,spacedim>::InternalData *>(&mapping_data) != 0),
3008  ExcInternalError());
3010  &data = static_cast<const typename MappingQGeneric<dim,spacedim>::InternalData &>(mapping_data);
3011 
3012  switch (mapping_type)
3013  {
3014  case mapping_contravariant:
3015  {
3017  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_contravariant_transformation"));
3018 
3019  for (unsigned int i=0; i<output.size(); ++i)
3020  output[i] = apply_transformation(data.contravariant[i], input[i]);
3021 
3022  return;
3023  }
3024 
3025  case mapping_piola:
3026  {
3028  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_contravariant_transformation"));
3030  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_volume_elements"));
3031  Assert (rank==1, ExcMessage("Only for rank 1"));
3032  if (rank!=1)
3033  return;
3034 
3035  for (unsigned int i=0; i<output.size(); ++i)
3036  {
3037  output[i] = apply_transformation(data.contravariant[i], input[i]);
3038  output[i] /= data.volume_elements[i];
3039  }
3040  return;
3041  }
3042  //We still allow this operation as in the
3043  //reference cell Derivatives are Tensor
3044  //rather than DerivativeForm
3045  case mapping_covariant:
3046  {
3048  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3049 
3050  for (unsigned int i=0; i<output.size(); ++i)
3051  output[i] = apply_transformation(data.covariant[i], input[i]);
3052 
3053  return;
3054  }
3055 
3056  default:
3057  Assert(false, ExcNotImplemented());
3058  }
3059  }
3060 
3061 
3062  template <int dim, int spacedim, int rank>
3063  void
3064  transform_gradients(const ArrayView<const Tensor<rank,dim> > &input,
3065  const MappingType mapping_type,
3066  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3067  const ArrayView<Tensor<rank,spacedim> > &output)
3068  {
3069  AssertDimension (input.size(), output.size());
3070  Assert ((dynamic_cast<const typename MappingQGeneric<dim,spacedim>::InternalData *>(&mapping_data) != 0),
3071  ExcInternalError());
3073  &data = static_cast<const typename MappingQGeneric<dim,spacedim>::InternalData &>(mapping_data);
3074 
3075  switch (mapping_type)
3076  {
3078  {
3080  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3082  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_contravariant_transformation"));
3083  Assert (rank==2, ExcMessage("Only for rank 2"));
3084 
3085  for (unsigned int i=0; i<output.size(); ++i)
3086  {
3088  apply_transformation(data.contravariant[i], transpose(input[i]) );
3089  output[i] = apply_transformation(data.covariant[i], A.transpose() );
3090  }
3091 
3092  return;
3093  }
3094 
3096  {
3098  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3099  Assert (rank==2, ExcMessage("Only for rank 2"));
3100 
3101  for (unsigned int i=0; i<output.size(); ++i)
3102  {
3104  apply_transformation(data.covariant[i], transpose(input[i]) );
3105  output[i] = apply_transformation(data.covariant[i], A.transpose() );
3106  }
3107 
3108  return;
3109  }
3110 
3112  {
3114  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3116  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_contravariant_transformation"));
3118  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_volume_elements"));
3119  Assert (rank==2, ExcMessage("Only for rank 2"));
3120 
3121  for (unsigned int i=0; i<output.size(); ++i)
3122  {
3124  apply_transformation(data.covariant[i], input[i] );
3125  Tensor<2,spacedim> T =
3126  apply_transformation(data.contravariant[i], A.transpose() );
3127 
3128  output[i] = transpose(T);
3129  output[i] /= data.volume_elements[i];
3130  }
3131 
3132  return;
3133  }
3134 
3135  default:
3136  Assert(false, ExcNotImplemented());
3137  }
3138  }
3139 
3140 
3141 
3142 
3143  template <int dim, int spacedim>
3144  void
3145  transform_hessians(const ArrayView<const Tensor<3,dim> > &input,
3146  const MappingType mapping_type,
3147  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3148  const ArrayView<Tensor<3,spacedim> > &output)
3149  {
3150  AssertDimension (input.size(), output.size());
3151  Assert ((dynamic_cast<const typename MappingQGeneric<dim,spacedim>::InternalData *>(&mapping_data) != 0),
3152  ExcInternalError());
3154  &data = static_cast<const typename MappingQGeneric<dim,spacedim>::InternalData &>(mapping_data);
3155 
3156  switch (mapping_type)
3157  {
3159  {
3161  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3163  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_contravariant_transformation"));
3164 
3165  for (unsigned int q=0; q<output.size(); ++q)
3166  for (unsigned int i=0; i<spacedim; ++i)
3167  {
3168  double tmp1[dim][dim];
3169  for (unsigned int J=0; J<dim; ++J)
3170  for (unsigned int K=0; K<dim; ++K)
3171  {
3172  tmp1[J][K] = data.contravariant[q][i][0] * input[q][0][J][K];
3173  for (unsigned int I=1; I<dim; ++I)
3174  tmp1[J][K] += data.contravariant[q][i][I] * input[q][I][J][K];
3175  }
3176  for (unsigned int j=0; j<spacedim; ++j)
3177  {
3178  double tmp2[dim];
3179  for (unsigned int K=0; K<dim; ++K)
3180  {
3181  tmp2[K] = data.covariant[q][j][0] * tmp1[0][K];
3182  for (unsigned int J=1; J<dim; ++J)
3183  tmp2[K] += data.covariant[q][j][J] * tmp1[J][K];
3184  }
3185  for (unsigned int k=0; k<spacedim; ++k)
3186  {
3187  output[q][i][j][k] = data.covariant[q][k][0] * tmp2[0];
3188  for (unsigned int K=1; K<dim; ++K)
3189  output[q][i][j][k] += data.covariant[q][k][K] * tmp2[K];
3190  }
3191  }
3192  }
3193  return;
3194  }
3195 
3197  {
3199  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3200 
3201  for (unsigned int q=0; q<output.size(); ++q)
3202  for (unsigned int i=0; i<spacedim; ++i)
3203  {
3204  double tmp1[dim][dim];
3205  for (unsigned int J=0; J<dim; ++J)
3206  for (unsigned int K=0; K<dim; ++K)
3207  {
3208  tmp1[J][K] = data.covariant[q][i][0] * input[q][0][J][K];
3209  for (unsigned int I=1; I<dim; ++I)
3210  tmp1[J][K] += data.covariant[q][i][I] * input[q][I][J][K];
3211  }
3212  for (unsigned int j=0; j<spacedim; ++j)
3213  {
3214  double tmp2[dim];
3215  for (unsigned int K=0; K<dim; ++K)
3216  {
3217  tmp2[K] = data.covariant[q][j][0] * tmp1[0][K];
3218  for (unsigned int J=1; J<dim; ++J)
3219  tmp2[K] += data.covariant[q][j][J] * tmp1[J][K];
3220  }
3221  for (unsigned int k=0; k<spacedim; ++k)
3222  {
3223  output[q][i][j][k] = data.covariant[q][k][0] * tmp2[0];
3224  for (unsigned int K=1; K<dim; ++K)
3225  output[q][i][j][k] += data.covariant[q][k][K] * tmp2[K];
3226  }
3227  }
3228  }
3229 
3230  return;
3231  }
3232 
3233  case mapping_piola_hessian:
3234  {
3236  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3238  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_contravariant_transformation"));
3240  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_volume_elements"));
3241 
3242  for (unsigned int q=0; q<output.size(); ++q)
3243  for (unsigned int i=0; i<spacedim; ++i)
3244  {
3245  double factor[dim];
3246  for (unsigned int I=0; I<dim; ++I)
3247  factor[I] = data.contravariant[q][i][I] / data.volume_elements[q];
3248  double tmp1[dim][dim];
3249  for (unsigned int J=0; J<dim; ++J)
3250  for (unsigned int K=0; K<dim; ++K)
3251  {
3252  tmp1[J][K] = factor[0] * input[q][0][J][K];
3253  for (unsigned int I=1; I<dim; ++I)
3254  tmp1[J][K] += factor[I] * input[q][I][J][K];
3255  }
3256  for (unsigned int j=0; j<spacedim; ++j)
3257  {
3258  double tmp2[dim];
3259  for (unsigned int K=0; K<dim; ++K)
3260  {
3261  tmp2[K] = data.covariant[q][j][0] * tmp1[0][K];
3262  for (unsigned int J=1; J<dim; ++J)
3263  tmp2[K] += data.covariant[q][j][J] * tmp1[J][K];
3264  }
3265  for (unsigned int k=0; k<spacedim; ++k)
3266  {
3267  output[q][i][j][k] = data.covariant[q][k][0] * tmp2[0];
3268  for (unsigned int K=1; K<dim; ++K)
3269  output[q][i][j][k] += data.covariant[q][k][K] * tmp2[K];
3270  }
3271  }
3272  }
3273 
3274  return;
3275  }
3276 
3277  default:
3278  Assert(false, ExcNotImplemented());
3279  }
3280  }
3281 
3282 
3283 
3284 
3285  template<int dim, int spacedim, int rank>
3286  void
3287  transform_differential_forms(const ArrayView<const DerivativeForm<rank, dim,spacedim> > &input,
3288  const MappingType mapping_type,
3289  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3290  const ArrayView<Tensor<rank+1, spacedim> > &output)
3291  {
3292  AssertDimension (input.size(), output.size());
3293  Assert ((dynamic_cast<const typename MappingQGeneric<dim,spacedim>::InternalData *>(&mapping_data) != 0),
3294  ExcInternalError());
3296  &data = static_cast<const typename MappingQGeneric<dim,spacedim>::InternalData &>(mapping_data);
3297 
3298  switch (mapping_type)
3299  {
3300  case mapping_covariant:
3301  {
3303  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3304 
3305  for (unsigned int i=0; i<output.size(); ++i)
3306  output[i] = apply_transformation(data.covariant[i], input[i]);
3307 
3308  return;
3309  }
3310  default:
3311  Assert(false, ExcNotImplemented());
3312  }
3313  }
3314 }
3315 
3316 
3317 
3318 template<int dim, int spacedim>
3319 void
3321 transform (const ArrayView<const Tensor<1, dim> > &input,
3322  const MappingType mapping_type,
3323  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3324  const ArrayView<Tensor<1, spacedim> > &output) const
3325 {
3326  transform_fields(input, mapping_type, mapping_data, output);
3327 }
3328 
3329 
3330 
3331 template<int dim, int spacedim>
3332 void
3335  const MappingType mapping_type,
3336  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3337  const ArrayView<Tensor<2, spacedim> > &output) const
3338 {
3339  transform_differential_forms(input, mapping_type, mapping_data, output);
3340 }
3341 
3342 
3343 
3344 template<int dim, int spacedim>
3345 void
3347 transform (const ArrayView<const Tensor<2, dim> > &input,
3348  const MappingType mapping_type,
3349  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3350  const ArrayView<Tensor<2, spacedim> > &output) const
3351 {
3352  switch (mapping_type)
3353  {
3354  case mapping_contravariant:
3355  transform_fields(input, mapping_type, mapping_data, output);
3356  return;
3357 
3361  transform_gradients(input, mapping_type, mapping_data, output);
3362  return;
3363  default:
3364  Assert(false, ExcNotImplemented());
3365  }
3366 }
3367 
3368 
3369 
3370 template<int dim, int spacedim>
3371 void
3374  const MappingType mapping_type,
3375  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3376  const ArrayView<Tensor<3,spacedim> > &output) const
3377 {
3378 
3379  AssertDimension (input.size(), output.size());
3380  Assert (dynamic_cast<const InternalData *>(&mapping_data) != 0,
3381  ExcInternalError());
3382  const InternalData &data = static_cast<const InternalData &>(mapping_data);
3383 
3384  switch (mapping_type)
3385  {
3387  {
3389  typename FEValuesBase<dim>::ExcAccessToUninitializedField("update_covariant_transformation"));
3390 
3391  for (unsigned int q=0; q<output.size(); ++q)
3392  for (unsigned int i=0; i<spacedim; ++i)
3393  for (unsigned int j=0; j<spacedim; ++j)
3394  {
3395  double tmp[dim];
3396  for (unsigned int K=0; K<dim; ++K)
3397  {
3398  tmp[K] = data.covariant[q][j][0] * input[q][i][0][K];
3399  for (unsigned int J=1; J<dim; ++J)
3400  tmp[K] += data.covariant[q][j][J] * input[q][i][J][K];
3401  }
3402  for (unsigned int k=0; k<spacedim; ++k)
3403  {
3404  output[q][i][j][k] = data.covariant[q][k][0] * tmp[0];
3405  for (unsigned int K=1; K<dim; ++K)
3406  output[q][i][j][k] += data.covariant[q][k][K] * tmp[K];
3407  }
3408  }
3409  return;
3410  }
3411 
3412  default:
3413  Assert(false, ExcNotImplemented());
3414  }
3415 }
3416 
3417 
3418 
3419 template<int dim, int spacedim>
3420 void
3422 transform (const ArrayView<const Tensor<3,dim> > &input,
3423  const MappingType mapping_type,
3424  const typename Mapping<dim,spacedim>::InternalDataBase &mapping_data,
3425  const ArrayView<Tensor<3,spacedim> > &output) const
3426 {
3427  switch (mapping_type)
3428  {
3429  case mapping_piola_hessian:
3432  transform_hessians(input, mapping_type, mapping_data, output);
3433  return;
3434  default:
3435  Assert(false, ExcNotImplemented());
3436  }
3437 }
3438 
3439 
3440 
3441 namespace
3442 {
3451  template<int dim, int spacedim>
3452  void
3453  get_intermediate_points (const Manifold<dim, spacedim> &manifold,
3454  const QGaussLobatto<1> &line_support_points,
3455  const std::vector<Point<spacedim> > &surrounding_points,
3456  std::vector<Point<spacedim> > &points)
3457  {
3458  Assert(surrounding_points.size() >= 2, ExcMessage("At least 2 surrounding points are required"));
3459  const unsigned int n=points.size();
3460  Assert(n>0, ExcMessage("You can't ask for 0 intermediate points."));
3461  std::vector<double> w(surrounding_points.size());
3462 
3463  switch (surrounding_points.size())
3464  {
3465  case 2:
3466  {
3467  // If two points are passed, these are the two vertices, and
3468  // we can only compute degree-1 intermediate points.
3469  for (unsigned int i=0; i<n; ++i)
3470  {
3471  const double x = line_support_points.point(i+1)[0];
3472  w[1] = x;
3473  w[0] = (1-x);
3474  Quadrature<spacedim> quadrature(surrounding_points, w);
3475  points[i] = manifold.get_new_point(quadrature);
3476  }
3477  break;
3478  }
3479 
3480  case 4:
3481  {
3482  Assert(spacedim >= 2, ExcImpossibleInDim(spacedim));
3483  const unsigned m=
3484  static_cast<unsigned int>(std::sqrt(static_cast<double>(n)));
3485  // is n a square number
3486  Assert(m*m==n, ExcInternalError());
3487 
3488  // If four points are passed, these are the two vertices, and
3489  // we can only compute (degree-1)*(degree-1) intermediate
3490  // points.
3491  for (unsigned int i=0; i<m; ++i)
3492  {
3493  const double y=line_support_points.point(1+i)[0];
3494  for (unsigned int j=0; j<m; ++j)
3495  {
3496  const double x=line_support_points.point(1+j)[0];
3497 
3498  w[0] = (1-x)*(1-y);
3499  w[1] = x*(1-y);
3500  w[2] = (1-x)*y ;
3501  w[3] = x*y ;
3502  Quadrature<spacedim> quadrature(surrounding_points, w);
3503  points[i*m+j]=manifold.get_new_point(quadrature);
3504  }
3505  }
3506  break;
3507  }
3508 
3509  case 8:
3510  Assert(false, ExcNotImplemented());
3511  break;
3512  default:
3513  Assert(false, ExcInternalError());
3514  break;
3515  }
3516  }
3517 
3518 
3519 
3520 
3529  template <int dim, int spacedim, class TriaIterator>
3530  void get_intermediate_points_on_object(const Manifold<dim, spacedim> &manifold,
3531  const QGaussLobatto<1> &line_support_points,
3532  const TriaIterator &iter,
3533  std::vector<Point<spacedim> > &points)
3534  {
3535  const unsigned int structdim = TriaIterator::AccessorType::structure_dimension;
3536 
3537  // Try backward compatibility option.
3538  if (const Boundary<dim,spacedim> *boundary
3539  = dynamic_cast<const Boundary<dim,spacedim> *>(&manifold))
3540  // This is actually a boundary. Call old methods.
3541  {
3542  switch (structdim)
3543  {
3544  case 1:
3545  {
3546  const typename Triangulation<dim,spacedim>::line_iterator line = iter;
3547  boundary->get_intermediate_points_on_line(line, points);
3548  return;
3549  }
3550  case 2:
3551  {
3552  const typename Triangulation<dim,spacedim>::quad_iterator quad = iter;
3553  boundary->get_intermediate_points_on_quad(quad, points);
3554  return;
3555  }
3556  default:
3557  Assert(false, ExcInternalError());
3558  return;
3559  }
3560  }
3561  else
3562  {
3563  std::vector<Point<spacedim> > sp(GeometryInfo<structdim>::vertices_per_cell);
3564  for (unsigned int i=0; i<sp.size(); ++i)
3565  sp[i] = iter->vertex(i);
3566  get_intermediate_points(manifold, line_support_points, sp, points);
3567  }
3568  }
3569 
3570 
3581  template <int spacedim>
3582  void add_weighted_interior_points(const Table<2,double> &lvs,
3583  std::vector<Point<spacedim> > &a)
3584  {
3585  const unsigned int n_inner_apply=lvs.n_rows();
3586  const unsigned int n_outer_apply=lvs.n_cols();
3587  Assert(a.size()==n_outer_apply,
3588  ExcDimensionMismatch(a.size(), n_outer_apply));
3589 
3590  // compute each inner point as linear combination of the outer points. the
3591  // weights are given by the lvs entries, the outer points are the first
3592  // (existing) elements of a
3593  for (unsigned int unit_point=0; unit_point<n_inner_apply; ++unit_point)
3594  {
3595  Assert(lvs.n_cols()==n_outer_apply, ExcInternalError());
3596  Point<spacedim> p;
3597  for (unsigned int k=0; k<n_outer_apply; ++k)
3598  p+=lvs[unit_point][k]*a[k];
3599 
3600  a.push_back(p);
3601  }
3602  }
3603 }
3604 
3605 
3606 template <int dim, int spacedim>
3607 void
3610  std::vector<Point<spacedim> > &a) const
3611 {
3612  // if we only need the midpoint, then ask for it.
3613  if (this->polynomial_degree==2)
3614  {
3615  for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no)
3616  {
3617  const typename Triangulation<dim,spacedim>::line_iterator line =
3618  (dim == 1 ?
3619  static_cast<typename Triangulation<dim,spacedim>::line_iterator>(cell) :
3620  cell->line(line_no));
3621 
3622  const Manifold<dim,spacedim> &manifold =
3623  ( ( line->manifold_id() == numbers::invalid_manifold_id ) &&
3624  ( dim < spacedim )
3625  ?
3626  cell->get_manifold()
3627  :
3628  line->get_manifold() );
3629  a.push_back(manifold.get_new_point_on_line(line));
3630  }
3631  }
3632  else
3633  // otherwise call the more complicated functions and ask for inner points
3634  // from the boundary description
3635  {
3636  std::vector<Point<spacedim> > line_points (this->polynomial_degree-1);
3637  // loop over each of the lines, and if it is at the boundary, then first
3638  // get the boundary description and second compute the points on it
3639  for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no)
3640  {
3641  const typename Triangulation<dim,spacedim>::line_iterator
3642  line = (dim == 1
3643  ?
3644  static_cast<typename Triangulation<dim,spacedim>::line_iterator>(cell)
3645  :
3646  cell->line(line_no));
3647 
3648  const Manifold<dim,spacedim> &manifold =
3649  ( ( line->manifold_id() == numbers::invalid_manifold_id ) &&
3650  ( dim < spacedim )
3651  ?
3652  cell->get_manifold() :
3653  line->get_manifold() );
3654 
3655  get_intermediate_points_on_object (manifold, line_support_points, line, line_points);
3656 
3657  if (dim==3)
3658  {
3659  // in 3D, lines might be in wrong orientation. if so, reverse
3660  // the vector
3661  if (cell->line_orientation(line_no))
3662  a.insert (a.end(), line_points.begin(), line_points.end());
3663  else
3664  a.insert (a.end(), line_points.rbegin(), line_points.rend());
3665  }
3666  else
3667  // in 2D, lines always have the correct orientation. simply append
3668  // all points
3669  a.insert (a.end(), line_points.begin(), line_points.end());
3670  }
3671  }
3672 }
3673 
3674 
3675 
3676 template <>
3677 void
3680  std::vector<Point<3> > &a) const
3681 {
3682  const unsigned int faces_per_cell = GeometryInfo<3>::faces_per_cell,
3683  vertices_per_face = GeometryInfo<3>::vertices_per_face,
3684  lines_per_face = GeometryInfo<3>::lines_per_face,
3685  vertices_per_cell = GeometryInfo<3>::vertices_per_cell;
3686 
3687  static const StraightBoundary<3> straight_boundary;
3688  // used if face quad at boundary or entirely in the interior of the domain
3689  std::vector<Point<3> > quad_points ((polynomial_degree-1)*(polynomial_degree-1));
3690  // used if only one line of face quad is at boundary
3691  std::vector<Point<3> > b(4*polynomial_degree);
3692 
3693  // Used by the new Manifold interface. This vector collects the
3694  // vertices used to compute the intermediate points.
3695  std::vector<Point<3> > vertices(4);
3696 
3697  // loop over all faces and collect points on them
3698  for (unsigned int face_no=0; face_no<faces_per_cell; ++face_no)
3699  {
3700  const Triangulation<3>::face_iterator face = cell->face(face_no);
3701 
3702  // select the correct mappings for the present face
3703  const bool face_orientation = cell->face_orientation(face_no),
3704  face_flip = cell->face_flip (face_no),
3705  face_rotation = cell->face_rotation (face_no);
3706 
3707 #ifdef DEBUG
3708  // some sanity checks up front
3709  for (unsigned int i=0; i<vertices_per_face; ++i)
3710  Assert(face->vertex_index(i)==cell->vertex_index(
3712  face_orientation,
3713  face_flip,
3714  face_rotation)),
3715  ExcInternalError());
3716 
3717  // indices of the lines that bound a face are given by GeometryInfo<3>::
3718  // face_to_cell_lines
3719  for (unsigned int i=0; i<lines_per_face; ++i)
3720  Assert(face->line(i)==cell->line(GeometryInfo<3>::face_to_cell_lines(
3721  face_no, i, face_orientation, face_flip, face_rotation)),
3722  ExcInternalError());
3723 #endif
3724 
3725  // if face at boundary, then ask boundary object to return intermediate
3726  // points on it
3727  if (face->at_boundary())
3728  {
3729  get_intermediate_points_on_object(face->get_manifold(), line_support_points, face, quad_points);
3730 
3731  // in 3D, the orientation, flip and rotation of the face might not
3732  // match what we expect here, namely the standard orientation. thus
3733  // reorder points accordingly. since a Mapping uses the same shape
3734  // function as an FE_Q, we can ask a FE_Q to do the reordering for us.
3735  for (unsigned int i=0; i<quad_points.size(); ++i)
3736  a.push_back(quad_points[fe_q->adjust_quad_dof_index_for_face_orientation(i,
3737  face_orientation,
3738  face_flip,
3739  face_rotation)]);
3740  }
3741  else
3742  {
3743  // face is not at boundary, but maybe some of its lines are. count
3744  // them
3745  unsigned int lines_at_boundary=0;
3746  for (unsigned int i=0; i<lines_per_face; ++i)
3747  if (face->line(i)->at_boundary())
3748  ++lines_at_boundary;
3749 
3750  Assert(lines_at_boundary<=lines_per_face, ExcInternalError());
3751 
3752  // if at least one of the lines bounding this quad is at the
3753  // boundary, then collect points separately
3754  if (lines_at_boundary>0)
3755  {
3756  // call of function add_weighted_interior_points increases size of b
3757  // about 1. There resize b for the case the mentioned function
3758  // was already called.
3759  b.resize(4*polynomial_degree);
3760 
3761  // b is of size 4*degree, make sure that this is the right size
3762  Assert(b.size()==vertices_per_face+lines_per_face*(polynomial_degree-1),
3763  ExcDimensionMismatch(b.size(),
3764  vertices_per_face+lines_per_face*(polynomial_degree-1)));
3765 
3766  // sort the points into b. We used access from the cell (not
3767  // from the face) to fill b, so we can assume a standard face
3768  // orientation. Doing so, the calculated points will be in
3769  // standard orientation as well.
3770  for (unsigned int i=0; i<vertices_per_face; ++i)
3771  b[i]=a[GeometryInfo<3>::face_to_cell_vertices(face_no, i)];
3772 
3773  for (unsigned int i=0; i<lines_per_face; ++i)
3774  for (unsigned int j=0; j<polynomial_degree-1; ++j)
3775  b[vertices_per_face+i*(polynomial_degree-1)+j]=
3776  a[vertices_per_cell + GeometryInfo<3>::face_to_cell_lines(
3777  face_no, i)*(polynomial_degree-1)+j];
3778 
3779  // Now b includes the support points on the quad and we can
3780  // apply the laplace vector
3781  add_weighted_interior_points (support_point_weights_on_quad, b);
3782  AssertDimension (b.size(),
3783  4*this->polynomial_degree +
3784  (this->polynomial_degree-1)*(this->polynomial_degree-1));
3785 
3786  for (unsigned int i=0; i<(polynomial_degree-1)*(polynomial_degree-1); ++i)
3787  a.push_back(b[4*polynomial_degree+i]);
3788  }
3789  else
3790  {
3791  // face is entirely in the interior. get intermediate
3792  // points from the relevant manifold object.
3793  vertices.resize(4);
3794  for (unsigned int i=0; i<4; ++i)
3795  vertices[i] = face->vertex(i);
3796  get_intermediate_points (face->get_manifold(), line_support_points, vertices, quad_points);
3797  // in 3D, the orientation, flip and rotation of the face might
3798  // not match what we expect here, namely the standard
3799  // orientation. thus reorder points accordingly. since a Mapping
3800  // uses the same shape function as an FE_Q, we can ask a FE_Q to
3801  // do the reordering for us.
3802  for (unsigned int i=0; i<quad_points.size(); ++i)
3803  a.push_back(quad_points[fe_q->adjust_quad_dof_index_for_face_orientation(i,
3804  face_orientation,
3805  face_flip,
3806  face_rotation)]);
3807  }
3808  }
3809  }
3810 }
3811 
3812 
3813 
3814 template <>
3815 void
3818  std::vector<Point<3> > &a) const
3819 {
3820  std::vector<Point<3> > quad_points ((polynomial_degree-1)*(polynomial_degree-1));
3821  get_intermediate_points_on_object (cell->get_manifold(), line_support_points,
3822  cell, quad_points);
3823  for (unsigned int i=0; i<quad_points.size(); ++i)
3824  a.push_back(quad_points[i]);
3825 }
3826 
3827 
3828 
3829 template <int dim, int spacedim>
3830 void
3833  std::vector<Point<spacedim> > &) const
3834 {
3835  Assert (false, ExcInternalError());
3836 }
3837 
3838 
3839 
3840 template<int dim, int spacedim>
3841 std::vector<Point<spacedim> >
3844 {
3845  // get the vertices first
3846  std::vector<Point<spacedim> > a(GeometryInfo<dim>::vertices_per_cell);
3847  for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i)
3848  a[i] = cell->vertex(i);
3849 
3850  if (this->polynomial_degree>1)
3851  switch (dim)
3852  {
3853  case 1:
3854  add_line_support_points(cell, a);
3855  break;
3856  case 2:
3857  // in 2d, add the points on the four bounding lines to the exterior
3858  // (outer) points
3859  add_line_support_points(cell, a);
3860 
3861  // then get the support points on the quad if we are on a
3862  // manifold, otherwise compute them from the points around it
3863  if (dim != spacedim)
3864  add_quad_support_points(cell, a);
3865  else
3866  add_weighted_interior_points (support_point_weights_on_quad, a);
3867  break;
3868 
3869  case 3:
3870  {
3871  // in 3d also add the points located on the boundary faces
3872  add_line_support_points (cell, a);
3873  add_quad_support_points (cell, a);
3874 
3875  // then compute the interior points
3876  add_weighted_interior_points (support_point_weights_on_hex, a);
3877  break;
3878  }
3879 
3880  default:
3881  Assert(false, ExcNotImplemented());
3882  break;
3883  }
3884 
3885  return a;
3886 }
3887 
3888 
3889 
3890 //--------------------------- Explicit instantiations -----------------------
3891 #include "mapping_q_generic.inst"
3892 
3893 
3894 DEAL_II_NAMESPACE_CLOSE
Transformed quadrature weights.
unsigned int n() const
std::vector< DerivativeForm< 1, dim, spacedim > > covariant
static const unsigned int invalid_unsigned_int
Definition: types.h:164
virtual Point< spacedim > get_new_point(const Quadrature< spacedim > &quad) const
Definition: manifold.cc:52
const std_cxx11::unique_ptr< FE_Q< dim > > fe_q
Table< 2, double > support_point_weights_on_hex
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1052
std::vector< Tensor< 2, dim > > shape_second_derivatives
const unsigned int polynomial_degree
virtual CellSimilarity::Similarity fill_fe_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellSimilarity::Similarity cell_similarity, const Quadrature< dim > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, ::internal::FEValues::MappingRelatedData< dim, spacedim > &output_data) const
Contravariant transformation.
const std::vector< Point< dim > > & get_points() const
virtual void fill_fe_face_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const Quadrature< dim-1 > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, ::internal::FEValues::MappingRelatedData< dim, spacedim > &output_data) const
const std::vector< double > & get_weights() const
virtual InternalData * get_subface_data(const UpdateFlags flags, const Quadrature< dim-1 > &quadrature) const
MappingType
Definition: mapping.h:50
virtual InternalData * get_data(const UpdateFlags, const Quadrature< dim > &quadrature) const
std::vector< Tensor< 4, dim > > shape_fourth_derivatives
virtual Mapping< dim, spacedim > * clone() const
virtual Point< dim > transform_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p) const
Volume element.
::ExceptionBase & ExcMessage(std::string arg1)
Outer normal vector, not normalized.
const Point< dim > & point(const unsigned int i) const
std::vector< Polynomial< double > > generate_complete_Lagrange_basis(const std::vector< Point< 1 > > &points)
Definition: polynomial.cc:818
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
void invert(const FullMatrix< number2 > &M)
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const
Determinant of the Jacobian.
Triangulation< dim, spacedim >::cell_iterator cell_of_current_support_points
Transformed quadrature points.
const Tensor< 3, dim > & third_derivative(const unsigned int qpoint, const unsigned int shape_nr) const
MappingQGeneric(const unsigned int polynomial_degree)
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1047
static DataSetDescriptor cell()
Definition: qprojector.h:348
const Tensor< 4, dim > & fourth_derivative(const unsigned int qpoint, const unsigned int shape_nr) const
Definition: point.h:89
std::vector< Tensor< 1, spacedim > > boundary_forms
std::vector< Tensor< 4, spacedim > > jacobian_pushed_forward_2nd_derivatives
InternalData(const unsigned int polynomial_degree)
virtual std_cxx11::array< Point< spacedim >, GeometryInfo< dim >::vertices_per_cell > get_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
Definition: mapping.cc:30
std::vector< DerivativeForm< 2, dim, spacedim > > jacobian_grads
std::vector< Tensor< 1, dim > > shape_derivatives
virtual void add_quad_support_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell, std::vector< Point< spacedim > > &a) const
void compute_shape_function_values(const std::vector< Point< dim > > &unit_points)
Definition: tria.h:46
std::vector< Tensor< 3, spacedim > > jacobian_pushed_forward_grads
virtual Point< spacedim > get_new_point_on_line(const typename Triangulation< dim, spacedim >::line_iterator &line) const
Definition: manifold.cc:75
Definition: fe_q.h:522
static unsigned int face_to_cell_lines(const unsigned int face, const unsigned int line, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
void reinit(const TableIndices< N > &new_size, const bool omit_default_initialization=false)
#define Assert(cond, exc)
Definition: exceptions.h:294
UpdateFlags
std::vector< DerivativeForm< 1, dim, spacedim > > jacobians
Abstract base class for mapping classes.
Definition: dof_tools.h:52
std::vector< Tensor< 1, spacedim > > normal_vectors
virtual void transform(const ArrayView< const Tensor< 1, dim > > &input, const MappingType type, const typename Mapping< dim, spacedim >::InternalDataBase &internal, const ArrayView< Tensor< 1, spacedim > > &output) const
void loop(ITERATOR begin, typename identity< ITERATOR >::type end, DOFINFO &dinfo, INFOBOX &info, const std_cxx11::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &cell_worker, const std_cxx11::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &boundary_worker, const std_cxx11::function< void(DOFINFO &, DOFINFO &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, ASSEMBLER &assembler, const LoopControl &lctrl=LoopControl())
Definition: loop.h:370
void mmult(FullMatrix< number2 > &C, const FullMatrix< number2 > &B, const bool adding=false) const
std::vector< Point< spacedim > > mapping_support_points
std::vector< DerivativeForm< 1, dim, spacedim > > contravariant
DerivativeForm< 1, spacedim, dim, Number > transpose() const
std::vector< std::vector< Tensor< 1, spacedim > > > aux
void initialize(const UpdateFlags update_flags, const Quadrature< dim > &quadrature, const unsigned int n_original_q_points)
std::vector< double > volume_elements
Gradient of volume element.
const unsigned int n_shape_functions
unsigned int size() const
Point< dim > transform_real_to_unit_cell_internal(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p, const Point< dim > &initial_p_unit) const
std::vector< Tensor< 5, spacedim > > jacobian_pushed_forward_3rd_derivatives
virtual std::size_t memory_consumption() const
unsigned int get_degree() const
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
const double & shape(const unsigned int qpoint, const unsigned int shape_nr) const
Definition: mpi.h:55
const types::manifold_id invalid_manifold_id
Definition: types.h:220
Number determinant(const Tensor< 2, dim, Number > &t)
Definition: tensor.h:1778
virtual Point< spacedim > transform_unit_to_real_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &p) const
Definition: mpi.h:48
std::vector< DerivativeForm< 4, dim, spacedim > > jacobian_3rd_derivatives
Table< 2, double > support_point_weights_on_quad
std::vector< Point< spacedim > > quadrature_points
Normal vectors.
void do_fill_fe_face_values(const ::MappingFEField< dim, spacedim > &mapping, const typename ::Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int subface_no, const typename ::QProjector< dim >::DataSetDescriptor data_set, const Quadrature< dim-1 > &quadrature, const typename ::MappingFEField< dim, spacedim >::InternalData &data, const FiniteElement< dim, spacedim > &fe, const ComponentMask &fe_mask, const std::vector< unsigned int > &fe_to_real, internal::FEValues::MappingRelatedData< dim, spacedim > &output_data)
virtual void fill_fe_subface_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int subface_no, const Quadrature< dim-1 > &quadrature, const typename Mapping< dim, spacedim >::InternalDataBase &internal_data, ::internal::FEValues::MappingRelatedData< dim, spacedim > &output_data) const
virtual std::vector< Point< spacedim > > compute_mapping_support_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
virtual void add_line_support_points(const typename Triangulation< dim, spacedim >::cell_iterator &cell, std::vector< Point< spacedim > > &a) const
virtual InternalData * get_face_data(const UpdateFlags flags, const Quadrature< dim-1 > &quadrature) const
static Point< dim > project_to_unit_cell(const Point< dim > &p)
std::vector< Tensor< 3, dim > > shape_third_derivatives
const Tensor< 2, dim > & second_derivative(const unsigned int qpoint, const unsigned int shape_nr) const
const Tensor< 1, dim > & derivative(const unsigned int qpoint, const unsigned int shape_nr) const
void initialize_face(const UpdateFlags update_flags, const Quadrature< dim > &quadrature, const unsigned int n_original_q_points)
std::vector< std::vector< Tensor< 1, dim > > > unit_tangentials
double compute_value(const unsigned int i, const Point< dim > &p) const
std::vector< DerivativeForm< 1, spacedim, dim > > inverse_jacobians
void clear()
Definition: tensor.h:1128
std::vector< double > shape_values
std::vector< DerivativeForm< 3, dim, spacedim > > jacobian_2nd_derivatives
static double subface_ratio(const internal::SubfaceCase< dim > &subface_case, const unsigned int subface_no)
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
Definition: tria.cc:8955
Covariant transformation.
double weight(const unsigned int i) const
UpdateFlags update_each
Definition: mapping.h:560