Reference documentation for deal.II version 8.5.1
manifold_lib.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2013 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/grid/tria.h>
17 #include <deal.II/grid/tria_iterator.h>
18 #include <deal.II/grid/tria_accessor.h>
19 #include <deal.II/grid/manifold_lib.h>
20 #include <deal.II/base/tensor.h>
21 #include <deal.II/lac/vector.h>
22 #include <cmath>
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 // ============================================================
27 // PolarManifold
28 // ============================================================
29 
30 template <int dim, int spacedim>
32  ChartManifold<dim,spacedim,spacedim>(PolarManifold<dim,spacedim>::get_periodicity()),
33  center(center)
34 {}
35 
36 template <int dim, int spacedim>
39 {
40  Tensor<1,spacedim> periodicity;
41  // In two dimensions, theta is periodic.
42  // In three dimensions things are a little more complicated, since the only variable
43  // that is truly periodic is phi, while theta should be bounded between
44  // 0 and pi. There is currently no way to enforce this, so here we only fix
45  // periodicity for the last variable, corresponding to theta in 2d and phi in 3d.
46  periodicity[spacedim-1] = 2*numbers::PI;
47  return periodicity;
48 }
49 
50 template <int dim, int spacedim>
53 {
54  Assert(spherical_point[0] >=0.0,
55  ExcMessage("Negative radius for given point."));
56  const double rho = spherical_point[0];
57  const double theta = spherical_point[1];
58 
60  if (rho > 1e-10)
61  switch (spacedim)
62  {
63  case 2:
64  p[0] = rho*cos(theta);
65  p[1] = rho*sin(theta);
66  break;
67  case 3:
68  {
69  const double phi= spherical_point[2];
70  p[0] = rho*sin(theta)*cos(phi);
71  p[1] = rho*sin(theta)*sin(phi);
72  p[2] = rho*cos(theta);
73  break;
74  }
75  default:
76  Assert(false, ExcNotImplemented());
77  }
78  return p+center;
79 }
80 
81 template <int dim, int spacedim>
84 {
85  const Tensor<1,spacedim> R = space_point-center;
86  const double rho = R.norm();
87 
89  p[0] = rho;
90 
91  switch (spacedim)
92  {
93  case 2:
94  {
95  p[1] = atan2(R[1],R[0]);
96  if (p[1] < 0)
97  p[1] += 2*numbers::PI;
98  break;
99  }
100 
101  case 3:
102  {
103  const double z = R[2];
104  p[2] = atan2(R[1],R[0]); // phi
105  if (p[2] < 0)
106  p[2] += 2*numbers::PI; // phi is periodic
107  p[1] = atan2(sqrt(R[0]*R[0]+R[1]*R[1]),z); // theta
108  break;
109  }
110 
111  default:
112  Assert(false, ExcNotImplemented());
113  }
114  return p;
115 }
116 
117 template <int dim, int spacedim>
120 {
121  Assert(spherical_point[0] >= 0.0,
122  ExcMessage("Negative radius for given point."));
123  const double rho = spherical_point[0];
124  const double theta = spherical_point[1];
125 
127  if (rho > 1e-10)
128  switch (spacedim)
129  {
130  case 2:
131  {
132  DX[0][0] = cos(theta);
133  DX[0][1] = -rho*sin(theta);
134  DX[1][0] = sin(theta);
135  DX[1][1] = rho*cos(theta);
136  break;
137  }
138 
139  case 3:
140  {
141  const double phi= spherical_point[2];
142  DX[0][0] = sin(theta)*cos(phi);
143  DX[0][1] = rho*cos(theta)*cos(phi);
144  DX[0][2] = -rho*sin(theta)*sin(phi);
145 
146  DX[1][0] = sin(theta)*sin(phi);
147  DX[1][1] = rho*cos(theta)*sin(phi);
148  DX[1][2] = rho*sin(theta)*cos(phi);
149 
150  DX[2][0] = cos(theta);
151  DX[2][1] = -rho*sin(theta);
152  DX[2][2] = 0;
153  break;
154  }
155 
156  default:
157  Assert(false, ExcNotImplemented());
158  }
159  return DX;
160 }
161 
162 // ============================================================
163 // SphericalManifold
164 // ============================================================
165 
166 template <int dim, int spacedim>
168  center(center)
169 {}
170 
171 template <int dim, int spacedim>
175  const Point<spacedim> &p2,
176  const double w) const
177 {
178  Assert(w >=0.0 && w <= 1.0,
179  ExcMessage("w should be in the range [0.0,1.0]."));
180 
181  const double tol = 1e-10;
182 
183  if ( p1.distance(p2) < tol || w < tol)
184  return p1;
185  else if (w > 1.0 - tol)
186  return p2;
187 
188  // If the points are one dimensional then there is no need for anything but
189  // a linear combination.
190  if (spacedim == 1)
191  return Point<spacedim>(w*p2 + (1-w)*p1);
192 
193  const Tensor<1,spacedim> v1 = p1 - center;
194  const Tensor<1,spacedim> v2 = p2 - center;
195  const double r1 = v1.norm();
196  const double r2 = v2.norm();
197 
198  Assert(r1 > tol && r2 > tol,
199  ExcMessage("p1 and p2 cannot coincide with the center."));
200 
201  const Tensor<1,spacedim> e1 = v1/r1;
202  const Tensor<1,spacedim> e2 = v2/r2;
203 
204  if ((e1 - e2).norm_square() < tol*tol)
205  return Point<spacedim>(center + w*v2 + (1-w)*v1);
206 
207  // Find the angle gamma described by v1 and v2:
208  const double gamma = std::acos(e1*e2);
209 
210  // Find the angle sigma that corresponds to arclength equal to w
211  const double sigma = w * gamma;
212 
213  // Normal to v1 in the plane described by v1,v2,and the origin.
214  // Since p1 and p2 do not coincide n is not zero and well defined.
215  Tensor<1,spacedim> n = v2 - (v2*e1)*e1;
216  Assert( n.norm() > 0,
217  ExcInternalError("n should be different from the null vector."
218  "Probably this means v1==v2 or v2==0."));
219 
220  n /= n.norm();
221 
222  // Find the point Q along O,v1 such that
223  // P1,V,P2 has measure sigma.
224  const Tensor<1,spacedim> P = std::cos(sigma) * e1 + std::sin(sigma) * n;
225 
226  // Project this point on the manifold.
227  return Point<spacedim>(center + (w*r2+(1.0-w)*r1)*P);
228 }
229 
230 template <int dim, int spacedim>
234  const Point<spacedim> &p2) const
235 {
236  Assert(p1 != p2,
237  ExcMessage("p1 and p2 should not concide."));
238 
239  const double r1 = (p1 - center).norm();
240  const double r2 = (p2 - center).norm();
241 
242  Assert(r1 > 1e-10,
243  ExcMessage("p1 cannot coincide with the center."));
244 
245  Assert(r2 > 1e-10,
246  ExcMessage("p2 cannot coincide with the center."));
247 
248  const Tensor<1,spacedim> e1 = (p1 - center)/r1;
249  const Tensor<1,spacedim> e2 = (p2 - center)/r2;
250 
251  Assert(e1*e2 + 1.0 > 1e-10,
252  ExcMessage("p1 and p2 cannot lie on the same diameter and be opposite "
253  "respect to the center."));
254 
255  // Tangent vector to the unit sphere along the geodesic given by e1 and e2.
256  Tensor<1,spacedim> tg = (e2-(e2*e1)*e1);
257  tg = tg / tg.norm();
258 
259  const double gamma = std::acos(e1*e2);
260 
261  return (r1-r2)*e1 + r1*gamma*tg;
262 }
263 
264 template <int dim, int spacedim>
267 get_new_point (const Quadrature<spacedim> &quad) const
268 {
269  return get_new_point(quad.get_points(),quad.get_weights());
270 }
271 
272 template <int dim, int spacedim>
275 get_new_point (const std::vector<Point<spacedim> > &vertices,
276  const std::vector<double> &weights) const
277 {
278  const unsigned int n_points = vertices.size();
279 
280  double rho = 0.0;
281  Tensor<1,spacedim> candidate;
282  for (unsigned int i = 0; i<n_points; i++)
283  {
284  const Tensor<1,spacedim> direction (vertices[i]-center);
285  rho += direction.norm()*weights[i];
286  candidate += direction*weights[i];
287  }
288 
289  // Unit norm direction.
290  candidate /= candidate.norm();
291 
292  return center+rho*candidate;
293 }
294 
295 // ============================================================
296 // CylindricalManifold
297 // ============================================================
298 
299 template <int dim, int spacedim>
301  const double tolerance) :
302  direction (Point<spacedim>::unit_vector(axis)),
303  point_on_axis (Point<spacedim>()),
304  tolerance(tolerance)
305 {
306  Assert(spacedim > 1, ExcImpossibleInDim(1));
307 }
308 
309 
310 template <int dim, int spacedim>
312  const Point<spacedim> &point_on_axis,
313  const double tolerance) :
314  direction (direction),
315  point_on_axis (point_on_axis),
316  tolerance(tolerance)
317 {
318  Assert(spacedim > 2, ExcImpossibleInDim(spacedim));
319 }
320 
321 
322 
323 
324 template <int dim, int spacedim>
328 {
329  return get_new_point(quad.get_points(),quad.get_weights());
330 }
331 
332 
333 
334 template <int dim, int spacedim>
337 get_new_point (const std::vector<Point<spacedim> > &surrounding_points,
338  const std::vector<double> &weights) const
339 {
340  // compute a proposed new point
341  const Point<spacedim> middle = flat_manifold.get_new_point(surrounding_points,
342  weights);
343 
344  double radius = 0;
345  Tensor<1,spacedim> on_plane;
346 
347  for (unsigned int i=0; i<surrounding_points.size(); ++i)
348  {
349  on_plane = surrounding_points[i]-point_on_axis;
350  on_plane = on_plane - (on_plane*direction) * direction;
351  radius += weights[i]*on_plane.norm();
352  }
353 
354  // we then have to project this point out to the given radius from
355  // the axis. to this end, we have to take into account the offset
356  // point_on_axis and the direction of the axis
357  const Tensor<1,spacedim> vector_from_axis = (middle-point_on_axis) -
358  ((middle-point_on_axis) * direction) * direction;
359 
360  // scale it to the desired length and put everything back together,
361  // unless we have a point on the axis
362  if (vector_from_axis.norm() <= tolerance * middle.norm())
363  return middle;
364 
365  else
366  return Point<spacedim>((vector_from_axis / vector_from_axis.norm() * radius +
367  ((middle-point_on_axis) * direction) * direction +
368  point_on_axis));
369 }
370 
371 
372 // ============================================================
373 // FunctionChartManifold
374 // ============================================================
375 template <int dim, int spacedim, int chartdim>
377 (const Function<chartdim> &push_forward_function,
378  const Function<spacedim> &pull_back_function,
379  const Tensor<1,chartdim> &periodicity,
380  const double tolerance):
382  push_forward_function(&push_forward_function),
383  pull_back_function(&pull_back_function),
384  tolerance(tolerance),
385  owns_pointers(false)
386 {
387  AssertDimension(push_forward_function.n_components, spacedim);
388  AssertDimension(pull_back_function.n_components, chartdim);
389 }
390 
391 template <int dim, int spacedim, int chartdim>
393 (const std::string push_forward_expression,
394  const std::string pull_back_expression,
395  const Tensor<1,chartdim> &periodicity,
396  const typename FunctionParser<spacedim>::ConstMap const_map,
397  const std::string chart_vars,
398  const std::string space_vars,
399  const double tolerance,
400  const double h) :
402  const_map(const_map),
403  tolerance(tolerance),
404  owns_pointers(true)
405 {
406  FunctionParser<chartdim> *pf = new FunctionParser<chartdim>(spacedim, 0.0, h);
407  FunctionParser<spacedim> *pb = new FunctionParser<spacedim>(chartdim, 0.0, h);
408  pf->initialize(chart_vars, push_forward_expression, const_map);
409  pb->initialize(space_vars, pull_back_expression, const_map);
410  push_forward_function = pf;
411  pull_back_function = pb;
412 }
413 
414 template <int dim, int spacedim, int chartdim>
416 {
417  if (owns_pointers == true)
418  {
419  const Function<chartdim> *pf = push_forward_function;
420  push_forward_function = 0;
421  delete pf;
422 
423  const Function<spacedim> *pb = pull_back_function;
424  pull_back_function = 0;
425  delete pb;
426  }
427 }
428 
429 template <int dim, int spacedim, int chartdim>
432 {
433  Vector<double> pf(spacedim);
434  Point<spacedim> result;
435  push_forward_function->vector_value(chart_point, pf);
436  for (unsigned int i=0; i<spacedim; ++i)
437  result[i] = pf[i];
438 
439 #ifdef DEBUG
440  Vector<double> pb(chartdim);
441  pull_back_function->vector_value(result, pb);
442  for (unsigned int i=0; i<chartdim; ++i)
443  Assert((chart_point.norm() > tolerance &&
444  (std::abs(pb[i]-chart_point[i]) < tolerance*chart_point.norm())) ||
445  (std::abs(pb[i]-chart_point[i]) < tolerance),
446  ExcMessage("The push forward is not the inverse of the pull back! Bailing out."));
447 #endif
448 
449  return result;
450 }
451 
452 
453 template <int dim, int spacedim, int chartdim>
456 {
458  std::vector<Tensor<1, chartdim> > gradients(spacedim);
459  push_forward_function->vector_gradient(chart_point, gradients);
460  for (unsigned int i=0; i<spacedim; ++i)
461  for (unsigned int j=0; j<chartdim; ++j)
462  DF[i][j] = gradients[i][j];
463  return DF;
464 }
465 
466 
467 template <int dim, int spacedim, int chartdim>
470 {
471  Vector<double> pb(chartdim);
472  Point<chartdim> result;
473  pull_back_function->vector_value(space_point, pb);
474  for (unsigned int i=0; i<chartdim; ++i)
475  result[i] = pb[i];
476  return result;
477 }
478 
479 
480 
481 template <int dim>
482 Point<3>
484 {
485  double x = p(0);
486  double z = p(1);
487  double y = p(2);
488  double phi = atan2(y, x);
489  double theta = atan2(z, std::sqrt(x*x+y*y)-R);
490  double w = std::sqrt(pow(y-sin(phi)*R, 2.0)+pow(x-cos(phi)*R, 2.0)+z*z)/r;
491  return Point<3>(phi, theta, w);
492 }
493 
494 template <int dim>
495 Point<3>
497 {
498  double phi = chart_point(0);
499  double theta = chart_point(1);
500  double w = chart_point(2);
501 
502  return Point<3>(cos(phi)*R + r*w*cos(theta)*cos(phi),
503  r*w*sin(theta),
504  sin(phi)*R + r*w*cos(theta)*sin(phi)
505  );
506 }
507 
508 
509 template <int dim>
510 TorusManifold<dim>::TorusManifold (const double R, const double r)
511  : ChartManifold<dim,3,3> (Point<3>(2*numbers::PI, 2*numbers::PI, 0.0)),
512  r(r),
513  R(R)
514 {
515  Assert (R>r, ExcMessage("Outer radius R must be greater than the inner "
516  "radius r."));
517  Assert (r>0.0, ExcMessage("inner radius must be positive."));
518 }
519 
520 template <int dim>
523 {
525 
526  double phi = chart_point(0);
527  double theta = chart_point(1);
528  double w = chart_point(2);
529 
530  DX[0][0] = -sin(phi)*R - r*w*cos(theta)*sin(phi);
531  DX[0][1] = -r*w*sin(theta)*cos(phi);
532  DX[0][2] = r*cos(theta)*cos(phi);
533 
534  DX[1][0] = 0;
535  DX[1][1] = r*w*cos(theta);
536  DX[1][2] = r*sin(theta);
537 
538  DX[2][0] = cos(phi)*R + r*w*cos(theta)*cos(phi);
539  DX[2][1] = -r*w*sin(theta)*sin(phi);
540  DX[2][2] = r*cos(theta)*sin(phi);
541 
542  return DX;
543 }
544 
545 
546 
547 // explicit instantiations
548 #include "manifold_lib.inst"
549 
550 DEAL_II_NAMESPACE_CLOSE
virtual Point< spacedim > get_new_point(const ::Quadrature< spacedim > &quadrature) const 1
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1146
FunctionManifold(const Function< chartdim > &push_forward_function, const Function< spacedim > &pull_back_function, const Tensor< 1, chartdim > &periodicity=Tensor< 1, chartdim >(), const double tolerance=1e-10)
static Tensor< 1, spacedim > get_periodicity()
Definition: manifold_lib.cc:38
const std::vector< Point< dim > > & get_points() const
const std::vector< double > & get_weights() const
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:991
TorusManifold(const double R, const double r)
const unsigned int n_components
Definition: function.h:144
static const double PI
Definition: numbers.h:94
virtual Point< spacedim > get_new_point(const Quadrature< spacedim > &quad) const 1
static ::ExceptionBase & ExcMessage(std::string arg1)
virtual DerivativeForm< 1, spacedim, spacedim > push_forward_gradient(const Point< spacedim > &chart_point) const
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
CylindricalManifold(const unsigned int axis=0, const double tolerance=1e-10)
PolarManifold(const Point< spacedim > center=Point< spacedim >())
Definition: manifold_lib.cc:31
#define Assert(cond, exc)
Definition: exceptions.h:313
virtual Point< 3 > pull_back(const Point< 3 > &p) const
VectorizedArray< Number > pow(const ::VectorizedArray< Number > &x, const Number p)
virtual Point< chartdim > pull_back(const Point< spacedim > &space_point) const
virtual Point< spacedim > get_intermediate_point(const Point< spacedim > &p1, const Point< spacedim > &p2, const double w) const
numbers::NumberTraits< Number >::real_type distance(const Point< dim, Number > &p) const
virtual Point< spacedim > push_forward(const Point< chartdim > &chart_point) const
VectorizedArray< Number > sqrt(const ::VectorizedArray< Number > &x)
VectorizedArray< Number > sin(const ::VectorizedArray< Number > &x)
void initialize(const std::string &vars, const std::vector< std::string > &expressions, const ConstMap &constants, const bool time_dependent=false)
virtual DerivativeForm< 1, chartdim, spacedim > push_forward_gradient(const Point< chartdim > &chart_point) const
virtual Point< spacedim > pull_back(const Point< spacedim > &space_point) const
Definition: manifold_lib.cc:83
virtual void vector_gradient(const Point< dim > &p, std::vector< Tensor< 1, dim, Number > > &gradients) const
static ::ExceptionBase & ExcNotImplemented()
virtual Point< 3 > push_forward(const Point< 3 > &chart_point) const
SphericalManifold(const Point< spacedim > center=Point< spacedim >())
virtual Tensor< 1, spacedim > get_tangent_vector(const Point< spacedim > &x1, const Point< spacedim > &x2) const
virtual void vector_value(const Point< dim > &p, Vector< Number > &values) const
virtual DerivativeForm< 1, 3, 3 > push_forward_gradient(const Point< 3 > &chart_point) const
VectorizedArray< Number > cos(const ::VectorizedArray< Number > &x)
virtual Point< spacedim > push_forward(const Point< spacedim > &chart_point) const
Definition: manifold_lib.cc:52
static ::ExceptionBase & ExcInternalError()