libMesh
inf_fe_map.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/libmesh_config.h"
22 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
23 #include "libmesh/inf_fe_map.h"
24 #include "libmesh/inf_fe.h"
25 #include "libmesh/fe.h"
26 #include "libmesh/elem.h"
27 #include "libmesh/inf_fe_macro.h"
28 #include "libmesh/libmesh_logging.h"
29 
30 namespace libMesh
31 {
32 
33 
34 
35 // ------------------------------------------------------------
36 // InfFE static class members concerned with coordinate
37 // mapping
38 
39 
40 Point InfFEMap::map (const unsigned int dim,
41  const Elem * inf_elem,
42  const Point & reference_point)
43 {
44  libmesh_assert(inf_elem);
45  libmesh_assert_not_equal_to (dim, 0);
46 
47  std::unique_ptr<Elem> base_elem (InfFEBase::build_elem (inf_elem));
48 
49  const Order radial_mapping_order (InfFERadial::mapping_order());
50  const Real v (reference_point(dim-1));
51 
52  // map in the base face
53  Point base_point;
54  switch (dim)
55  {
56  case 1:
57  base_point = inf_elem->point(0);
58  break;
59  case 2:
60  case 3:
61  base_point = FEMap::map (dim-1, base_elem.get(), reference_point);
62  break;
63  default:
64 #ifdef DEBUG
65  libmesh_error_msg("Unknown dim = " << dim);
66 #endif
67  break;
68  }
69 
70 
71  // map in the outer node face not necessary. Simply
72  // compute the outer_point = base_point + (base_point-origin)
73  const Point outer_point (base_point * 2. - inf_elem->origin());
74 
75  Point p;
76 
77  // there are only two mapping shapes in radial direction
78  p.add_scaled (base_point, eval (v, radial_mapping_order, 0));
79  p.add_scaled (outer_point, eval (v, radial_mapping_order, 1));
80 
81  return p;
82 }
83 
84 
85 
86 
87 
88 Point InfFEMap::inverse_map (const unsigned int dim,
89  const Elem * inf_elem,
90  const Point & physical_point,
91  const Real tolerance,
92  const bool secure)
93 {
94  libmesh_assert(inf_elem);
95  libmesh_assert_greater_equal (tolerance, 0.);
96  libmesh_assert(dim > 0);
97 
98  // Start logging the map inversion.
99  LOG_SCOPE("inverse_map()", "InfFEMap");
100 
101  // The strategy is:
102  // compute the intersection of the line
103  // physical_point - origin with the base element,
104  // find its internal coordinatels using FEMap::inverse_map():
105  // The radial part can then be computed directly later on.
106 
107  // 1.)
108  // build a base element to do the map inversion in the base face
109  std::unique_ptr<Elem> base_elem (InfFEBase::build_elem (inf_elem));
110 
111  // The point on the reference element (which we are looking for).
112  // start with an invalid guess:
113  Point p;
114  p(dim-1)=-2.;
115 
116  // 2.)
117  // Now find the intersection of a plane represented by the base
118  // element nodes and the line given by the origin of the infinite
119  // element and the physical point.
120  Point intersection;
121 
122  // the origin of the infinite element
123  const Point o = inf_elem->origin();
124 
125  switch (dim)
126  {
127  // unnecessary for 1D
128  case 1:
129  break;
130 
131  case 2:
132  libmesh_error_msg("ERROR: InfFE::inverse_map is not yet implemented in 2d");
133 
134  case 3:
135  {
136  // references to the nodal points of the base element
137  const Point & p0 = base_elem->point(0);
138  const Point & p1 = base_elem->point(1);
139  const Point & p2 = base_elem->point(2);
140 
141  // a reference to the physical point
142  const Point & fp = physical_point;
143 
144  // The intersection of the plane and the line is given by
145  // can be computed solving a linear 3x3 system
146  // a*({p1}-{p0})+b*({p2}-{p0})-c*({fp}-{o})={fp}-{p0}.
147  const Real c_factor = -(p1(0)*fp(1)*p0(2)-p1(0)*fp(2)*p0(1)
148  +fp(0)*p1(2)*p0(1)-p0(0)*fp(1)*p1(2)
149  +p0(0)*fp(2)*p1(1)+p2(0)*fp(2)*p0(1)
150  -p2(0)*fp(1)*p0(2)-fp(0)*p2(2)*p0(1)
151  +fp(0)*p0(2)*p2(1)+p0(0)*fp(1)*p2(2)
152  -p0(0)*fp(2)*p2(1)-fp(0)*p0(2)*p1(1)
153  +p0(2)*p2(0)*p1(1)-p0(1)*p2(0)*p1(2)
154  -fp(0)*p1(2)*p2(1)+p2(1)*p0(0)*p1(2)
155  -p2(0)*fp(2)*p1(1)-p1(0)*fp(1)*p2(2)
156  +p2(2)*p1(0)*p0(1)+p1(0)*fp(2)*p2(1)
157  -p0(2)*p1(0)*p2(1)-p2(2)*p0(0)*p1(1)
158  +fp(0)*p2(2)*p1(1)+p2(0)*fp(1)*p1(2))/
159  (fp(0)*p1(2)*p0(1)-p1(0)*fp(2)*p0(1)
160  +p1(0)*fp(1)*p0(2)-p1(0)*o(1)*p0(2)
161  +o(0)*p2(2)*p0(1)-p0(0)*fp(2)*p2(1)
162  +p1(0)*o(1)*p2(2)+fp(0)*p0(2)*p2(1)
163  -fp(0)*p1(2)*p2(1)-p0(0)*o(1)*p2(2)
164  +p0(0)*fp(1)*p2(2)-o(0)*p0(2)*p2(1)
165  +o(0)*p1(2)*p2(1)-p2(0)*fp(2)*p1(1)
166  +fp(0)*p2(2)*p1(1)-p2(0)*fp(1)*p0(2)
167  -o(2)*p0(0)*p1(1)-fp(0)*p0(2)*p1(1)
168  +p0(0)*o(1)*p1(2)+p0(0)*fp(2)*p1(1)
169  -p0(0)*fp(1)*p1(2)-o(0)*p1(2)*p0(1)
170  -p2(0)*o(1)*p1(2)-o(2)*p2(0)*p0(1)
171  -o(2)*p1(0)*p2(1)+o(2)*p0(0)*p2(1)
172  -fp(0)*p2(2)*p0(1)+o(2)*p2(0)*p1(1)
173  +p2(0)*o(1)*p0(2)+p2(0)*fp(1)*p1(2)
174  +p2(0)*fp(2)*p0(1)-p1(0)*fp(1)*p2(2)
175  +p1(0)*fp(2)*p2(1)-o(0)*p2(2)*p1(1)
176  +o(2)*p1(0)*p0(1)+o(0)*p0(2)*p1(1));
177 
178 
179  // Check whether the above system is ill-posed. It should
180  // only happen when \p physical_point is not in \p
181  // inf_elem. In this case, any point that is not in the
182  // element is a valid answer.
183  if (libmesh_isinf(c_factor))
184  return p;
185 
186  // The intersection should always be between the origin and the physical point.
187  // It can become positive close to the border, but should
188  // be only very small.
189  // So as in the case above, we can be sufficiently sure here
190  // that \p fp is not in this element:
191  if (c_factor > 0.01)
192  return p;
193 
194  // Compute the intersection with
195  // {intersection} = {fp} + c*({fp}-{o}).
196  intersection.add_scaled(fp,1.+c_factor);
197  intersection.add_scaled(o,-c_factor);
198 
199  break;
200  }
201 
202  default:
203  libmesh_error_msg("Invalid dim = " << dim);
204  }
205 
206  // 3.)
207  // Now we have the intersection-point (projection of physical point onto base-element).
208  // Lets compute its internal coordinates (being p(0) and p(1)):
209  p= FEMap::inverse_map(dim-1, base_elem.get(), intersection,
210  tolerance, secure);
211 
212  // 4.
213  // Now that we have the local coordinates in the base,
214  // we compute the radial distance with Newton iteration.
215 
216  // distance from the physical point to the ifem origin
217  const Real fp_o_dist = Point(o-physical_point).norm();
218 
219  // the distance from the intersection on the
220  // base to the origin
221  const Real a_dist = Point(o-intersection).norm();
222 
223  // element coordinate in radial direction
224 
225  // fp_o_dist is at infinity.
226  if (libmesh_isinf(fp_o_dist))
227  {
228  p(dim-1)=1;
229  return p;
230  }
231 
232  // when we are somewhere in this element:
233  Real v = 0;
234 
235  // For now we're sticking with T_map == CARTESIAN
236  // if (T_map == CARTESIAN)
237  v = 1.-2.*a_dist/fp_o_dist;
238  // else
239  // libmesh_not_implemented();
240 
241  // do not put the point back into the element, otherwise the contains_point-function
242  // gives false positives!
243  //if (v <= -1.-1e-5)
244  // v=-1.;
245  //if (v >= 1.)
246  // v=1.-1e-5;
247 
248  p(dim-1)=v;
249 #ifdef DEBUG
250  // first check whether we are in the reference-element:
251  if (-1.-1.e-5 < v && v < 1.)
252  {
253  const Point check = map (dim, inf_elem, p);
254  const Point diff = physical_point - check;
255 
256  if (diff.norm() > tolerance)
257  libmesh_warning("WARNING: diff is " << diff.norm());
258  }
259 #endif
260 
261  return p;
262 }
263 
264 
265 
266 void InfFEMap::inverse_map (const unsigned int dim,
267  const Elem * elem,
268  const std::vector<Point> & physical_points,
269  std::vector<Point> & reference_points,
270  const Real tolerance,
271  const bool secure)
272 {
273  // The number of points to find the
274  // inverse map of
275  const std::size_t n_points = physical_points.size();
276 
277  // Resize the vector to hold the points
278  // on the reference element
279  reference_points.resize(n_points);
280 
281  // Find the coordinates on the reference
282  // element of each point in physical space
283  for (unsigned int p=0; p<n_points; p++)
284  reference_points[p] =
285  inverse_map (dim, elem, physical_points[p], tolerance, secure);
286 }
287 
288 
289 } // namespace libMesh
290 
291 
292 #endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
libMesh::InfFERadial::mapping_order
static Order mapping_order()
Definition: inf_fe.h:93
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::Order
Order
Definition: enum_order.h:40
libMesh::FEMap::map
static Point map(const unsigned int dim, const Elem *elem, const Point &reference_point)
Definition: fe_map.C:2043
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::Elem::point
const Point & point(const unsigned int i) const
Definition: elem.h:1955
libMesh::TypeVector::size
auto size() const -> decltype(std::norm(T()))
Definition: type_vector.h:944
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::InfFEMap::inverse_map
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: inf_fe_map.C:88
libMesh::InfFEMap::eval
static Real eval(Real v, Order o, unsigned int i)
Definition: inf_fe_map_eval.C:27
libMesh::FEMap::inverse_map
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_map.C:1622
libMesh::libmesh_isinf
bool libmesh_isinf(T x)
Definition: libmesh_common.h:185
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::TypeVector::add_scaled
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:665
libMesh::InfFEMap::map
static Point map(const unsigned int dim, const Elem *inf_elem, const Point &reference_point)
Definition: inf_fe_map.C:40
libMesh::InfFEBase::build_elem
static Elem * build_elem(const Elem *inf_elem)
Build the base element of an infinite element.
Definition: inf_fe_base_radial.C:35
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::Elem::origin
virtual Point origin() const
Definition: elem.h:1593
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::TypeVector::norm
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:955