inf_fe_map.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 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.h"
24 #include "libmesh/fe.h"
25 #include "libmesh/elem.h"
26 #include "libmesh/inf_fe_macro.h"
28 
29 namespace libMesh
30 {
31 
32 
33 
34 // ------------------------------------------------------------
35 // InfFE static class members concerned with coordinate
36 // mapping
37 
38 
39 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
41  const Point & reference_point)
42 {
43  libmesh_assert(inf_elem);
44  libmesh_assert_not_equal_to (Dim, 0);
45 
46  std::unique_ptr<Elem> base_elem (Base::build_elem (inf_elem));
47 
48  const Order radial_mapping_order (Radial::mapping_order());
49  const Real v (reference_point(Dim-1));
50 
51  // map in the base face
52  Point base_point;
53  switch (Dim)
54  {
55  case 1:
56  base_point = inf_elem->point(0);
57  break;
58  case 2:
59  base_point = FE<1,LAGRANGE>::map (base_elem.get(), reference_point);
60  break;
61  case 3:
62  base_point = FE<2,LAGRANGE>::map (base_elem.get(), reference_point);
63  break;
64  default:
65 #ifdef DEBUG
66  libmesh_error_msg("Unknown Dim = " << Dim);
67 #endif
68  break;
69  }
70 
71 
72  // map in the outer node face not necessary. Simply
73  // compute the outer_point = base_point + (base_point-origin)
74  const Point outer_point (base_point * 2. - inf_elem->origin());
75 
76  Point p;
77 
78  // there are only two mapping shapes in radial direction
79  p.add_scaled (base_point, InfFE<Dim,INFINITE_MAP,T_map>::eval (v, radial_mapping_order, 0));
80  p.add_scaled (outer_point, InfFE<Dim,INFINITE_MAP,T_map>::eval (v, radial_mapping_order, 1));
81 
82  return p;
83 }
84 
85 
86 
87 
88 
89 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
91  const Point & physical_point,
92  const Real tolerance,
93  const bool secure)
94 {
95  libmesh_assert(inf_elem);
96  libmesh_assert_greater_equal (tolerance, 0.);
97 
98  // Start logging the map inversion.
99  LOG_SCOPE("inverse_map()", "InfFE");
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 FE<Dim-1,LAGRANGE>::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 (Base::build_elem (inf_elem));
110 
111  // The point on the reference element (which we are looking for).
112  Point p;
113 
114  // 2.)
115  // Now find the intersection of a plane represented by the base
116  // element nodes and the line given by the origin of the infinite
117  // element and the physical point.
118  Point intersection;
119 
120  // the origin of the infinite element
121  const Point o = inf_elem->origin();
122 
123  switch (Dim)
124  {
125  // unnecessary for 1D
126  case 1:
127  break;
128 
129  case 2:
130  libmesh_error_msg("ERROR: InfFE::inverse_map is not yet implemented in 2d");
131 
132  case 3:
133  {
134  // references to the nodal points of the base element
135  const Point & p0 = base_elem->point(0);
136  const Point & p1 = base_elem->point(1);
137  const Point & p2 = base_elem->point(2);
138 
139  // a reference to the physical point
140  const Point & fp = physical_point;
141 
142  // The intersection of the plane and the line is given by
143  // can be computed solving a linear 3x3 system
144  // a*({p1}-{p0})+b*({p2}-{p0})-c*({fp}-{o})={fp}-{p0}.
145  const Real c_factor = -(p1(0)*fp(1)*p0(2)-p1(0)*fp(2)*p0(1)
146  +fp(0)*p1(2)*p0(1)-p0(0)*fp(1)*p1(2)
147  +p0(0)*fp(2)*p1(1)+p2(0)*fp(2)*p0(1)
148  -p2(0)*fp(1)*p0(2)-fp(0)*p2(2)*p0(1)
149  +fp(0)*p0(2)*p2(1)+p0(0)*fp(1)*p2(2)
150  -p0(0)*fp(2)*p2(1)-fp(0)*p0(2)*p1(1)
151  +p0(2)*p2(0)*p1(1)-p0(1)*p2(0)*p1(2)
152  -fp(0)*p1(2)*p2(1)+p2(1)*p0(0)*p1(2)
153  -p2(0)*fp(2)*p1(1)-p1(0)*fp(1)*p2(2)
154  +p2(2)*p1(0)*p0(1)+p1(0)*fp(2)*p2(1)
155  -p0(2)*p1(0)*p2(1)-p2(2)*p0(0)*p1(1)
156  +fp(0)*p2(2)*p1(1)+p2(0)*fp(1)*p1(2))/
157  (fp(0)*p1(2)*p0(1)-p1(0)*fp(2)*p0(1)
158  +p1(0)*fp(1)*p0(2)-p1(0)*o(1)*p0(2)
159  +o(0)*p2(2)*p0(1)-p0(0)*fp(2)*p2(1)
160  +p1(0)*o(1)*p2(2)+fp(0)*p0(2)*p2(1)
161  -fp(0)*p1(2)*p2(1)-p0(0)*o(1)*p2(2)
162  +p0(0)*fp(1)*p2(2)-o(0)*p0(2)*p2(1)
163  +o(0)*p1(2)*p2(1)-p2(0)*fp(2)*p1(1)
164  +fp(0)*p2(2)*p1(1)-p2(0)*fp(1)*p0(2)
165  -o(2)*p0(0)*p1(1)-fp(0)*p0(2)*p1(1)
166  +p0(0)*o(1)*p1(2)+p0(0)*fp(2)*p1(1)
167  -p0(0)*fp(1)*p1(2)-o(0)*p1(2)*p0(1)
168  -p2(0)*o(1)*p1(2)-o(2)*p2(0)*p0(1)
169  -o(2)*p1(0)*p2(1)+o(2)*p0(0)*p2(1)
170  -fp(0)*p2(2)*p0(1)+o(2)*p2(0)*p1(1)
171  +p2(0)*o(1)*p0(2)+p2(0)*fp(1)*p1(2)
172  +p2(0)*fp(2)*p0(1)-p1(0)*fp(1)*p2(2)
173  +p1(0)*fp(2)*p2(1)-o(0)*p2(2)*p1(1)
174  +o(2)*p1(0)*p0(1)+o(0)*p0(2)*p1(1));
175 
176 
177  // Check whether the above system is ill-posed. It should
178  // only happen when \p physical_point is not in \p
179  // inf_elem. In this case, any point that is not in the
180  // element is a valid answer.
181  if (libmesh_isinf(c_factor))
182  return o;
183 
184  // The intersection should always be between the origin and the physical point.
185  // It can become positive close to the border, but should
186  // be only very small.
187  // So as in the case above, we can be sufficiently sure here
188  // that \p fp is not in this element:
189  if (c_factor > 0.01)
190  return o;
191 
192  // Compute the intersection with
193  // {intersection} = {fp} + c*({fp}-{o}).
194  intersection.add_scaled(fp,1.+c_factor);
195  intersection.add_scaled(o,-c_factor);
196 
197  break;
198  }
199 
200  default:
201  libmesh_error_msg("Invalid dim = " << Dim);
202  }
203 
204  // 3.)
205  // Now we have the intersection-point (projection of physical point onto base-element).
206  // Lets compute its internal coordinates (being p(0) and p(1)):
207  p= FE<Dim-1,LAGRANGE>::inverse_map(base_elem.get(), intersection, tolerance, secure);
208 
209  // 4.
210  //
211  // Now that we have the local coordinates in the base,
212  // we compute the radial distance with Newton iteration.
213 
214  // distance from the physical point to the ifem origin
215  const Real fp_o_dist = Point(o-physical_point).norm();
216 
217  // the distance from the intersection on the
218  // base to the origin
219  const Real a_dist = Point(o-intersection).norm();
220 
221  // element coordinate in radial direction
222  Real v = 0;
223 
224  // Physical_point is not in this element (return the best approximation)
225  if (fp_o_dist < a_dist)
226  {
227  v=-1;
228  }
229 
230  // fp_o_dist is at infinity.
231  if (libmesh_isinf(fp_o_dist))
232  {
233  v=1;
234  }
235 
236  // when we are somewhere in this element:
237  if (v==0)
238  {
239  // We know the analytic answer for CARTESIAN,
240  // other schemes do not yet have a better guess.
241  if (T_map == CARTESIAN)
242  v = 1.-2.*a_dist/fp_o_dist;
243  else
244  libmesh_not_implemented();
245 
246  // after the tests above, this should never be reached,
247  // but lets be safe and ensure a valid result.
248  if (v <= -1.-1e-5)
249  v=-1.;
250  if (v >= 1.)
251  v=1.-1e-5;
252  }
253 
254  p(Dim-1)=v;
255 #ifdef DEBUG
256  const Point check = InfFE<Dim,T_radial,T_map>::map (inf_elem, p);
257  const Point diff = physical_point - check;
258 
259  if (diff.norm() > tolerance)
260  libmesh_warning("WARNING: diff is " << diff.norm());
261 #endif
262 
263  return p;
264 }
265 
266 
267 
268 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
270  const std::vector<Point> & physical_points,
271  std::vector<Point> & reference_points,
272  const Real tolerance,
273  const bool secure)
274 {
275  // The number of points to find the
276  // inverse map of
277  const std::size_t n_points = physical_points.size();
278 
279  // Resize the vector to hold the points
280  // on the reference element
281  reference_points.resize(n_points);
282 
283  // Find the coordinates on the reference
284  // element of each point in physical space
285  for (unsigned int p=0; p<n_points; p++)
286  reference_points[p] =
287  InfFE<Dim,T_radial,T_map>::inverse_map (elem, physical_points[p], tolerance, secure);
288 }
289 
290 
291 
292 
293 //--------------------------------------------------------------
294 // Explicit instantiations using the macro from inf_fe_macro.h
295 //INSTANTIATE_INF_FE(1,CARTESIAN);
296 
297 //INSTANTIATE_INF_FE(2,CARTESIAN);
298 
299 //INSTANTIATE_INF_FE(3,CARTESIAN);
300 
301 INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Point, map(const Elem *, const Point &));
302 INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Point, map(const Elem *, const Point &));
303 INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Point, map(const Elem *, const Point &));
304 
305 INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Point, inverse_map(const Elem *, const Point &, const Real, const bool));
306 INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, Point, inverse_map(const Elem *, const Point &, const Real, const bool));
307 INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, Point, inverse_map(const Elem *, const Point &, const Real, const bool));
308 
309 INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, void, inverse_map(const Elem *, const std::vector<Point> &, std::vector<Point> &, const Real, const bool));
310 INSTANTIATE_INF_FE_MBRF(2, CARTESIAN, void, inverse_map(const Elem *, const std::vector<Point> &, std::vector<Point> &, const Real, const bool));
311 INSTANTIATE_INF_FE_MBRF(3, CARTESIAN, void, inverse_map(const Elem *, const std::vector<Point> &, std::vector<Point> &, const Real, const bool));
312 
313 
314 } // namespace libMesh
315 
316 
317 #endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
Base class for all the infinite geometric element types.
Definition: fe.h:40
virtual Point origin() const
Definition: elem.h:1553
Real norm() const
Definition: type_vector.h:912
void add_scaled(const TypeVector< T2 > &, const T)
Definition: type_vector.h:627
The base class for all geometric element types.
Definition: elem.h:100
INSTANTIATE_INF_FE_MBRF(1, CARTESIAN, Elem *, Base::build_elem(const Elem *))
bool libmesh_isinf(T x)
static Point map(const Elem *elem, const Point &reference_point)
Definition: fe_map.C:1985
static Point inverse_map(const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: inf_fe_map.C:90
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static Point map(const Elem *inf_elem, const Point &reference_point)
Definition: inf_fe_map.C:40
Real size() const
Definition: type_vector.h:901
A geometric point in (x,y,z) space.
Definition: point.h:38
const Point & point(const unsigned int i) const
Definition: elem.h:1892
static Point inverse_map(const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_map.C:1576