Reference documentation for deal.II version 9.0.0
manifold.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 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 at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/tensor.h>
17 #include <deal.II/base/table.h>
18 #include <deal.II/base/std_cxx14/memory.h>
19 #include <deal.II/grid/manifold.h>
20 #include <deal.II/grid/tria.h>
21 #include <deal.II/grid/tria_iterator.h>
22 #include <deal.II/grid/tria_accessor.h>
23 #include <deal.II/fe/fe_q.h>
24 
25 #include <cmath>
26 
27 #include <boost/container/small_vector.hpp>
28 
29 DEAL_II_NAMESPACE_OPEN
30 
31 using namespace Manifolds;
32 
33 /* -------------------------- Manifold --------------------- */
34 template <int dim, int spacedim>
38  const Point<spacedim> &) const
39 {
40  Assert (false, ExcPureFunctionCalled());
41  return Point<spacedim>();
42 }
43 
44 
45 
46 template <int dim, int spacedim>
50  const Point<spacedim> &p2,
51  const double w) const
52 {
53  const std::array<Point<spacedim>, 2> vertices {{p1, p2}};
54  return project_to_manifold(make_array_view(vertices.begin(), vertices.end()),
55  w * p2 + (1-w)*p1);
56 }
57 
58 
59 
60 template <int dim, int spacedim>
63 get_new_point (const ArrayView<const Point<spacedim>> &surrounding_points,
64  const ArrayView<const double> &weights) const
65 {
66  const double tol = 1e-10;
67  const unsigned int n_points = surrounding_points.size();
68 
69  Assert(n_points > 0,
70  ExcMessage("There should be at least one point."));
71 
72  Assert(n_points == weights.size(),
73  ExcMessage("There should be as many surrounding points as weights given."));
74 
75  Assert(std::abs(std::accumulate(weights.begin(), weights.end(), 0.0)-1.0) < tol,
76  ExcMessage("The weights for the individual points should sum to 1!"));
77 
78  // First sort points in the order of their weights. This is done to
79  // produce unique points even if get_intermediate_points is not
80  // associative (as for the SphericalManifold).
81  boost::container::small_vector<unsigned int, 100> permutation(n_points);
82  std::iota(permutation.begin(), permutation.end(), 0u);
83  std::sort(permutation.begin(), permutation.end(),
84  [&weights](const std::size_t a, const std::size_t b)
85  {
86  return weights[a] < weights[b];
87  });
88 
89  // Now loop over points in the order of their associated weight
90  Point<spacedim> p = surrounding_points[permutation[0]];
91  double w = weights[permutation[0]];
92 
93  for (unsigned int i=1; i<n_points; ++i)
94  {
95  double weight = 0.0;
96  if ( (weights[permutation[i]] + w) < tol )
97  weight = 0.0;
98  else
99  weight = w/(weights[permutation[i]] + w);
100 
101  if (std::abs(weight) > 1e-14)
102  p = get_intermediate_point(p, surrounding_points[permutation[i]],1.0 - weight );
103  w += weights[permutation[i]];
104  }
105 
106  return p;
107 }
108 
109 
110 
111 template <int dim, int spacedim>
112 void
114 get_new_points (const ArrayView<const Point<spacedim>> &surrounding_points,
115  const Table<2,double> &weights,
116  ArrayView<Point<spacedim>> new_points) const
117 {
118  AssertDimension(surrounding_points.size(), weights.size(1));
119 
120  for (unsigned int row=0; row<weights.size(0); ++row)
121  {
122  new_points[row] = get_new_point(make_array_view(surrounding_points.begin(),
123  surrounding_points.end()),
124  make_array_view(weights,
125  row));
126  }
127 }
128 
129 
130 
131 template <>
135  const Point<2> &p) const
136 {
137  const int spacedim=2;
138 
139  // get the tangent vector from the point 'p' in the direction of the further
140  // one of the two vertices that make up the face of this 2d cell
141  const Tensor<1,spacedim> tangent
142  = ((p-face->vertex(0)).norm_square() > (p-face->vertex(1)).norm_square() ?
143  -get_tangent_vector(p, face->vertex(0)) :
144  get_tangent_vector(p, face->vertex(1)));
145 
146  // then rotate it by 90 degrees
147  const Tensor<1,spacedim> normal = cross_product_2d(tangent);
148  return normal/normal.norm();
149 }
150 
151 
152 
153 template <>
157  const Point<3> &p) const
158 {
159  const int spacedim=3;
160 
161  const std::array<Point<spacedim>, 4> vertices
162  {{face->vertex(0), face->vertex(1), face->vertex(2), face->vertex(3)}};
163  const std::array<double, 4> distances
164  {{vertices[0].distance(p), vertices[1].distance(p), vertices[2].distance(p), vertices[3].distance(p)}};
165  const double max_distance = std::max(std::max(distances[0], distances[1]),
166  std::max(distances[2], distances[3]));
167 
168  // We need to find two tangential vectors to the given point p, but we do
169  // not know how the point is oriented against the face. We guess the two
170  // directions by assuming a flat topology and take the two directions that
171  // indicate the angle closest to a perpendicular one (i.e., cos(theta) close
172  // to zero). We start with an invalid value but the loops should always find
173  // a value.
174  double abs_cos_angle = std::numeric_limits<double>::max();
175  unsigned int first_index = numbers::invalid_unsigned_int,
176  second_index = numbers::invalid_unsigned_int;
177  for (unsigned int i=0; i<3; ++i)
178  if (distances[i] > 1e-8*max_distance)
179  for (unsigned int j=i+1; j<4; ++j)
180  if (distances[j] > 1e-8*max_distance)
181  {
182  const double new_angle = (p-vertices[i]) * (p-vertices[j]) /
183  (distances[i]*distances[j]);
184  // multiply by factor 0.999 to bias the search in a way that
185  // avoids trouble with roundoff
186  if (std::abs(new_angle) < 0.999 * abs_cos_angle)
187  {
188  abs_cos_angle = std::abs(new_angle);
189  first_index = i;
190  second_index = j;
191  }
192  }
193  Assert(first_index != numbers::invalid_unsigned_int,
194  ExcMessage("The search for possible directions did not succeed."));
195 
196  // Compute tangents and normal for selected vertices
197  Tensor<1,spacedim> t1 = get_tangent_vector(p, vertices[first_index]);
198  Tensor<1,spacedim> t2 = get_tangent_vector(p, vertices[second_index]);
199  Tensor<1,spacedim> normal = cross_product_3d(t1,t2);
200 
201  Assert(normal.norm_square() > 1e4 * std::numeric_limits<double>::epsilon() *
202  t1.norm_square() * t2.norm_square(),
203  ExcMessage("Manifold::normal_vector was unable to find a suitable combination "
204  "of vertices to compute a normal on this face. We chose the secants "
205  "that are as orthogonal as possible, but tangents appear to be "
206  "linearly dependent. Check for distorted faces in your triangulation."));
207 
208  // Now figure out if we need to flip the direction, we do this by comparing
209  // to a reference normal that would be the correct result if all vertices
210  // would lie in a plane
211  const Tensor<1,spacedim> rt1 = vertices[3] - vertices[0];
212  const Tensor<1,spacedim> rt2 = vertices[2] - vertices[1];
213  const Tensor<1,spacedim> reference_normal = cross_product_3d(rt1,rt2);
214 
215  if (reference_normal * normal < 0.0)
216  normal *= -1.0;
217 
218  return normal / normal.norm();
219 }
220 
221 
222 
223 template <int dim, int spacedim>
227  const Point<spacedim> &/*p*/) const
228 {
229  Assert(false, ExcPureFunctionCalled());
230  return Tensor<1,spacedim>();
231 }
232 
233 
234 
235 template <>
236 void
239  FaceVertexNormals &n) const
240 {
241  n[0] = cross_product_2d(get_tangent_vector(face->vertex(0), face->vertex(1)));
242  n[1] = -cross_product_2d(get_tangent_vector(face->vertex(1), face->vertex(0)));
243 
244  for (unsigned int i=0; i<2; ++i)
245  {
246  Assert(n[i].norm() != 0, ExcInternalError("Something went wrong. The "
247  "computed normals have "
248  "zero length."));
249  n[i] /= n[i].norm();
250  }
251 }
252 
253 
254 
255 template <>
256 void
259  FaceVertexNormals &n) const
260 {
261  n[0] = cross_product_3d
262  (get_tangent_vector(face->vertex(0), face->vertex(1)),
263  get_tangent_vector(face->vertex(0), face->vertex(2)));
264 
265  n[1] = cross_product_3d
266  (get_tangent_vector(face->vertex(1), face->vertex(3)),
267  get_tangent_vector(face->vertex(1), face->vertex(0)));
268 
269  n[2] = cross_product_3d
270  (get_tangent_vector(face->vertex(2), face->vertex(0)),
271  get_tangent_vector(face->vertex(2), face->vertex(3)));
272 
273  n[3] = cross_product_3d
274  (get_tangent_vector(face->vertex(3), face->vertex(2)),
275  get_tangent_vector(face->vertex(3), face->vertex(1)));
276 
277  for (unsigned int i=0; i<4; ++i)
278  {
279  Assert(n[i].norm() != 0, ExcInternalError("Something went wrong. The "
280  "computed normals have "
281  "zero length."));
282  n[i] /=n[i].norm();
283  }
284 }
285 
286 
287 
288 template <int dim, int spacedim>
289 void
292  FaceVertexNormals &n) const
293 {
294  for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_face; ++v)
295  {
296  n[v] = normal_vector(face, face->vertex(v));
297  n[v] /= n[v].norm();
298  }
299 }
300 
301 
302 
303 template <int dim, int spacedim>
306 get_new_point_on_line (const typename Triangulation<dim, spacedim>::line_iterator &line) const
307 {
308  const auto points_weights = get_default_points_and_weights(line);
309  return get_new_point (make_array_view(points_weights.first.begin(),
310  points_weights.first.end()),
311  make_array_view(points_weights.second.begin(),
312  points_weights.second.end()));
313 }
314 
315 
316 
317 template <int dim, int spacedim>
320 get_new_point_on_quad (const typename Triangulation<dim, spacedim>::quad_iterator &quad) const
321 {
322  const auto points_weights = get_default_points_and_weights(quad);
323  return get_new_point (make_array_view(points_weights.first.begin(),
324  points_weights.first.end()),
325  make_array_view(points_weights.second.begin(),
326  points_weights.second.end()));
327 }
328 
329 
330 
331 template <int dim, int spacedim>
335 {
336  Assert (dim>1, ExcImpossibleInDim(dim));
337 
338  switch (dim)
339  {
340  case 2:
341  return get_new_point_on_line (face);
342  case 3:
343  return get_new_point_on_quad (face);
344  }
345 
346  return Point<spacedim>();
347 }
348 
349 
350 
351 template <int dim, int spacedim>
355 {
356  switch (dim)
357  {
358  case 1:
359  return get_new_point_on_line (cell);
360  case 2:
361  return get_new_point_on_quad (cell);
362  case 3:
363  return get_new_point_on_hex (cell);
364  }
365 
366  return Point<spacedim>();
367 }
368 
369 
370 
371 template <>
372 Point<1>
375 {
376  Assert (false, ExcImpossibleInDim(1));
377  return Point<1>();
378 }
379 
380 
381 
382 template <>
383 Point<2>
386 {
387  Assert (false, ExcImpossibleInDim(1));
388  return Point<2>();
389 }
390 
391 
392 
393 template <>
394 Point<3>
397 {
398  Assert (false, ExcImpossibleInDim(1));
399  return Point<3>();
400 }
401 
402 
403 
404 template <>
405 Point<1>
407 get_new_point_on_quad (const Triangulation<1,1>::quad_iterator &) const
408 {
409  Assert (false, ExcImpossibleInDim(1));
410  return Point<1>();
411 }
412 
413 
414 
415 template <>
416 Point<2>
418 get_new_point_on_quad (const Triangulation<1,2>::quad_iterator &) const
419 {
420  Assert (false, ExcImpossibleInDim(1));
421  return Point<2>();
422 }
423 
424 
425 
426 template <>
427 Point<3>
429 get_new_point_on_quad (const Triangulation<1,3>::quad_iterator &) const
430 {
431  Assert (false, ExcImpossibleInDim(1));
432  return Point<3>();
433 }
434 
435 
436 
437 template <int dim, int spacedim>
440 get_new_point_on_hex (const typename Triangulation<dim, spacedim>::hex_iterator &/*hex*/) const
441 {
442  Assert (false, ExcImpossibleInDim(dim));
443  return Point<spacedim>();
444 }
445 
446 
447 
448 template <>
449 Point<3>
451 get_new_point_on_hex (const Triangulation<3, 3>::hex_iterator &hex) const
452 {
453  const auto points_weights = get_default_points_and_weights(hex, true);
454  return get_new_point (make_array_view(points_weights.first.begin(),
455  points_weights.first.end()),
456  make_array_view(points_weights.second.begin(),
457  points_weights.second.end()));
458 }
459 
460 
461 
462 template <int dim, int spacedim>
465  const Point<spacedim> &x2) const
466 {
467  const double epsilon = 1e-8;
468 
469  const std::array<Point<spacedim>, 2> points {{x1, x2}};
470  const std::array<double, 2> weights {{epsilon, 1.0 - epsilon}};
471  const Point<spacedim> neighbor_point = get_new_point (make_array_view(points.begin(),
472  points.end()),
473  make_array_view(weights.begin(),
474  weights.end()));
475  return (neighbor_point-x1)/epsilon;
476 }
477 
478 /* -------------------------- FlatManifold --------------------- */
479 
480 namespace internal
481 {
482  namespace
483  {
485  normalized_alternating_product (const Tensor<1,3> ( &)[1])
486  {
487  // we get here from FlatManifold<2,3>::normal_vector, but
488  // the implementation below is bogus for this case anyway
489  // (see the assert at the beginning of that function).
490  Assert (false, ExcNotImplemented());
491  return Tensor<1,3>();
492  }
493 
494 
495 
497  normalized_alternating_product (const Tensor<1,3> (&basis_vectors)[2])
498  {
499  Tensor<1,3> tmp = cross_product_3d (basis_vectors[0], basis_vectors[1]);
500  return tmp/tmp.norm();
501  }
502 
503  }
504 }
505 
506 template <int dim, int spacedim>
508  const double tolerance)
509  :
510  periodicity(periodicity),
511  tolerance(tolerance)
512 {}
513 
514 
515 
516 template<int dim, int spacedim>
517 std::unique_ptr<Manifold<dim, spacedim> >
519 {
520  return std_cxx14::make_unique<FlatManifold<dim,spacedim> >(periodicity, tolerance);
521 }
522 
523 
524 
525 template <int dim, int spacedim>
528 get_new_point (const ArrayView<const Point<spacedim>> &surrounding_points,
529  const ArrayView<const double> &weights) const
530 {
531  Assert(std::abs(std::accumulate(weights.begin(), weights.end(), 0.0)-1.0) < 1e-10,
532  ExcMessage("The weights for the individual points should sum to 1!"));
533 
534  Point<spacedim> p;
535 
536  // if there is no periodicity, use a shortcut
537  if (periodicity == Tensor<1,spacedim>())
538  {
539  for (unsigned int i=0; i<surrounding_points.size(); ++i)
540  p += surrounding_points[i] * weights[i];
541  }
542  else
543  {
544  Tensor<1,spacedim> minP = periodicity;
545 
546  for (unsigned int d=0; d<spacedim; ++d)
547  if (periodicity[d] > 0)
548  for (unsigned int i=0; i<surrounding_points.size(); ++i)
549  {
550  minP[d] = std::min(minP[d], surrounding_points[i][d]);
551  Assert( (surrounding_points[i][d] < periodicity[d]+tolerance*periodicity[d]) ||
552  (surrounding_points[i][d] >= -tolerance*periodicity[d]),
553  ExcPeriodicBox(d, surrounding_points[i], periodicity[d]));
554  }
555 
556  // compute the weighted average point, possibly taking into account periodicity
557  for (unsigned int i=0; i<surrounding_points.size(); ++i)
558  {
559  Point<spacedim> dp;
560  for (unsigned int d=0; d<spacedim; ++d)
561  if (periodicity[d] > 0)
562  dp[d] = ( (surrounding_points[i][d]-minP[d]) > periodicity[d]/2.0 ?
563  -periodicity[d] : 0.0 );
564 
565  p += (surrounding_points[i]+dp)*weights[i];
566  }
567 
568  // if necessary, also adjust the weighted point by the periodicity
569  for (unsigned int d=0; d<spacedim; ++d)
570  if (periodicity[d] > 0)
571  if (p[d] < 0)
572  p[d] += periodicity[d];
573  }
574 
575  return project_to_manifold(surrounding_points, p);
576 }
577 
578 
579 
580 template <int dim, int spacedim>
581 void
583 get_new_points (const ArrayView<const Point<spacedim>> &surrounding_points,
584  const Table<2,double> &weights,
585  ArrayView<Point<spacedim>> new_points) const
586 {
587  AssertDimension(surrounding_points.size(), weights.size(1));
588  if (weights.size(0) == 0)
589  return;
590 
591  const std::size_t n_points = surrounding_points.size();
592 
593  Tensor<1,spacedim> minP = periodicity;
594  for (unsigned int d=0; d<spacedim; ++d)
595  if (periodicity[d] > 0)
596  for (unsigned int i=0; i<n_points; ++i)
597  {
598  minP[d] = std::min(minP[d], surrounding_points[i][d]);
599  Assert( (surrounding_points[i][d] < periodicity[d]+tolerance*periodicity[d]) ||
600  (surrounding_points[i][d] >= -tolerance*periodicity[d]),
601  ExcPeriodicBox(d, surrounding_points[i], periodicity[i]));
602  }
603 
604  // check whether periodicity shifts some of the points. Only do this if
605  // necessary to avoid memory allocation
606  const Point<spacedim> *surrounding_points_start = surrounding_points.data();
607 
608  boost::container::small_vector<Point<spacedim>, 200> modified_points;
609  bool adjust_periodicity = false;
610  for (unsigned int d=0; d<spacedim; ++d)
611  if (periodicity[d] > 0)
612  for (unsigned int i=0; i<n_points; ++i)
613  if ((surrounding_points[i][d]-minP[d]) > periodicity[d]/2.0)
614  {
615  adjust_periodicity = true;
616  break;
617  }
618  if (adjust_periodicity == true)
619  {
620  modified_points.resize(surrounding_points.size());
621  std::copy(surrounding_points.begin(), surrounding_points.end(),
622  modified_points.begin());
623  for (unsigned int d=0; d<spacedim; ++d)
624  if (periodicity[d] > 0)
625  for (unsigned int i=0; i<n_points; ++i)
626  if ((surrounding_points[i][d]-minP[d]) > periodicity[d]/2.0)
627  modified_points[i][d] -= periodicity[d];
628  surrounding_points_start = modified_points.data();
629  }
630 
631  // Now perform the interpolation
632  for (unsigned int row=0; row<weights.size(0); ++row)
633  {
634  Assert(std::abs(std::accumulate(&weights(row,0), &weights(row,0)+n_points, 0.0)-1.0) < 1e-10,
635  ExcMessage("The weights for the individual points should sum to 1!"));
636  Point<spacedim> new_point;
637  for (unsigned int p=0; p<n_points; ++p)
638  new_point += surrounding_points_start[p] * weights(row,p);
639 
640  // if necessary, also adjust the weighted point by the periodicity
641  for (unsigned int d=0; d<spacedim; ++d)
642  if (periodicity[d] > 0)
643  if (new_point[d] < 0)
644  new_point[d] += periodicity[d];
645 
646  // TODO should this use surrounding_points_start or surrounding_points?
647  // The older version used surrounding_points
648  new_points[row] = project_to_manifold(make_array_view(surrounding_points.begin(),
649  surrounding_points.end()),
650  new_point);
651  }
652 }
653 
654 
655 
656 template <int dim, int spacedim>
659 (const ArrayView<const Point<spacedim>> &/*vertices*/,
660  const Point<spacedim> &candidate) const
661 {
662  return candidate;
663 }
664 
665 
666 
667 template <int dim, int spacedim>
668 const Tensor<1,spacedim> &
670 {
671  return periodicity;
672 }
673 
674 
675 
676 template <int dim, int spacedim>
679  const Point<spacedim> &x2) const
680 {
681  Tensor<1,spacedim> direction = x2-x1;
682 
683  // see if we have to take into account periodicity. if so, we need
684  // to make sure that if a distance in one coordinate direction
685  // is larger than half of the box length, then go the other way
686  // around (i.e., via the periodic box)
687  for (unsigned int d=0; d<spacedim; ++d)
688  if (periodicity[d] > tolerance)
689  {
690  if (direction[d] < -periodicity[d]/2)
691  direction[d] += periodicity[d];
692  else if (direction[d] > periodicity[d]/2)
693  direction[d] -= periodicity[d];
694  }
695 
696  return direction;
697 }
698 
699 
700 
701 template <>
702 void
706 {
707  Assert (false, ExcImpossibleInDim(1));
708 }
709 
710 
711 
712 template <>
713 void
717 {
718  Assert (false, ExcNotImplemented());
719 }
720 
721 
722 
723 template <>
724 void
728 {
729  Assert (false, ExcNotImplemented());
730 }
731 
732 
733 
734 template <>
735 void
738  Manifold<2,2>::FaceVertexNormals &face_vertex_normals) const
739 {
740  const Tensor<1,2> tangent = face->vertex(1) - face->vertex(0);
741  for (unsigned int vertex=0; vertex<GeometryInfo<2>::vertices_per_face; ++vertex)
742  // compute normals from tangent
743  face_vertex_normals[vertex] = Point<2>(tangent[1],
744  -tangent[0]);
745 }
746 
747 
748 
749 template <>
750 void
753  Manifold<2,3>::FaceVertexNormals &/*face_vertex_normals*/) const
754 {
755  Assert(false, ExcNotImplemented());
756 }
757 
758 
759 
760 template <>
761 void
764  Manifold<3,3>::FaceVertexNormals &face_vertex_normals) const
765 {
766  const unsigned int vertices_per_face = GeometryInfo<3>::vertices_per_face;
767 
768  static const unsigned int neighboring_vertices[4][2]=
769  { {1,2},{3,0},{0,3},{2,1}};
770  for (unsigned int vertex=0; vertex<vertices_per_face; ++vertex)
771  {
772  // first define the two tangent vectors at the vertex by using the
773  // two lines radiating away from this vertex
774  const Tensor<1,3> tangents[2]
775  = { face->vertex(neighboring_vertices[vertex][0])
776  - face->vertex(vertex),
777  face->vertex(neighboring_vertices[vertex][1])
778  - face->vertex(vertex)
779  };
780 
781  // then compute the normal by taking the cross product. since the
782  // normal is not required to be normalized, no problem here
783  face_vertex_normals[vertex] = cross_product_3d(tangents[0], tangents[1]);
784  }
785 }
786 
787 
788 
789 template <>
793  const Point<1> &) const
794 {
795  Assert (false, ExcNotImplemented());
796  return Tensor<1,1>();
797 }
798 
799 
800 
801 template <>
805  const Point<2> &) const
806 {
807  Assert (false, ExcNotImplemented());
808  return Tensor<1,2>();
809 }
810 
811 
812 
813 template <>
817  const Point<3> &) const
818 {
819  Assert (false, ExcNotImplemented());
820  return Tensor<1,3>();
821 }
822 
823 
824 
825 template <>
829  const Point<2> &p) const
830 {
831  // In 2d, a face is just a straight line and
832  // we can use the 'standard' implementation.
833  return Manifold<2,2>::normal_vector(face, p);
834 }
835 
836 
837 
838 template <int dim, int spacedim>
842  const Point<spacedim> &p) const
843 {
844  // I don't think the implementation below will work when dim!=spacedim;
845  // in fact, I believe that we don't even have enough information here,
846  // because we would need to know not only about the tangent vectors
847  // of the face, but also of the cell, to compute the normal vector.
848  // Someone will have to think about this some more.
849  Assert (dim == spacedim, ExcNotImplemented());
850 
851  // in order to find out what the normal vector is, we first need to
852  // find the reference coordinates of the point p on the given face,
853  // or at least the reference coordinates of the closest point on the
854  // face
855  //
856  // in other words, we need to find a point xi so that f(xi)=||F(xi)-p||^2->min
857  // where F(xi) is the mapping. this algorithm is implemented in
858  // MappingQ1<dim,spacedim>::transform_real_to_unit_cell but only for cells,
859  // while we need it for faces here. it's also implemented in somewhat
860  // more generality there using the machinery of the MappingQ1 class
861  // while we really only need it for a specific case here
862  //
863  // in any case, the iteration we use here is a Gauss-Newton's iteration with
864  // xi^{n+1} = xi^n - H(xi^n)^{-1} J(xi^n)
865  // where
866  // J(xi) = (grad F(xi))^T (F(xi)-p)
867  // and
868  // H(xi) = [grad F(xi)]^T [grad F(xi)]
869  // In all this,
870  // F(xi) = sum_v vertex[v] phi_v(xi)
871  // We get the shape functions phi_v from an object of type FE_Q<dim-1>(1)
872 
873  // we start with the point xi=1/2, xi=(1/2,1/2), ...
874  const unsigned int facedim = dim-1;
875 
876  Point<facedim> xi;
877  for (unsigned int i=0; i<facedim; ++i)
878  xi[i] = 1./2;
879 
880  const double eps = 1e-12;
881  Tensor<1,spacedim> grad_F[facedim];
882  unsigned int iteration = 0;
883  while (true)
884  {
885  Point<spacedim> F;
886  for (unsigned int v=0; v<GeometryInfo<facedim>::vertices_per_cell; ++v)
887  F += face->vertex(v) * GeometryInfo<facedim>::d_linear_shape_function(xi, v);
888 
889  for (unsigned int i=0; i<facedim; ++i)
890  {
891  grad_F[i] = 0;
892  for (unsigned int v=0; v<GeometryInfo<facedim>::vertices_per_cell; ++v)
893  grad_F[i] += face->vertex(v) *
895  }
896 
898  for (unsigned int i=0; i<facedim; ++i)
899  for (unsigned int j=0; j<spacedim; ++j)
900  J[i] += grad_F[i][j] * (F-p)[j];
901 
903  for (unsigned int i=0; i<facedim; ++i)
904  for (unsigned int j=0; j<facedim; ++j)
905  for (unsigned int k=0; k<spacedim; ++k)
906  H[i][j] += grad_F[i][k] * grad_F[j][k];
907 
908  const Tensor<1,facedim> delta_xi = -invert(H) * J;
909  xi += delta_xi;
910  ++iteration;
911 
912  Assert (iteration<10,
913  ExcMessage("The Newton iteration to find the reference point "
914  "did not converge in 10 iterations. Do you have a "
915  "deformed cell? (See the glossary for a definition "
916  "of what a deformed cell is. You may want to output "
917  "the vertices of your cell."));
918 
919  if (delta_xi.norm() < eps)
920  break;
921  }
922 
923  // so now we have the reference coordinates xi of the point p.
924  // we then have to compute the normal vector, which we can do
925  // by taking the (normalize) alternating product of all the tangent
926  // vectors given by grad_F
927  return internal::normalized_alternating_product(grad_F);
928 }
929 
930 
931 /* -------------------------- ChartManifold --------------------- */
932 template <int dim, int spacedim, int chartdim>
934  :
935  sub_manifold(periodicity)
936 {}
937 
938 
939 
940 template <int dim, int spacedim, int chartdim>
944  const Point<spacedim> &p2,
945  const double w) const
946 {
947  const std::array<Point<spacedim>, 2> points {{p1, p2}};
948  const std::array<double, 2> weights {{1.-w, w}};
949  return get_new_point(make_array_view(points.begin(), points.end()),
950  make_array_view(weights.begin(), weights.end()));
951 }
952 
953 
954 
955 template <int dim, int spacedim, int chartdim>
958 get_new_point (const ArrayView<const Point<spacedim>> &surrounding_points,
959  const ArrayView<const double> &weights) const
960 {
961  const std::size_t n_points = surrounding_points.size();
962 
963  boost::container::small_vector<Point<chartdim>, 200> chart_points(n_points);
964 
965  for (unsigned int i=0; i<n_points; ++i)
966  chart_points[i] = pull_back(surrounding_points[i]);
967 
968  const Point<chartdim> p_chart = sub_manifold.get_new_point
969  (make_array_view(chart_points.begin(), chart_points.end()),
970  weights);
971 
972  return push_forward(p_chart);
973 }
974 
975 
976 
977 template <int dim, int spacedim, int chartdim>
978 void
980 get_new_points (const ArrayView<const Point<spacedim>> &surrounding_points,
981  const Table<2,double> &weights,
982  ArrayView<Point<spacedim>> new_points) const
983 {
984  Assert(weights.size(0) > 0, ExcEmptyObject());
985  AssertDimension(surrounding_points.size(), weights.size(1));
986 
987  const std::size_t n_points = surrounding_points.size();
988 
989  boost::container::small_vector<Point<chartdim>, 200> chart_points(n_points);
990  for (std::size_t i=0; i<n_points; ++i)
991  chart_points[i] = pull_back(surrounding_points[i]);
992 
993  boost::container::small_vector<Point<chartdim>, 200> new_points_on_chart(weights.size(0));
994  sub_manifold.get_new_points(make_array_view(chart_points.begin(),
995  chart_points.end()),
996  weights,
997  make_array_view(new_points_on_chart.begin(),
998  new_points_on_chart.end()));
999 
1000  for (std::size_t row=0; row<weights.size(0); ++row)
1001  new_points[row] = push_forward(new_points_on_chart[row]);
1002 }
1003 
1004 
1005 
1006 template <int dim, int spacedim, int chartdim>
1010 {
1011  // function must be implemented in a derived class to be usable,
1012  // as discussed in this function's documentation
1013  Assert (false, ExcPureFunctionCalled());
1015 }
1016 
1017 
1018 
1019 template <int dim, int spacedim, int chartdim>
1023  const Point<spacedim> &x2) const
1024 {
1025  const DerivativeForm<1,chartdim,spacedim> F_prime = push_forward_gradient(pull_back(x1));
1026 
1027  // ensure that the chart is not singular by asserting that its
1028  // derivative has a positive determinant. we need to make this
1029  // comparison relative to the size of the derivative. since the
1030  // determinant is the product of chartdim factors, take the
1031  // chartdim-th root of it in comparing against the size of the
1032  // derivative
1033  Assert (std::pow(std::abs(F_prime.determinant()), 1./chartdim) >= 1e-12 * F_prime.norm(),
1034  ExcMessage("The derivative of a chart function must not be singular."));
1035 
1036  const Tensor<1,chartdim> delta = sub_manifold.get_tangent_vector(pull_back(x1),
1037  pull_back(x2));
1038 
1039  Tensor<1,spacedim> result;
1040  for (unsigned int i=0; i<spacedim; ++i)
1041  result[i] += F_prime[i] * delta;
1042 
1043  return result;
1044 }
1045 
1046 
1047 
1048 template <int dim, int spacedim, int chartdim>
1049 const Tensor<1, chartdim> &
1051 {
1052  return sub_manifold.get_periodicity();
1053 }
1054 
1055 // explicit instantiations
1056 #include "manifold.inst"
1057 
1058 DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcPureFunctionCalled()
static const unsigned int invalid_unsigned_int
Definition: types.h:173
FlatManifold(const Tensor< 1, spacedim > &periodicity=Tensor< 1, spacedim >(), const double tolerance=1e-10)
Definition: manifold.cc:507
std::pair< std::array< Point< MeshIteratorType::AccessorType::space_dimension >, n_default_points_per_cell< MeshIteratorType >)>, std::array< double, n_default_points_per_cell< MeshIteratorType >)> > get_default_points_and_weights(const MeshIteratorType &iterator, const bool with_interpolation=false)
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const override
Definition: manifold.cc:841
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
iterator begin() const
Definition: array_view.h:378
SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &t)
const Tensor< 1, spacedim > & get_periodicity() const
Definition: manifold.cc:669
virtual Point< spacedim > get_new_point_on_hex(const typename Triangulation< dim, spacedim >::hex_iterator &hex) const
Definition: manifold.cc:440
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim >> &surrounding_points, const ArrayView< const double > &weights) const
Definition: manifold.cc:63
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1273
static Tensor< 1, dim > d_linear_shape_function_gradient(const Point< dim > &xi, const unsigned int i)
Number determinant() const
ArrayView< typename std::remove_reference< typename std::iterator_traits< Iterator >::reference >::type > make_array_view(const Iterator begin, const Iterator end)
Definition: array_view.h:490
static ::ExceptionBase & ExcMessage(std::string arg1)
virtual Point< spacedim > get_new_point_on_line(const typename Triangulation< dim, spacedim >::line_iterator &line) const
Definition: manifold.cc:306
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
virtual Tensor< 1, spacedim > get_tangent_vector(const Point< spacedim > &x1, const Point< spacedim > &x2) const
Definition: manifold.cc:464
virtual DerivativeForm< 1, chartdim, spacedim > push_forward_gradient(const Point< chartdim > &chart_point) const
Definition: manifold.cc:1009
virtual Point< spacedim > project_to_manifold(const ArrayView< const Point< spacedim >> &surrounding_points, const Point< spacedim > &candidate) const
Definition: manifold.cc:37
#define Assert(cond, exc)
Definition: exceptions.h:1142
iterator end() const
Definition: array_view.h:388
numbers::NumberTraits< Number >::real_type norm_square() const
Definition: tensor.h:1283
const Tensor< 1, chartdim > & get_periodicity() const
Definition: manifold.cc:1050
virtual Point< spacedim > project_to_manifold(const ArrayView< const Point< spacedim >> &points, const Point< spacedim > &candidate) const override
Definition: manifold.cc:659
numbers::NumberTraits< Number >::real_type norm() const
std::size_t size() const
Definition: array_view.h:370
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
Definition: manifold.cc:518
virtual Point< spacedim > get_intermediate_point(const Point< spacedim > &p1, const Point< spacedim > &p2, const double w) const
Definition: manifold.cc:49
numbers::NumberTraits< Number >::real_type distance(const Point< dim, Number > &p) const
Tensor< 1, dim, Number > cross_product_3d(const Tensor< 1, dim, Number > &src1, const Tensor< 1, dim, Number > &src2)
Definition: tensor.h:1971
virtual void get_new_points(const ArrayView< const Point< spacedim >> &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim >> new_points) const override
Definition: manifold.cc:980
virtual Tensor< 1, spacedim > get_tangent_vector(const Point< spacedim > &x1, const Point< spacedim > &x2) const override
Definition: manifold.cc:1022
double norm(const FEValuesBase< dim > &fe, const VectorSlice< const std::vector< std::vector< Tensor< 1, dim > > > > &Du)
Definition: divergence.h:534
virtual void get_new_points(const ArrayView< const Point< spacedim >> &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim >> new_points) const
Definition: manifold.cc:114
size_type size(const unsigned int i) const
static double d_linear_shape_function(const Point< dim > &xi, const unsigned int i)
Definition: mpi.h:53
virtual Tensor< 1, spacedim > get_tangent_vector(const Point< spacedim > &x1, const Point< spacedim > &x2) const override
Definition: manifold.cc:678
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim >> &surrounding_points, const ArrayView< const double > &weights) const override
Definition: manifold.cc:958
virtual Point< spacedim > get_new_point_on_quad(const typename Triangulation< dim, spacedim >::quad_iterator &quad) const
Definition: manifold.cc:320
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim >> &surrounding_points, const ArrayView< const double > &weights) const override
Definition: manifold.cc:528
static ::ExceptionBase & ExcEmptyObject()
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, typename Manifold< dim, spacedim >::FaceVertexNormals &face_vertex_normals) const override
static ::ExceptionBase & ExcNotImplemented()
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const
Definition: manifold.cc:226
virtual void get_new_points(const ArrayView< const Point< spacedim >> &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim >> new_points) const override
Definition: manifold.cc:583
ChartManifold(const Tensor< 1, chartdim > &periodicity=Tensor< 1, chartdim >())
Definition: manifold.cc:933
Point< spacedim > get_new_point_on_face(const typename Triangulation< dim, spacedim >::face_iterator &face) const
Definition: manifold.cc:334
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, FaceVertexNormals &face_vertex_normals) const
Definition: manifold.cc:291
virtual Point< spacedim > get_intermediate_point(const Point< spacedim > &p1, const Point< spacedim > &p2, const double w) const override
Definition: manifold.cc:943
static ::ExceptionBase & ExcInternalError()
Point< spacedim > get_new_point_on_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
Definition: manifold.cc:354