Reference documentation for deal.II version 9.1.0-pre
mapping_manifold.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 2018 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/array_view.h>
18 #include <deal.II/base/derivative_form.h>
19 #include <deal.II/base/memory_consumption.h>
20 #include <deal.II/base/qprojector.h>
21 #include <deal.II/base/quadrature.h>
22 #include <deal.II/base/quadrature_lib.h>
23 #include <deal.II/base/std_cxx14/memory.h>
24 #include <deal.II/base/tensor_product_polynomials.h>
25 
26 #include <deal.II/dofs/dof_accessor.h>
27 
28 #include <deal.II/fe/fe.h>
29 #include <deal.II/fe/fe_tools.h>
30 #include <deal.II/fe/fe_values.h>
31 #include <deal.II/fe/mapping_manifold.h>
32 #include <deal.II/fe/mapping_q1.h>
33 
34 #include <deal.II/grid/manifold.h>
35 #include <deal.II/grid/tria.h>
36 #include <deal.II/grid/tria_iterator.h>
37 
38 #include <deal.II/lac/full_matrix.h>
39 
40 #include <algorithm>
41 #include <array>
42 #include <cmath>
43 #include <memory>
44 #include <numeric>
45 
46 
47 DEAL_II_NAMESPACE_OPEN
48 
49 template <int dim, int spacedim>
50 std::size_t
52 {
53  return (
66 }
67 
68 
69 template <int dim, int spacedim>
70 void
72  const UpdateFlags update_flags,
73  const Quadrature<dim> &q,
74  const unsigned int n_original_q_points)
75 {
76  // store the flags in the internal data object so we can access them
77  // in fill_fe_*_values()
78  this->update_each = update_flags;
79 
80  // Store the quadrature
81  this->quad = q;
82 
83  // Resize the weights
85 
86  // see if we need the (transformation) shape function values
87  // and/or gradients and resize the necessary arrays
88  if (this->update_each &
91 
93  covariant.resize(n_original_q_points);
94 
96  contravariant.resize(n_original_q_points);
97 
99  volume_elements.resize(n_original_q_points);
100 }
101 
102 
103 template <int dim, int spacedim>
104 void
106  const UpdateFlags update_flags,
107  const Quadrature<dim> &q,
108  const unsigned int n_original_q_points)
109 {
110  initialize(update_flags, q, n_original_q_points);
111 
112  if (dim > 1)
113  {
115  {
116  aux.resize(dim - 1,
117  std::vector<Tensor<1, spacedim>>(n_original_q_points));
118 
119  // Compute tangentials to the unit cell.
120  for (unsigned int i = 0; i < unit_tangentials.size(); ++i)
121  unit_tangentials[i].resize(n_original_q_points);
122  switch (dim)
123  {
124  case 2:
125  {
126  // ensure a counterclockwise
127  // orientation of tangentials
128  static const int tangential_orientation[4] = {-1, 1, 1, -1};
129  for (unsigned int i = 0;
130  i < GeometryInfo<dim>::faces_per_cell;
131  ++i)
132  {
133  Tensor<1, dim> tang;
134  tang[1 - i / 2] = tangential_orientation[i];
135  std::fill(unit_tangentials[i].begin(),
136  unit_tangentials[i].end(),
137  tang);
138  }
139  break;
140  }
141  case 3:
142  {
143  for (unsigned int i = 0;
144  i < GeometryInfo<dim>::faces_per_cell;
145  ++i)
146  {
147  Tensor<1, dim> tang1, tang2;
148 
149  const unsigned int nd =
151 
152  // first tangential
153  // vector in direction
154  // of the (nd+1)%3 axis
155  // and inverted in case
156  // of unit inward normal
157  tang1[(nd + 1) % dim] =
159  // second tangential
160  // vector in direction
161  // of the (nd+2)%3 axis
162  tang2[(nd + 2) % dim] = 1.;
163 
164  // same unit tangents
165  // for all quadrature
166  // points on this face
167  std::fill(unit_tangentials[i].begin(),
168  unit_tangentials[i].end(),
169  tang1);
170  std::fill(
172  .begin(),
174  .end(),
175  tang2);
176  }
177  break;
178  }
179  default:
180  Assert(false, ExcNotImplemented());
181  }
182  }
183  }
184 }
185 
186 
187 
188 template <int dim, int spacedim>
191 {}
192 
193 
194 
195 template <int dim, int spacedim>
196 std::unique_ptr<Mapping<dim, spacedim>>
198 {
199  return std_cxx14::make_unique<MappingManifold<dim, spacedim>>(*this);
200 }
201 
202 
203 
204 template <int dim, int spacedim>
208  const Point<spacedim> &) const
209 {
210  Assert(false, ExcNotImplemented());
211  return Point<dim>();
212 }
213 
214 
215 
216 template <int dim, int spacedim>
220  const Point<dim> & p) const
221 {
222  std::array<Point<spacedim>, GeometryInfo<dim>::vertices_per_cell> vertices;
223  std::array<double, GeometryInfo<dim>::vertices_per_cell> weights;
224 
225  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
226  {
227  vertices[v] = cell->vertex(v);
229  }
230  return cell->get_manifold().get_new_point(
231  make_array_view(vertices.begin(), vertices.end()),
232  make_array_view(weights.begin(), weights.end()));
233 }
234 
235 
236 
237 // In the code below, GCC tries to instantiate MappingManifold<3,4> when
238 // seeing which of the overloaded versions of
239 // do_transform_real_to_unit_cell_internal() to call. This leads to bad
240 // error messages and, generally, nothing very good. Avoid this by ensuring
241 // that this class exists, but does not have an inner InternalData
242 // type, thereby ruling out the codim-1 version of the function
243 // below when doing overload resolution.
244 template <>
245 class MappingManifold<3, 4>
246 {};
247 
248 
249 
250 template <int dim, int spacedim>
253  const UpdateFlags in) const
254 {
255  // add flags if the respective quantities are necessary to compute
256  // what we need. note that some flags appear in both the conditions
257  // and in subsequent set operations. this leads to some circular
258  // logic. the only way to treat this is to iterate. since there are
259  // 5 if-clauses in the loop, it will take at most 5 iterations to
260  // converge. do them:
261  UpdateFlags out = in;
262  for (unsigned int i = 0; i < 5; ++i)
263  {
264  // The following is a little incorrect:
265  // If not applied on a face,
266  // update_boundary_forms does not
267  // make sense. On the other hand,
268  // it is necessary on a
269  // face. Currently,
270  // update_boundary_forms is simply
271  // ignored for the interior of a
272  // cell.
274  out |= update_boundary_forms;
275 
280 
281  if (out &
286 
287  // The contravariant transformation used in the Piola
288  // transformation, which requires the determinant of the Jacobi
289  // matrix of the transformation. Because we have no way of
290  // knowing here whether the finite elements wants to use the
291  // contravariant of the Piola transforms, we add the JxW values
292  // to the list of flags to be updated for each cell.
294  out |= update_JxW_values;
295 
296  if (out & update_normal_vectors)
297  out |= update_JxW_values;
298  }
299 
300  // Now throw an exception if we stumble upon something that was not
301  // implemented yet
306 
307  return out;
308 }
309 
310 
311 
312 template <int dim, int spacedim>
313 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
315  const Quadrature<dim> &q) const
316 {
317  auto data = std_cxx14::make_unique<InternalData>();
318  data->initialize(this->requires_update_flags(update_flags), q, q.size());
319 
320  return std::move(data);
321 }
322 
323 
324 
325 template <int dim, int spacedim>
326 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
328  const UpdateFlags update_flags,
329  const Quadrature<dim - 1> &quadrature) const
330 {
331  auto data = std_cxx14::make_unique<InternalData>();
332  data->initialize_face(this->requires_update_flags(update_flags),
334  quadrature.size());
335 
336  return std::move(data);
337 }
338 
339 
340 
341 template <int dim, int spacedim>
342 std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
344  const UpdateFlags update_flags,
345  const Quadrature<dim - 1> &quadrature) const
346 {
347  auto data = std_cxx14::make_unique<InternalData>();
348  data->initialize_face(this->requires_update_flags(update_flags),
350  quadrature.size());
351 
352  return std::move(data);
353 }
354 
355 
356 
357 namespace internal
358 {
359  namespace MappingManifoldImplementation
360  {
361  namespace
362  {
369  template <int dim, int spacedim>
370  void
371  maybe_compute_q_points(
372  const typename QProjector<dim>::DataSetDescriptor data_set,
373  const typename ::MappingManifold<dim, spacedim>::InternalData
374  & data,
375  std::vector<Point<spacedim>> &quadrature_points)
376  {
377  const UpdateFlags update_flags = data.update_each;
378 
379  AssertDimension(data.vertices.size(),
381 
382  if (update_flags & update_quadrature_points)
383  {
384  for (unsigned int point = 0; point < quadrature_points.size();
385  ++point)
386  {
387  quadrature_points[point] = data.manifold->get_new_point(
388  make_array_view(data.vertices),
389  make_array_view(
390  data.cell_manifold_quadrature_weights[point + data_set]));
391  }
392  }
393  }
394 
395 
396 
403  template <int dim, int spacedim>
404  void
405  maybe_update_Jacobians(
406  const typename ::QProjector<dim>::DataSetDescriptor data_set,
407  const typename ::MappingManifold<dim, spacedim>::InternalData
408  &data)
409  {
410  const UpdateFlags update_flags = data.update_each;
411 
412  if (update_flags & update_contravariant_transformation)
413  {
414  const unsigned int n_q_points = data.contravariant.size();
415 
416  std::fill(data.contravariant.begin(),
417  data.contravariant.end(),
419 
421  data.vertices.size());
422  for (unsigned int point = 0; point < n_q_points; ++point)
423  {
424  // Start by figuring out how to compute the direction in
425  // the reference space:
426  const Point<dim> &p = data.quad.point(point + data_set);
427 
428  // And get its image on the manifold:
429  const Point<spacedim> P = data.manifold->get_new_point(
430  make_array_view(data.vertices),
431  make_array_view(
432  data.cell_manifold_quadrature_weights[point + data_set]));
433 
434  // To compute the Jacobian, we choose dim points aligned
435  // with the dim reference axes, which are still in the
436  // given cell, and ask for the tangent vector in these
437  // directions. Choosing the points is somewhat arbitrary,
438  // so we try to be smart and we pick points which are
439  // on the opposite quadrant w.r.t. the evaluation
440  // point.
441  for (unsigned int i = 0; i < dim; ++i)
442  {
443  const Point<dim> ei = Point<dim>::unit_vector(i);
444  const double pi = p[i];
445  Assert(pi >= 0 && pi <= 1.0,
447  "Was expecting a quadrature point "
448  "inside the unit reference element."));
449 
450  // In the length L, we store also the direction sign,
451  // which is positive, if the coordinate is < .5,
452  const double L = pi > .5 ? -pi : 1 - pi;
453 
454  const Point<dim> np(p + L * ei);
455 
456  // Get the weights to compute the np point in real space
457  for (unsigned int j = 0;
458  j < GeometryInfo<dim>::vertices_per_cell;
459  ++j)
460  data.vertex_weights[j] =
462 
463  const Point<spacedim> NP = data.manifold->get_new_point(
464  make_array_view(data.vertices),
465  make_array_view(data.vertex_weights));
466 
467  const Tensor<1, spacedim> T =
468  data.manifold->get_tangent_vector(P, NP);
469 
470  for (unsigned int d = 0; d < spacedim; ++d)
471  data.contravariant[point][d][i] = T[d] / L;
472  }
473  }
474 
475  if (update_flags & update_covariant_transformation)
476  {
477  const unsigned int n_q_points = data.contravariant.size();
478  for (unsigned int point = 0; point < n_q_points; ++point)
479  {
480  data.covariant[point] =
481  (data.contravariant[point]).covariant_form();
482  }
483  }
484 
485  if (update_flags & update_volume_elements)
486  {
487  const unsigned int n_q_points = data.contravariant.size();
488  for (unsigned int point = 0; point < n_q_points; ++point)
489  data.volume_elements[point] =
490  data.contravariant[point].determinant();
491  }
492  }
493  }
494  } // namespace
495  } // namespace MappingManifoldImplementation
496 } // namespace internal
497 
498 
499 
500 template <int dim, int spacedim>
504  const CellSimilarity::Similarity cell_similarity,
505  const Quadrature<dim> & quadrature,
506  const typename Mapping<dim, spacedim>::InternalDataBase & internal_data,
508  &output_data) const
509 {
510  // ensure that the following static_cast is really correct:
511  Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
512  ExcInternalError());
513  const InternalData &data = static_cast<const InternalData &>(internal_data);
514 
515  const unsigned int n_q_points = quadrature.size();
516 
517  data.store_vertices(cell);
518  data.manifold = &(cell->get_manifold());
519 
520  internal::MappingManifoldImplementation::maybe_compute_q_points<dim,
521  spacedim>(
523  data,
524  output_data.quadrature_points);
525 
526  internal::MappingManifoldImplementation::maybe_update_Jacobians<dim,
527  spacedim>(
529 
530  const UpdateFlags update_flags = data.update_each;
531  const std::vector<double> &weights = quadrature.get_weights();
532 
533  // Multiply quadrature weights by absolute value of Jacobian determinants or
534  // the area element g=sqrt(DX^t DX) in case of codim > 0
535 
536  if (update_flags & (update_normal_vectors | update_JxW_values))
537  {
538  AssertDimension(output_data.JxW_values.size(), n_q_points);
539 
540  Assert(!(update_flags & update_normal_vectors) ||
541  (output_data.normal_vectors.size() == n_q_points),
542  ExcDimensionMismatch(output_data.normal_vectors.size(),
543  n_q_points));
544 
545 
546  for (unsigned int point = 0; point < n_q_points; ++point)
547  {
548  if (dim == spacedim)
549  {
550  const double det = data.contravariant[point].determinant();
551 
552  // check for distorted cells.
553 
554  // TODO: this allows for anisotropies of up to 1e6 in 3D and
555  // 1e12 in 2D. might want to find a finer
556  // (dimension-independent) criterion
557  Assert(det > 1e-12 * Utilities::fixed_power<dim>(
558  cell->diameter() / std::sqrt(double(dim))),
560  cell->center(), det, point)));
561 
562  output_data.JxW_values[point] = weights[point] * det;
563  }
564  // if dim==spacedim, then there is no cell normal to
565  // compute. since this is for FEValues (and not FEFaceValues),
566  // there are also no face normals to compute
567  else // codim>0 case
568  {
569  Tensor<1, spacedim> DX_t[dim];
570  for (unsigned int i = 0; i < spacedim; ++i)
571  for (unsigned int j = 0; j < dim; ++j)
572  DX_t[j][i] = data.contravariant[point][i][j];
573 
574  Tensor<2, dim> G; // First fundamental form
575  for (unsigned int i = 0; i < dim; ++i)
576  for (unsigned int j = 0; j < dim; ++j)
577  G[i][j] = DX_t[i] * DX_t[j];
578 
579  output_data.JxW_values[point] =
580  std::sqrt(determinant(G)) * weights[point];
581 
582  if (cell_similarity == CellSimilarity::inverted_translation)
583  {
584  // we only need to flip the normal
585  if (update_flags & update_normal_vectors)
586  output_data.normal_vectors[point] *= -1.;
587  }
588  else
589  {
590  if (update_flags & update_normal_vectors)
591  {
592  Assert(spacedim == dim + 1,
593  ExcMessage(
594  "There is no (unique) cell normal for " +
596  "-dimensional cells in " +
597  Utilities::int_to_string(spacedim) +
598  "-dimensional space. This only works if the "
599  "space dimension is one greater than the "
600  "dimensionality of the mesh cells."));
601 
602  if (dim == 1)
603  output_data.normal_vectors[point] =
604  cross_product_2d(-DX_t[0]);
605  else // dim == 2
606  output_data.normal_vectors[point] =
607  cross_product_3d(DX_t[0], DX_t[1]);
608 
609  output_data.normal_vectors[point] /=
610  output_data.normal_vectors[point].norm();
611 
612  if (cell->direction_flag() == false)
613  output_data.normal_vectors[point] *= -1.;
614  }
615  }
616  } // codim>0 case
617  }
618  }
619 
620 
621 
622  // copy values from InternalData to vector given by reference
623  if (update_flags & update_jacobians)
624  {
625  AssertDimension(output_data.jacobians.size(), n_q_points);
626  if (cell_similarity != CellSimilarity::translation)
627  for (unsigned int point = 0; point < n_q_points; ++point)
628  output_data.jacobians[point] = data.contravariant[point];
629  }
630 
631  // copy values from InternalData to vector given by reference
632  if (update_flags & update_inverse_jacobians)
633  {
634  AssertDimension(output_data.inverse_jacobians.size(), n_q_points);
635  if (cell_similarity != CellSimilarity::translation)
636  for (unsigned int point = 0; point < n_q_points; ++point)
637  output_data.inverse_jacobians[point] =
638  data.covariant[point].transpose();
639  }
640 
641  return cell_similarity;
642 }
643 
644 
645 
646 namespace internal
647 {
648  namespace MappingManifoldImplementation
649  {
650  namespace
651  {
661  template <int dim, int spacedim>
662  void
663  maybe_compute_face_data(
664  const ::MappingManifold<dim, spacedim> &mapping,
665  const typename ::Triangulation<dim, spacedim>::cell_iterator
666  & cell,
667  const unsigned int face_no,
668  const unsigned int subface_no,
669  const unsigned int n_q_points,
670  const std::vector<double> &weights,
671  const typename ::MappingManifold<dim, spacedim>::InternalData
672  &data,
674  &output_data)
675  {
676  const UpdateFlags update_flags = data.update_each;
677 
678  if (update_flags & update_boundary_forms)
679  {
680  AssertDimension(output_data.boundary_forms.size(), n_q_points);
681  if (update_flags & update_normal_vectors)
682  AssertDimension(output_data.normal_vectors.size(), n_q_points);
683  if (update_flags & update_JxW_values)
684  AssertDimension(output_data.JxW_values.size(), n_q_points);
685 
686  // map the unit tangentials to the real cell. checking for d!=dim-1
687  // eliminates compiler warnings regarding unsigned int expressions <
688  // 0.
689  for (unsigned int d = 0; d != dim - 1; ++d)
690  {
692  data.unit_tangentials.size(),
693  ExcInternalError());
694  Assert(
695  data.aux[d].size() <=
696  data
697  .unit_tangentials[face_no +
699  .size(),
700  ExcInternalError());
701 
702  mapping.transform(
703  make_array_view(
704  data
705  .unit_tangentials[face_no +
708  data,
709  make_array_view(data.aux[d]));
710  }
711 
712  // if dim==spacedim, we can use the unit tangentials to compute the
713  // boundary form by simply taking the cross product
714  if (dim == spacedim)
715  {
716  for (unsigned int i = 0; i < n_q_points; ++i)
717  switch (dim)
718  {
719  case 1:
720  // in 1d, we don't have access to any of the data.aux
721  // fields (because it has only dim-1 components), but we
722  // can still compute the boundary form by simply
723  // looking at the number of the face
724  output_data.boundary_forms[i][0] =
725  (face_no == 0 ? -1 : +1);
726  break;
727  case 2:
728  output_data.boundary_forms[i] =
729  cross_product_2d(data.aux[0][i]);
730  break;
731  case 3:
732  output_data.boundary_forms[i] =
733  cross_product_3d(data.aux[0][i], data.aux[1][i]);
734  break;
735  default:
736  Assert(false, ExcNotImplemented());
737  }
738  }
739  else //(dim < spacedim)
740  {
741  // in the codim-one case, the boundary form results from the
742  // cross product of all the face tangential vectors and the cell
743  // normal vector
744  //
745  // to compute the cell normal, use the same method used in
746  // fill_fe_values for cells above
747  AssertDimension(data.contravariant.size(), n_q_points);
748 
749  for (unsigned int point = 0; point < n_q_points; ++point)
750  {
751  switch (dim)
752  {
753  case 1:
754  {
755  // J is a tangent vector
756  output_data.boundary_forms[point] =
757  data.contravariant[point].transpose()[0];
758  output_data.boundary_forms[point] /=
759  (face_no == 0 ? -1. : +1.) *
760  output_data.boundary_forms[point].norm();
761 
762  break;
763  }
764 
765  case 2:
766  {
768  data.contravariant[point].transpose();
769 
770  Tensor<1, spacedim> cell_normal =
771  cross_product_3d(DX_t[0], DX_t[1]);
772  cell_normal /= cell_normal.norm();
773 
774  // then compute the face normal from the face
775  // tangent and the cell normal:
776  output_data.boundary_forms[point] =
777  cross_product_3d(data.aux[0][point], cell_normal);
778 
779  break;
780  }
781 
782  default:
783  Assert(false, ExcNotImplemented());
784  }
785  }
786  }
787 
788  if (update_flags & (update_normal_vectors | update_JxW_values))
789  for (unsigned int i = 0; i < output_data.boundary_forms.size();
790  ++i)
791  {
792  if (update_flags & update_JxW_values)
793  {
794  output_data.JxW_values[i] =
795  output_data.boundary_forms[i].norm() * weights[i];
796 
797  if (subface_no != numbers::invalid_unsigned_int)
798  {
799  const double area_ratio =
801  cell->subface_case(face_no), subface_no);
802  output_data.JxW_values[i] *= area_ratio;
803  }
804  }
805 
806  if (update_flags & update_normal_vectors)
807  output_data.normal_vectors[i] =
808  Point<spacedim>(output_data.boundary_forms[i] /
809  output_data.boundary_forms[i].norm());
810  }
811 
812  if (update_flags & update_jacobians)
813  for (unsigned int point = 0; point < n_q_points; ++point)
814  output_data.jacobians[point] = data.contravariant[point];
815 
816  if (update_flags & update_inverse_jacobians)
817  for (unsigned int point = 0; point < n_q_points; ++point)
818  output_data.inverse_jacobians[point] =
819  data.covariant[point].transpose();
820  }
821  }
822 
823 
830  template <int dim, int spacedim>
831  void
832  do_fill_fe_face_values(
833  const ::MappingManifold<dim, spacedim> &mapping,
834  const typename ::Triangulation<dim, spacedim>::cell_iterator
835  & cell,
836  const unsigned int face_no,
837  const unsigned int subface_no,
838  const typename QProjector<dim>::DataSetDescriptor data_set,
839  const Quadrature<dim - 1> & quadrature,
840  const typename ::MappingManifold<dim, spacedim>::InternalData
841  &data,
843  &output_data)
844  {
845  data.store_vertices(cell);
846 
847  data.manifold = &cell->face(face_no)->get_manifold();
848 
849  maybe_compute_q_points<dim, spacedim>(data_set,
850  data,
851  output_data.quadrature_points);
852  maybe_update_Jacobians<dim, spacedim>(data_set, data);
853 
854  maybe_compute_face_data(mapping,
855  cell,
856  face_no,
857  subface_no,
858  quadrature.size(),
859  quadrature.get_weights(),
860  data,
861  output_data);
862  }
863 
864  template <int dim, int spacedim, int rank>
865  void
866  transform_fields(
867  const ArrayView<const Tensor<rank, dim>> & input,
868  const MappingType mapping_type,
869  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
870  const ArrayView<Tensor<rank, spacedim>> & output)
871  {
872  AssertDimension(input.size(), output.size());
873  Assert((dynamic_cast<const typename ::
874  MappingManifold<dim, spacedim>::InternalData *>(
875  &mapping_data) != nullptr),
876  ExcInternalError());
877  const typename ::MappingManifold<dim, spacedim>::InternalData
878  &data =
879  static_cast<const typename ::MappingManifold<dim, spacedim>::
880  InternalData &>(mapping_data);
881 
882  switch (mapping_type)
883  {
885  {
886  Assert(
887  data.update_each & update_contravariant_transformation,
889  "update_contravariant_transformation"));
890 
891  for (unsigned int i = 0; i < output.size(); ++i)
892  output[i] =
893  apply_transformation(data.contravariant[i], input[i]);
894 
895  return;
896  }
897 
898  case mapping_piola:
899  {
900  Assert(
901  data.update_each & update_contravariant_transformation,
903  "update_contravariant_transformation"));
904  Assert(
905  data.update_each & update_volume_elements,
907  "update_volume_elements"));
908  Assert(rank == 1, ExcMessage("Only for rank 1"));
909  if (rank != 1)
910  return;
911 
912  for (unsigned int i = 0; i < output.size(); ++i)
913  {
914  output[i] =
915  apply_transformation(data.contravariant[i], input[i]);
916  output[i] /= data.volume_elements[i];
917  }
918  return;
919  }
920  // We still allow this operation as in the
921  // reference cell Derivatives are Tensor
922  // rather than DerivativeForm
923  case mapping_covariant:
924  {
925  Assert(
926  data.update_each & update_contravariant_transformation,
928  "update_covariant_transformation"));
929 
930  for (unsigned int i = 0; i < output.size(); ++i)
931  output[i] = apply_transformation(data.covariant[i], input[i]);
932 
933  return;
934  }
935 
936  default:
937  Assert(false, ExcNotImplemented());
938  }
939  }
940 
941 
942  template <int dim, int spacedim, int rank>
943  void
944  transform_gradients(
945  const ArrayView<const Tensor<rank, dim>> & input,
946  const MappingType mapping_type,
947  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
948  const ArrayView<Tensor<rank, spacedim>> & output)
949  {
950  AssertDimension(input.size(), output.size());
951  Assert((dynamic_cast<const typename ::
952  MappingManifold<dim, spacedim>::InternalData *>(
953  &mapping_data) != nullptr),
954  ExcInternalError());
955  const typename ::MappingManifold<dim, spacedim>::InternalData
956  &data =
957  static_cast<const typename ::MappingManifold<dim, spacedim>::
958  InternalData &>(mapping_data);
959 
960  switch (mapping_type)
961  {
963  {
964  Assert(
965  data.update_each & update_covariant_transformation,
967  "update_covariant_transformation"));
968  Assert(
969  data.update_each & update_contravariant_transformation,
971  "update_contravariant_transformation"));
972  Assert(rank == 2, ExcMessage("Only for rank 2"));
973 
974  for (unsigned int i = 0; i < output.size(); ++i)
975  {
977  apply_transformation(data.contravariant[i],
978  transpose(input[i]));
979  output[i] =
980  apply_transformation(data.covariant[i], A.transpose());
981  }
982 
983  return;
984  }
985 
987  {
988  Assert(
989  data.update_each & update_covariant_transformation,
991  "update_covariant_transformation"));
992  Assert(rank == 2, ExcMessage("Only for rank 2"));
993 
994  for (unsigned int i = 0; i < output.size(); ++i)
995  {
997  apply_transformation(data.covariant[i],
998  transpose(input[i]));
999  output[i] =
1000  apply_transformation(data.covariant[i], A.transpose());
1001  }
1002 
1003  return;
1004  }
1005 
1007  {
1008  Assert(
1009  data.update_each & update_covariant_transformation,
1011  "update_covariant_transformation"));
1012  Assert(
1013  data.update_each & update_contravariant_transformation,
1015  "update_contravariant_transformation"));
1016  Assert(
1017  data.update_each & update_volume_elements,
1019  "update_volume_elements"));
1020  Assert(rank == 2, ExcMessage("Only for rank 2"));
1021 
1022  for (unsigned int i = 0; i < output.size(); ++i)
1023  {
1025  apply_transformation(data.covariant[i], input[i]);
1027  apply_transformation(data.contravariant[i],
1028  A.transpose());
1029 
1030  output[i] = transpose(T);
1031  output[i] /= data.volume_elements[i];
1032  }
1033 
1034  return;
1035  }
1036 
1037  default:
1038  Assert(false, ExcNotImplemented());
1039  }
1040  }
1041 
1042 
1043 
1044  template <int dim, int spacedim>
1045  void
1046  transform_hessians(
1047  const ArrayView<const Tensor<3, dim>> & input,
1048  const MappingType mapping_type,
1049  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1050  const ArrayView<Tensor<3, spacedim>> & output)
1051  {
1052  AssertDimension(input.size(), output.size());
1053  Assert((dynamic_cast<const typename ::
1054  MappingManifold<dim, spacedim>::InternalData *>(
1055  &mapping_data) != nullptr),
1056  ExcInternalError());
1057  const typename ::MappingManifold<dim, spacedim>::InternalData
1058  &data =
1059  static_cast<const typename ::MappingManifold<dim, spacedim>::
1060  InternalData &>(mapping_data);
1061 
1062  switch (mapping_type)
1063  {
1065  {
1066  Assert(
1067  data.update_each & update_covariant_transformation,
1069  "update_covariant_transformation"));
1070  Assert(
1071  data.update_each & update_contravariant_transformation,
1073  "update_contravariant_transformation"));
1074 
1075  for (unsigned int q = 0; q < output.size(); ++q)
1076  for (unsigned int i = 0; i < spacedim; ++i)
1077  {
1078  double tmp1[dim][dim];
1079  for (unsigned int J = 0; J < dim; ++J)
1080  for (unsigned int K = 0; K < dim; ++K)
1081  {
1082  tmp1[J][K] =
1083  data.contravariant[q][i][0] * input[q][0][J][K];
1084  for (unsigned int I = 1; I < dim; ++I)
1085  tmp1[J][K] +=
1086  data.contravariant[q][i][I] * input[q][I][J][K];
1087  }
1088  for (unsigned int j = 0; j < spacedim; ++j)
1089  {
1090  double tmp2[dim];
1091  for (unsigned int K = 0; K < dim; ++K)
1092  {
1093  tmp2[K] = data.covariant[q][j][0] * tmp1[0][K];
1094  for (unsigned int J = 1; J < dim; ++J)
1095  tmp2[K] += data.covariant[q][j][J] * tmp1[J][K];
1096  }
1097  for (unsigned int k = 0; k < spacedim; ++k)
1098  {
1099  output[q][i][j][k] =
1100  data.covariant[q][k][0] * tmp2[0];
1101  for (unsigned int K = 1; K < dim; ++K)
1102  output[q][i][j][k] +=
1103  data.covariant[q][k][K] * tmp2[K];
1104  }
1105  }
1106  }
1107  return;
1108  }
1109 
1111  {
1112  Assert(
1113  data.update_each & update_covariant_transformation,
1115  "update_covariant_transformation"));
1116 
1117  for (unsigned int q = 0; q < output.size(); ++q)
1118  for (unsigned int i = 0; i < spacedim; ++i)
1119  {
1120  double tmp1[dim][dim];
1121  for (unsigned int J = 0; J < dim; ++J)
1122  for (unsigned int K = 0; K < dim; ++K)
1123  {
1124  tmp1[J][K] =
1125  data.covariant[q][i][0] * input[q][0][J][K];
1126  for (unsigned int I = 1; I < dim; ++I)
1127  tmp1[J][K] +=
1128  data.covariant[q][i][I] * input[q][I][J][K];
1129  }
1130  for (unsigned int j = 0; j < spacedim; ++j)
1131  {
1132  double tmp2[dim];
1133  for (unsigned int K = 0; K < dim; ++K)
1134  {
1135  tmp2[K] = data.covariant[q][j][0] * tmp1[0][K];
1136  for (unsigned int J = 1; J < dim; ++J)
1137  tmp2[K] += data.covariant[q][j][J] * tmp1[J][K];
1138  }
1139  for (unsigned int k = 0; k < spacedim; ++k)
1140  {
1141  output[q][i][j][k] =
1142  data.covariant[q][k][0] * tmp2[0];
1143  for (unsigned int K = 1; K < dim; ++K)
1144  output[q][i][j][k] +=
1145  data.covariant[q][k][K] * tmp2[K];
1146  }
1147  }
1148  }
1149 
1150  return;
1151  }
1152 
1153  case mapping_piola_hessian:
1154  {
1155  Assert(
1156  data.update_each & update_covariant_transformation,
1158  "update_covariant_transformation"));
1159  Assert(
1160  data.update_each & update_contravariant_transformation,
1162  "update_contravariant_transformation"));
1163  Assert(
1164  data.update_each & update_volume_elements,
1166  "update_volume_elements"));
1167 
1168  for (unsigned int q = 0; q < output.size(); ++q)
1169  for (unsigned int i = 0; i < spacedim; ++i)
1170  {
1171  double factor[dim];
1172  for (unsigned int I = 0; I < dim; ++I)
1173  factor[I] =
1174  data.contravariant[q][i][I] / data.volume_elements[q];
1175  double tmp1[dim][dim];
1176  for (unsigned int J = 0; J < dim; ++J)
1177  for (unsigned int K = 0; K < dim; ++K)
1178  {
1179  tmp1[J][K] = factor[0] * input[q][0][J][K];
1180  for (unsigned int I = 1; I < dim; ++I)
1181  tmp1[J][K] += factor[I] * input[q][I][J][K];
1182  }
1183  for (unsigned int j = 0; j < spacedim; ++j)
1184  {
1185  double tmp2[dim];
1186  for (unsigned int K = 0; K < dim; ++K)
1187  {
1188  tmp2[K] = data.covariant[q][j][0] * tmp1[0][K];
1189  for (unsigned int J = 1; J < dim; ++J)
1190  tmp2[K] += data.covariant[q][j][J] * tmp1[J][K];
1191  }
1192  for (unsigned int k = 0; k < spacedim; ++k)
1193  {
1194  output[q][i][j][k] =
1195  data.covariant[q][k][0] * tmp2[0];
1196  for (unsigned int K = 1; K < dim; ++K)
1197  output[q][i][j][k] +=
1198  data.covariant[q][k][K] * tmp2[K];
1199  }
1200  }
1201  }
1202 
1203  return;
1204  }
1205 
1206  default:
1207  Assert(false, ExcNotImplemented());
1208  }
1209  }
1210 
1211 
1212 
1213  template <int dim, int spacedim, int rank>
1214  void
1215  transform_differential_forms(
1216  const ArrayView<const DerivativeForm<rank, dim, spacedim>> &input,
1217  const MappingType mapping_type,
1218  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1219  const ArrayView<Tensor<rank + 1, spacedim>> & output)
1220  {
1221  AssertDimension(input.size(), output.size());
1222  Assert((dynamic_cast<const typename ::
1223  MappingManifold<dim, spacedim>::InternalData *>(
1224  &mapping_data) != nullptr),
1225  ExcInternalError());
1226  const typename ::MappingManifold<dim, spacedim>::InternalData
1227  &data =
1228  static_cast<const typename ::MappingManifold<dim, spacedim>::
1229  InternalData &>(mapping_data);
1230 
1231  switch (mapping_type)
1232  {
1233  case mapping_covariant:
1234  {
1235  Assert(
1236  data.update_each & update_contravariant_transformation,
1238  "update_covariant_transformation"));
1239 
1240  for (unsigned int i = 0; i < output.size(); ++i)
1241  output[i] = apply_transformation(data.covariant[i], input[i]);
1242 
1243  return;
1244  }
1245  default:
1246  Assert(false, ExcNotImplemented());
1247  }
1248  }
1249  } // namespace
1250  } // namespace MappingManifoldImplementation
1251 } // namespace internal
1252 
1253 
1254 
1255 template <int dim, int spacedim>
1256 void
1259  const unsigned int face_no,
1260  const Quadrature<dim - 1> & quadrature,
1261  const typename Mapping<dim, spacedim>::InternalDataBase & internal_data,
1263  &output_data) const
1264 {
1265  // ensure that the following cast is really correct:
1266  Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1267  ExcInternalError());
1268  const InternalData &data = static_cast<const InternalData &>(internal_data);
1269 
1270  internal::MappingManifoldImplementation::do_fill_fe_face_values(
1271  *this,
1272  cell,
1273  face_no,
1276  cell->face_orientation(face_no),
1277  cell->face_flip(face_no),
1278  cell->face_rotation(face_no),
1279  quadrature.size()),
1280  quadrature,
1281  data,
1282  output_data);
1283 }
1284 
1285 
1286 
1287 template <int dim, int spacedim>
1288 void
1291  const unsigned int face_no,
1292  const unsigned int subface_no,
1293  const Quadrature<dim - 1> & quadrature,
1294  const typename Mapping<dim, spacedim>::InternalDataBase & internal_data,
1296  &output_data) const
1297 {
1298  // ensure that the following cast is really correct:
1299  Assert((dynamic_cast<const InternalData *>(&internal_data) != nullptr),
1300  ExcInternalError());
1301  const InternalData &data = static_cast<const InternalData &>(internal_data);
1302 
1303  internal::MappingManifoldImplementation::do_fill_fe_face_values(
1304  *this,
1305  cell,
1306  face_no,
1307  subface_no,
1309  subface_no,
1310  cell->face_orientation(face_no),
1311  cell->face_flip(face_no),
1312  cell->face_rotation(face_no),
1313  quadrature.size(),
1314  cell->subface_case(face_no)),
1315  quadrature,
1316  data,
1317  output_data);
1318 }
1319 
1320 
1321 
1322 template <int dim, int spacedim>
1323 void
1325  const ArrayView<const Tensor<1, dim>> & input,
1326  const MappingType mapping_type,
1327  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1328  const ArrayView<Tensor<1, spacedim>> & output) const
1329 {
1330  internal::MappingManifoldImplementation::transform_fields(input,
1331  mapping_type,
1332  mapping_data,
1333  output);
1334 }
1335 
1336 
1337 
1338 template <int dim, int spacedim>
1339 void
1341  const ArrayView<const DerivativeForm<1, dim, spacedim>> &input,
1342  const MappingType mapping_type,
1343  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1344  const ArrayView<Tensor<2, spacedim>> & output) const
1345 {
1346  internal::MappingManifoldImplementation::transform_differential_forms(
1347  input, mapping_type, mapping_data, output);
1348 }
1349 
1350 
1351 
1352 template <int dim, int spacedim>
1353 void
1355  const ArrayView<const Tensor<2, dim>> & input,
1356  const MappingType mapping_type,
1357  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1358  const ArrayView<Tensor<2, spacedim>> & output) const
1359 {
1360  switch (mapping_type)
1361  {
1362  case mapping_contravariant:
1363  internal::MappingManifoldImplementation::transform_fields(input,
1364  mapping_type,
1365  mapping_data,
1366  output);
1367  return;
1368 
1372  internal::MappingManifoldImplementation::transform_gradients(
1373  input, mapping_type, mapping_data, output);
1374  return;
1375  default:
1376  Assert(false, ExcNotImplemented());
1377  }
1378 }
1379 
1380 
1381 
1382 template <int dim, int spacedim>
1383 void
1385  const ArrayView<const DerivativeForm<2, dim, spacedim>> &input,
1386  const MappingType mapping_type,
1387  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1388  const ArrayView<Tensor<3, spacedim>> & output) const
1389 {
1390  AssertDimension(input.size(), output.size());
1391  Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
1392  ExcInternalError());
1393  const InternalData &data = static_cast<const InternalData &>(mapping_data);
1394 
1395  switch (mapping_type)
1396  {
1398  {
1401  "update_covariant_transformation"));
1402 
1403  for (unsigned int q = 0; q < output.size(); ++q)
1404  for (unsigned int i = 0; i < spacedim; ++i)
1405  for (unsigned int j = 0; j < spacedim; ++j)
1406  {
1407  double tmp[dim];
1408  for (unsigned int K = 0; K < dim; ++K)
1409  {
1410  tmp[K] = data.covariant[q][j][0] * input[q][i][0][K];
1411  for (unsigned int J = 1; J < dim; ++J)
1412  tmp[K] += data.covariant[q][j][J] * input[q][i][J][K];
1413  }
1414  for (unsigned int k = 0; k < spacedim; ++k)
1415  {
1416  output[q][i][j][k] = data.covariant[q][k][0] * tmp[0];
1417  for (unsigned int K = 1; K < dim; ++K)
1418  output[q][i][j][k] += data.covariant[q][k][K] * tmp[K];
1419  }
1420  }
1421  return;
1422  }
1423 
1424  default:
1425  Assert(false, ExcNotImplemented());
1426  }
1427 }
1428 
1429 
1430 
1431 template <int dim, int spacedim>
1432 void
1434  const ArrayView<const Tensor<3, dim>> & input,
1435  const MappingType mapping_type,
1436  const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
1437  const ArrayView<Tensor<3, spacedim>> & output) const
1438 {
1439  switch (mapping_type)
1440  {
1441  case mapping_piola_hessian:
1444  internal::MappingManifoldImplementation::transform_hessians(
1445  input, mapping_type, mapping_data, output);
1446  return;
1447  default:
1448  Assert(false, ExcNotImplemented());
1449  }
1450 }
1451 
1452 //--------------------------- Explicit instantiations -----------------------
1453 #include "mapping_manifold.inst"
1454 
1455 
1456 DEAL_II_NAMESPACE_CLOSE
Transformed quadrature weights.
std::vector< DerivativeForm< 1, dim, spacedim > > covariant
static const unsigned int invalid_unsigned_int
Definition: types.h:173
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 override
virtual std::unique_ptr< Mapping< dim, spacedim > > clone() const override
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1366
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::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
SmartPointer< const Manifold< dim, spacedim > > manifold
Number determinant(const SymmetricTensor< 2, dim, Number > &)
Contravariant transformation.
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::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
std::vector< DerivativeForm< 1, dim, spacedim > > contravariant
MappingType
Definition: mapping.h:61
std::array< std::vector< Tensor< 1, dim > >, GeometryInfo< dim >::faces_per_cell *(dim-1)> unit_tangentials
std::vector< Tensor< 1, spacedim > > boundary_forms
Volume element.
static Point< dim, Number > unit_vector(const unsigned int i)
Outer normal vector, not normalized.
Determinant of the Jacobian.
Transformed quadrature points.
virtual std::size_t memory_consumption() const override
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1301
static DataSetDescriptor cell()
Definition: qprojector.h:344
Triangulation< dim, spacedim >::cell_iterator cell
std::vector< Point< spacedim > > vertices
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_subface_data(const UpdateFlags flags, const Quadrature< dim-1 > &quadrature) const override
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const override
void store_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
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::FEValuesImplementation::MappingRelatedData< dim, spacedim > &output_data) const override
std::vector< std::vector< Tensor< 1, spacedim > > > aux
unsigned int size() const
static::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1227
UpdateFlags
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
Abstract base class for mapping classes.
Definition: dof_tools.h:57
void initialize(const UpdateFlags update_flags, const Quadrature< dim > &quadrature, const unsigned int n_original_q_points)
SymmetricTensor< rank_, dim, Number > transpose(const SymmetricTensor< rank_, dim, Number > &t)
Gradient of volume element.
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:96
std::vector< double > volume_elements
const std::vector< double > & get_weights() const
std::vector< double > vertex_weights
void compute_manifold_quadrature_weights(const Quadrature< dim > &quadrature)
std::vector< Point< spacedim > > quadrature_points
DerivativeForm< 1, spacedim, dim, Number > transpose() const
static double d_linear_shape_function(const Point< dim > &xi, const unsigned int i)
Normal vectors.
std::vector< DerivativeForm< 1, dim, spacedim > > jacobians
virtual Point< spacedim > transform_unit_to_real_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &p) const override
static::ExceptionBase & ExcNotImplemented()
virtual Point< dim > transform_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p) const override
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_data(const UpdateFlags, const Quadrature< dim > &quadrature) const override
void initialize_face(const UpdateFlags update_flags, const Quadrature< dim > &quadrature, const unsigned int n_original_q_points)
virtual std::unique_ptr< typename Mapping< dim, spacedim >::InternalDataBase > get_face_data(const UpdateFlags flags, const Quadrature< dim-1 > &quadrature) const override
std::vector< DerivativeForm< 1, spacedim, dim > > inverse_jacobians
static double subface_ratio(const internal::SubfaceCase< dim > &subface_case, const unsigned int subface_no)
Covariant transformation.
std::vector< std::vector< double > > cell_manifold_quadrature_weights
std::vector< Tensor< 1, spacedim > > normal_vectors
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
MappingManifold()=default
UpdateFlags update_each
Definition: mapping.h:576
static::ExceptionBase & ExcInternalError()