Reference documentation for deal.II version 9.0.0
tria_boundary.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/std_cxx14/memory.h>
18 #include <deal.II/grid/tria_boundary.h>
19 #include <deal.II/grid/tria.h>
20 #include <deal.II/grid/tria_iterator.h>
21 #include <deal.II/grid/tria_accessor.h>
22 #include <deal.II/fe/fe_q.h>
23 #include <cmath>
24 
25 DEAL_II_NAMESPACE_OPEN
26 
27 
28 
29 /* -------------------------- Boundary --------------------- */
30 
31 
32 template <int dim, int spacedim>
33 std::unique_ptr<Manifold<dim, spacedim> >
35 {
37  return std::unique_ptr<Manifold<dim,spacedim> >();
38 }
39 
40 
41 
42 template <int dim, int spacedim>
43 void
45 get_intermediate_points_on_line (const typename Triangulation<dim, spacedim>::line_iterator &,
46  std::vector<Point<spacedim> > &) const
47 {
48  Assert (false, ExcPureFunctionCalled());
49 }
50 
51 
52 
53 template <int dim, int spacedim>
54 void
56 get_intermediate_points_on_quad (const typename Triangulation<dim, spacedim>::quad_iterator &,
57  std::vector<Point<spacedim> > &) const
58 {
59  Assert (false, ExcPureFunctionCalled());
60 }
61 
62 
63 template <int dim, int spacedim>
64 void
67  std::vector<Point<spacedim> > &points) const
68 {
69  Assert (dim>1, ExcImpossibleInDim(dim));
70 
71  switch (dim)
72  {
73  case 2:
74  get_intermediate_points_on_line (face, points);
75  break;
76  case 3:
77  get_intermediate_points_on_quad (face, points);
78  break;
79  default:
80  Assert (false, ExcNotImplemented());
81  }
82 }
83 
84 
85 template <>
86 void
89  std::vector<Point<1> > &) const
90 {
91  Assert (false, ExcImpossibleInDim(1));
92 }
93 
94 
95 template <>
96 void
99  std::vector<Point<2> > &) const
100 {
101  Assert (false, ExcImpossibleInDim(1));
102 }
103 
104 
105 template <>
106 void
109  std::vector<Point<3> > &) const
110 {
111  Assert (false, ExcImpossibleInDim(1));
112 }
113 
114 
115 template <int dim, int spacedim>
118 project_to_surface (const typename Triangulation<dim, spacedim>::line_iterator &,
119  const Point<spacedim> &trial_point) const
120 {
121  if (spacedim <= 1)
122  return trial_point;
123  else
124  {
125  Assert (false, ExcPureFunctionCalled());
126  return Point<spacedim>();
127  }
128 }
129 
130 
131 
132 template <int dim, int spacedim>
135 project_to_surface (const typename Triangulation<dim, spacedim>::quad_iterator &,
136  const Point<spacedim> &trial_point) const
137 {
138  if (spacedim <= 2)
139  return trial_point;
140  else
141  {
142  Assert (false, ExcPureFunctionCalled());
143  return Point<spacedim>();
144  }
145 }
146 
147 
148 
149 template <int dim, int spacedim>
152 project_to_surface (const typename Triangulation<dim, spacedim>::hex_iterator &,
153  const Point<spacedim> &trial_point) const
154 {
155  if (spacedim <= 3)
156  return trial_point;
157  else
158  {
159  Assert (false, ExcPureFunctionCalled());
160  return Point<spacedim>();
161  }
162 }
163 
164 
165 
166 template <int dim, int spacedim>
167 const std::vector<Point<1> > &
169 get_line_support_points (const unsigned int n_intermediate_points) const
170 {
171  if (points.size() <= n_intermediate_points ||
172  points[n_intermediate_points].get() == nullptr)
173  {
174  Threads::Mutex::ScopedLock lock(mutex);
175  if (points.size() <= n_intermediate_points)
176  points.resize(n_intermediate_points+1);
177 
178  // another thread might have created points in the meantime
179  if (points[n_intermediate_points].get() == nullptr)
180  points[n_intermediate_points] = std_cxx14::make_unique<QGaussLobatto<1> >
181  (n_intermediate_points+2);
182  }
183  return points[n_intermediate_points]->get_points();
184 }
185 
186 
187 
188 
189 /* -------------------------- StraightBoundary --------------------- */
190 
191 // At least clang < 3.9.0 complains if we move this definition to its
192 // declaration when a 'const StraightBoundary' object is built.
193 template <int dim, int spacedim>
195 
196 
197 
198 template <int dim, int spacedim>
201 get_new_point_on_line (const typename Triangulation<dim, spacedim>::line_iterator &line) const
202 {
203  return (line->vertex(0) + line->vertex(1)) / 2;
204 }
205 
206 
207 template <int dim, int spacedim>
208 std::unique_ptr<Manifold<dim, spacedim> >
210 {
211  return std_cxx14::make_unique<StraightBoundary<dim,spacedim> >();
212 }
213 
214 
215 namespace
216 {
217  // compute the new midpoint of a quad --
218  // either of a 2d cell on a manifold in 3d
219  // or of a face of a 3d triangulation in 3d
220  template <int dim>
221  Point<3>
222  compute_new_point_on_quad (const typename Triangulation<dim, 3>::quad_iterator &quad)
223  {
224  // generate a new point in the middle of
225  // the face based on the points on the
226  // edges and the vertices.
227  //
228  // there is a pathological situation when
229  // this face is on a straight boundary, but
230  // one of its edges and the face behind it
231  // are not; if that face is refined first,
232  // the new point in the middle of that edge
233  // may not be at the same position as
234  // quad->line(.)->center() would have been,
235  // but would have been moved to the
236  // non-straight boundary. We cater to that
237  // situation by using existing edge
238  // midpoints if available, or center() if
239  // not
240  //
241  // note that this situation can not happen
242  // during mesh refinement, as there the
243  // edges are refined first and only then
244  // the face. thus, the check whether a line
245  // has children does not lead to the
246  // situation where the new face midpoints
247  // have different positions depending on
248  // which of the two cells is refined first.
249  //
250  // the situation where the edges aren't
251  // refined happens when a higher order
252  // MappingQ requests the midpoint of a
253  // face, though, and it is for these cases
254  // that we need to have the check available
255  //
256  // note that the factor of 1/8 for each
257  // of the 8 surrounding points isn't
258  // chosen arbitrarily. rather, we may ask
259  // where the harmonic map would place the
260  // point (0,0) if we map the square
261  // [-1,1]^2 onto the domain that is
262  // described using the 4 vertices and 4
263  // edge point points of this quad. we can
264  // then discretize the harmonic map using
265  // four cells and Q1 elements on each of
266  // the quadrants of the square [-1,1]^2
267  // and see where the midpoint would land
268  // (this is the procedure we choose, for
269  // example, in
270  // GridGenerator::laplace_solve) and it
271  // turns out that it will land at the
272  // mean of the 8 surrounding
273  // points. whether a discretization of
274  // the harmonic map with only 4 cells is
275  // adequate is a different question
276  // altogether, of course.
277  return (quad->vertex(0) + quad->vertex(1) +
278  quad->vertex(2) + quad->vertex(3) +
279  (quad->line(0)->has_children() ?
280  quad->line(0)->child(0)->vertex(1) :
281  quad->line(0)->center()) +
282  (quad->line(1)->has_children() ?
283  quad->line(1)->child(0)->vertex(1) :
284  quad->line(1)->center()) +
285  (quad->line(2)->has_children() ?
286  quad->line(2)->child(0)->vertex(1) :
287  quad->line(2)->center()) +
288  (quad->line(3)->has_children() ?
289  quad->line(3)->child(0)->vertex(1) :
290  quad->line(3)->center()) ) / 8;
291  }
292 }
293 
294 
295 
296 template <int dim, int spacedim>
299 get_new_point_on_quad (const typename Triangulation<dim, spacedim>::quad_iterator &quad) const
300 {
302 }
303 
304 
305 template <>
306 Point<3>
308 get_new_point_on_quad (const Triangulation<2,3>::quad_iterator &quad) const
309 {
310  return compute_new_point_on_quad<2> (quad);
311 }
312 
313 
314 
315 template <>
316 Point<3>
318 get_new_point_on_quad (const Triangulation<3>::quad_iterator &quad) const
319 {
320  return compute_new_point_on_quad<3> (quad);
321 }
322 
323 
324 
325 template <int dim, int spacedim>
326 void
328 get_intermediate_points_on_line (const typename Triangulation<dim, spacedim>::line_iterator &line,
329  std::vector<Point<spacedim> > &points) const
330 {
331  const unsigned int n=points.size();
332  Assert(n>0, ExcInternalError());
333 
334  // Use interior points of QGaussLobatto quadrature formula support points
335  // for consistency with MappingQ
336  const std::vector<Point<1> > &line_points = this->get_line_support_points(n);
337 
338  const Point<spacedim> vertices[2] = { line->vertex(0),
339  line->vertex(1)
340  };
341 
342  for (unsigned int i=0; i<n; ++i)
343  {
344  const double x = line_points[1+i][0];
345  points[i] = (1-x)*vertices[0] + x*vertices[1];
346  }
347 }
348 
349 
350 
351 
352 template <int dim, int spacedim>
353 void
355 get_intermediate_points_on_quad (const typename Triangulation<dim, spacedim>::quad_iterator &,
356  std::vector<Point<spacedim> > &) const
357 {
358  Assert(false, ExcImpossibleInDim(dim));
359 }
360 
361 
362 
363 template <>
364 void
366 get_intermediate_points_on_quad (const Triangulation<3>::quad_iterator &quad,
367  std::vector<Point<3> > &points) const
368 {
369  const unsigned int spacedim = 3;
370 
371  const unsigned int n=points.size(),
372  m=static_cast<unsigned int>(std::sqrt(static_cast<double>(n)));
373  // is n a square number
374  Assert(m*m==n, ExcInternalError());
375 
376  const std::vector<Point<1> > &line_points = this->get_line_support_points(m);
377 
378  const Point<spacedim> vertices[4] = { quad->vertex(0),
379  quad->vertex(1),
380  quad->vertex(2),
381  quad->vertex(3)
382  };
383 
384  for (unsigned int i=0; i<m; ++i)
385  {
386  const double y=line_points[1+i][0];
387  for (unsigned int j=0; j<m; ++j)
388  {
389  const double x=line_points[1+j][0];
390  points[i*m+j]=((1-x) * vertices[0] +
391  x * vertices[1]) * (1-y) +
392  ((1-x) * vertices[2] +
393  x * vertices[3]) * y;
394  }
395  }
396 }
397 
398 
399 
400 template <>
401 void
403 get_intermediate_points_on_quad (const Triangulation<2,3>::quad_iterator &quad,
404  std::vector<Point<3> > &points) const
405 {
406  const unsigned int spacedim = 3;
407 
408  const unsigned int n=points.size(),
409  m=static_cast<unsigned int>(std::sqrt(static_cast<double>(n)));
410  // is n a square number
411  Assert(m*m==n, ExcInternalError());
412 
413  const std::vector<Point<1> > &line_points = this->get_line_support_points(m);
414 
415  const Point<spacedim> vertices[4] = { quad->vertex(0),
416  quad->vertex(1),
417  quad->vertex(2),
418  quad->vertex(3)
419  };
420 
421  for (unsigned int i=0; i<m; ++i)
422  {
423  const double y=line_points[1+i][0];
424  for (unsigned int j=0; j<m; ++j)
425  {
426  const double x=line_points[1+j][0];
427  points[i*m+j]=((1-x) * vertices[0] +
428  x * vertices[1]) * (1-y) +
429  ((1-x) * vertices[2] +
430  x * vertices[3]) * y;
431  }
432  }
433 }
434 
435 
436 
437 template <int dim, int spacedim>
441  const Point<spacedim> &p) const
442 {
444 }
445 
446 
447 
448 template <int dim, int spacedim>
449 void
452  typename Boundary<dim,spacedim>::FaceVertexNormals &face_vertex_normals) const
453 {
454  FlatManifold<dim, spacedim>::get_normals_at_vertices(face, face_vertex_normals);
455 }
456 
457 
458 
459 template <int dim, int spacedim>
462 project_to_surface (const typename Triangulation<dim, spacedim>::line_iterator &line,
463  const Point<spacedim> &trial_point) const
464 {
465  if (spacedim <= 1)
466  return trial_point;
467  else
468  {
469  // find the point that lies on
470  // the line p1--p2. the
471  // formulas pan out to
472  // something rather simple
473  // because the mapping to the
474  // line is linear
475  const Point<spacedim> p1 = line->vertex(0),
476  p2 = line->vertex(1);
477  const double s = (trial_point-p1)*(p2-p1) / ((p2-p1)*(p2-p1));
478  return p1 + s*(p2-p1);
479  }
480 }
481 
482 
483 
484 namespace internal
485 {
486  template <typename Iterator, int spacedim, int dim>
488  compute_projection (const Iterator &object,
489  const Point<spacedim> &y,
490  std::integral_constant<int, dim>)
491  {
492  // let's look at this for
493  // simplicity for a quad (dim==2)
494  // in a space with spacedim>2:
495 
496  // all points on the surface are given by
497  // x(\xi) = sum_i v_i phi_x(\xi)
498  // where v_i are the vertices of the quad,
499  // and \xi=(\xi_1,\xi_2) are the reference
500  // coordinates of the quad. so what we are
501  // trying to do is find a point x on
502  // the surface that is closest to the point
503  // y. there are different ways
504  // to solve this problem, but in the end
505  // it's a nonlinear problem and we have to
506  // find reference coordinates \xi so that
507  // J(\xi) = 1/2 || x(\xi)-y ||^2
508  // is minimal. x(\xi) is a function that
509  // is dim-linear in \xi, so J(\xi) is
510  // a polynomial of degree 2*dim that
511  // we'd like to minimize. unless dim==1,
512  // we'll have to use a Newton
513  // method to find the
514  // answer. This leads to the
515  // following formulation of
516  // Newton steps:
517  //
518  // Given \xi_k, find \delta\xi_k so that
519  // H_k \delta\xi_k = - F_k
520  // where H_k is an approximation to the
521  // second derivatives of J at \xi_k, and
522  // F_k is the first derivative of J.
523  // We'll iterate this a number of times
524  // until the right hand side is small
525  // enough. As a stopping criterion, we
526  // terminate if ||\delta\xi||<eps.
527  //
528  // As for the Hessian, the best choice
529  // would be
530  // H_k = J''(\xi_k)
531  // but we'll opt for the simpler
532  // Gauss-Newton form
533  // H_k = A^T A
534  // i.e.
535  // (H_k)_{nm} = \sum_{i,j} v_i*v_j *
536  // \partial_n phi_i *
537  // \partial_m phi_j
538  // we start at xi=(0.5,0.5).
539  Point<dim> xi;
540  for (unsigned int d=0; d<dim; ++d)
541  xi[d] = 0.5;
542 
543  Point<spacedim> x_k;
544  for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i)
545  x_k += object->vertex(i) *
547 
548  do
549  {
550  Tensor<1,dim> F_k;
551  for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i)
552  F_k += (x_k-y)*object->vertex(i) *
554 
555  Tensor<2,dim> H_k;
556  for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i)
557  for (unsigned int j=0; j<GeometryInfo<dim>::vertices_per_cell; ++j)
558  {
562  H_k += (object->vertex(i) * object->vertex(j)) * tmp;
563  }
564 
565  const Tensor<1,dim> delta_xi = - invert(H_k) * F_k;
566  xi += delta_xi;
567 
568  x_k = Point<spacedim>();
569  for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i)
570  x_k += object->vertex(i) *
572 
573  if (delta_xi.norm() < 1e-5)
574  break;
575  }
576  while (true);
577 
578  return x_k;
579  }
580 
581 
582  // specialization for a quad in 1d
583  template <typename Iterator>
584  Point<1>
585  compute_projection (const Iterator &,
586  const Point<1> &y,
587  /* it's a quad: */std::integral_constant<int, 2>)
588  {
589  return y;
590  }
591 
592  // specialization for a quad in 2d
593  template <typename Iterator>
594  Point<2>
595  compute_projection (const Iterator &,
596  const Point<2> &y,
597  /* it's a quad: */std::integral_constant<int, 2>)
598  {
599  return y;
600  }
601 }
602 
603 
604 
605 
606 
607 template <>
608 Point<3>
610 project_to_surface (const Triangulation<1, 3>::quad_iterator &,
611  const Point<3> &y) const
612 {
613  return y;
614 }
615 
616 //TODO[SP]: This is just a horrible way out to make it compile in codim 2.
617 template <int dim, int spacedim>
620 project_to_surface (const typename Triangulation<dim, spacedim>::quad_iterator &quad,
621  const Point<spacedim> &y) const
622 {
623  if (spacedim <= 2)
624  return y;
625  else
626  return internal::compute_projection (quad, y,
627  /* it's a quad */std::integral_constant<int, 2>());
628 }
629 
630 
631 
632 template <int dim, int spacedim>
635 project_to_surface (const typename Triangulation<dim, spacedim>::hex_iterator &,
636  const Point<spacedim> &trial_point) const
637 {
638  if (spacedim <= 3)
639  return trial_point;
640  else
641  {
642  // we can presumably call the
643  // same function as above (it's
644  // written in a generic way)
645  // but someone needs to check
646  // whether that actually yields
647  // the correct result
648  Assert (false, ExcNotImplemented());
649  return Point<spacedim>();
650  }
651 }
652 
653 
654 
655 // explicit instantiations
656 #include "tria_boundary.inst"
657 
658 DEAL_II_NAMESPACE_CLOSE
const std::vector< Point< 1 > > & get_line_support_points(const unsigned int n_intermediate_points) const
static ::ExceptionBase & ExcPureFunctionCalled()
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const override
Definition: manifold.cc:841
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
virtual void get_intermediate_points_on_line(const typename Triangulation< dim, spacedim >::line_iterator &line, std::vector< Point< spacedim > > &points) const
SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1273
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, typename Boundary< dim, spacedim >::FaceVertexNormals &face_vertex_normals) const override
static Tensor< 1, dim > d_linear_shape_function_gradient(const Point< dim > &xi, const unsigned int i)
SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
virtual Point< spacedim > get_new_point_on_line(const typename Triangulation< dim, spacedim >::line_iterator &line) const override
virtual void get_intermediate_points_on_quad(const typename Triangulation< dim, spacedim >::quad_iterator &quad, std::vector< Point< spacedim > > &points) const
Definition: tria.h:45
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1142
virtual void get_intermediate_points_on_quad(const typename Triangulation< dim, spacedim >::quad_iterator &quad, std::vector< Point< spacedim > > &points) const override
void get_intermediate_points_on_face(const typename Triangulation< dim, spacedim >::face_iterator &face, std::vector< Point< spacedim > > &points) const
static double d_linear_shape_function(const Point< dim > &xi, const unsigned int i)
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
virtual Point< spacedim > get_new_point_on_quad(const typename Triangulation< dim, spacedim >::quad_iterator &quad) const
Definition: manifold.cc:320
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, typename Manifold< dim, spacedim >::FaceVertexNormals &face_vertex_normals) const override
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const override
static ::ExceptionBase & ExcNotImplemented()
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
virtual void get_intermediate_points_on_line(const typename Triangulation< dim, spacedim >::line_iterator &line, std::vector< Point< spacedim > > &points) const override
virtual Point< spacedim > get_new_point_on_quad(const typename Triangulation< dim, spacedim >::quad_iterator &quad) const override
virtual Point< spacedim > project_to_surface(const typename Triangulation< dim, spacedim >::line_iterator &line, const Point< spacedim > &candidate) const
static ::ExceptionBase & ExcInternalError()
virtual Point< spacedim > project_to_surface(const typename Triangulation< dim, spacedim >::line_iterator &line, const Point< spacedim > &candidate) const override