cell_inf_hex.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 // Local includes
19 #include "libmesh/libmesh_config.h"
20 
21 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
22 
23 
24 // C++ includes
25 #include <algorithm> // for std::min, std::max
26 
27 // Local includes cont'd
28 #include "libmesh/cell_inf_hex.h"
29 #include "libmesh/cell_inf_hex8.h"
30 #include "libmesh/face_quad4.h"
31 #include "libmesh/face_inf_quad4.h"
32 #include "libmesh/fe_type.h"
33 #include "libmesh/fe_interface.h"
35 
36 namespace libMesh
37 {
38 
39 
40 
41 // ------------------------------------------------------------
42 // InfHex class static member initializations
43 
44 
45 // We need to require C++11...
46 const Real InfHex::_master_points[18][3] =
47  {
48  {-1, -1, 0},
49  {1, -1, 0},
50  {1, 1, 0},
51  {-1, 1, 0},
52  {-1, -1, 1},
53  {1, -1, 1},
54  {1, 1, 1},
55  {-1, 1, 1},
56  {0, -1, 0},
57  {1, 0, 0},
58  {0, 1, 0},
59  {-1, 0, 0},
60  {0, -1, 1},
61  {1, 0, 1},
62  {0, 1, 1},
63  {-1, 0, 1},
64  {0, 0, 0},
65  {0, 0, 1}
66  };
67 
68 
69 
70 
71 
72 
73 // ------------------------------------------------------------
74 // InfHex class member functions
75 dof_id_type InfHex::key (const unsigned int s) const
76 {
77  libmesh_assert_less (s, this->n_sides());
78 
79  // The order of the node ids does not matter, they are sorted by the
80  // compute_key() function.
81  return this->compute_key(this->node_id(InfHex8::side_nodes_map[s][0]),
82  this->node_id(InfHex8::side_nodes_map[s][1]),
83  this->node_id(InfHex8::side_nodes_map[s][2]),
84  this->node_id(InfHex8::side_nodes_map[s][3]));
85 }
86 
87 
88 
89 unsigned int InfHex::which_node_am_i(unsigned int side,
90  unsigned int side_node) const
91 {
92  libmesh_assert_less (side, this->n_sides());
93  libmesh_assert_less (side_node, 4);
94 
95  return InfHex8::side_nodes_map[side][side_node];
96 }
97 
98 
99 
100 std::unique_ptr<Elem> InfHex::side_ptr (const unsigned int i)
101 {
102  libmesh_assert_less (i, this->n_sides());
103 
104  // Return value
105  std::unique_ptr<Elem> face;
106 
107  // Think of a unit cube: (-1,1) x (-1,1) x (-1,1),
108  // with (in general) the normals pointing outwards
109  switch (i)
110  {
111  // the face at z = -1
112  // the base, where the infinite element couples to conventional
113  // elements
114  case 0:
115  {
116  // Oops, here we are, claiming the normal of the face
117  // elements point outwards -- and this is the exception:
118  // For the side built from the base face,
119  // the normal is pointing _into_ the element!
120  // Why is that? - In agreement with build_side_ptr(),
121  // which in turn _has_ to build the face in this
122  // way as to enable the cool way \p InfFE re-uses \p FE.
123  face = libmesh_make_unique<Quad4>();
124  break;
125  }
126 
127  // These faces connect to other infinite elements.
128  case 1: // the face at y = -1
129  case 2: // the face at x = 1
130  case 3: // the face at y = 1
131  case 4: // the face at x = -1
132  {
133  face = libmesh_make_unique<InfQuad4>();
134  break;
135  }
136 
137  default:
138  libmesh_error_msg("Invalid side i = " << i);
139  }
140 
141  // Set the nodes
142  for (unsigned n=0; n<face->n_nodes(); ++n)
143  face->set_node(n) = this->node_ptr(InfHex8::side_nodes_map[i][n]);
144 
145  return face;
146 }
147 
148 
149 
150 void InfHex::side_ptr (std::unique_ptr<Elem> & side,
151  const unsigned int i)
152 {
153  libmesh_assert_less (i, this->n_sides());
154 
155  // Think of a unit cube: (-1,1) x (-1,1) x (1,1)
156  switch (i)
157  {
158  // the base face
159  case 0:
160  {
161  if (!side.get() || side->type() != QUAD4)
162  {
163  side = this->side_ptr(i);
164  return;
165  }
166  break;
167  }
168 
169  // connecting to another infinite element
170  case 1:
171  case 2:
172  case 3:
173  case 4:
174  {
175  if (!side.get() || side->type() != INFQUAD4)
176  {
177  side = this->side_ptr(i);
178  return;
179  }
180  break;
181  }
182 
183  default:
184  libmesh_error_msg("Invalid side i = " << i);
185  }
186 
187  side->subdomain_id() = this->subdomain_id();
188 
189  // Set the nodes
190  for (auto n : side->node_index_range())
191  side->set_node(n) = this->node_ptr(InfHex8::side_nodes_map[i][n]);
192 }
193 
194 
195 
196 bool InfHex::is_child_on_side(const unsigned int c,
197  const unsigned int s) const
198 {
199  libmesh_assert_less (c, this->n_children());
200  libmesh_assert_less (s, this->n_sides());
201 
202  return (s == 0 || c+1 == s || c == s%4);
203 }
204 
205 
206 
207 bool InfHex::is_edge_on_side (const unsigned int e,
208  const unsigned int s) const
209 {
210  libmesh_assert_less (e, this->n_edges());
211  libmesh_assert_less (s, this->n_sides());
212 
213  return (is_node_on_side(InfHex8::edge_nodes_map[e][0],s) &&
215 }
216 
217 
218 
219 
221 {
222  switch (q)
223  {
224 
234  case DIAGONAL:
235  {
236  // Diagonal between node 0 and node 2
237  const Real d02 = this->length(0,2);
238 
239  // Diagonal between node 1 and node 3
240  const Real d13 = this->length(1,3);
241 
242  // Find the biggest and smallest diagonals
243  const Real min = std::min(d02, d13);
244  const Real max = std::max(d02, d13);
245 
246  libmesh_assert_not_equal_to (max, 0.0);
247 
248  return min / max;
249 
250  break;
251  }
252 
260  case TAPER:
261  {
262 
266  const Real d01 = this->length(0,1);
267  const Real d12 = this->length(1,2);
268  const Real d23 = this->length(2,3);
269  const Real d03 = this->length(0,3);
270 
271  std::vector<Real> edge_ratios(2);
272 
273  // Bottom
274  edge_ratios[8] = std::min(d01, d23) / std::max(d01, d23);
275  edge_ratios[9] = std::min(d03, d12) / std::max(d03, d12);
276 
277  return *(std::min_element(edge_ratios.begin(), edge_ratios.end())) ;
278 
279  break;
280  }
281 
282 
290  case STRETCH:
291  {
295  const Real sqrt3 = 1.73205080756888;
296 
300  const Real d02 = this->length(0,2);
301  const Real d13 = this->length(1,3);
302  const Real max_diag = std::max(d02, d13);
303 
304  libmesh_assert_not_equal_to ( max_diag, 0.0 );
305 
309  std::vector<Real> edges(4);
310  edges[0] = this->length(0,1);
311  edges[1] = this->length(1,2);
312  edges[2] = this->length(2,3);
313  edges[3] = this->length(0,3);
314 
315  const Real min_edge = *(std::min_element(edges.begin(), edges.end()));
316  return sqrt3 * min_edge / max_diag ;
317  }
318 
319 
324  default:
325  return Elem::quality(q);
326  }
327 }
328 
329 
330 
331 std::pair<Real, Real> InfHex::qual_bounds (const ElemQuality) const
332 {
333  libmesh_not_implemented();
334 
335  std::pair<Real, Real> bounds;
336 
337  /*
338  switch (q)
339  {
340 
341  case ASPECT_RATIO:
342  bounds.first = 1.;
343  bounds.second = 4.;
344  break;
345 
346  case SKEW:
347  bounds.first = 0.;
348  bounds.second = 0.5;
349  break;
350 
351  case SHEAR:
352  case SHAPE:
353  bounds.first = 0.3;
354  bounds.second = 1.;
355  break;
356 
357  case CONDITION:
358  bounds.first = 1.;
359  bounds.second = 8.;
360  break;
361 
362  case JACOBIAN:
363  bounds.first = 0.5;
364  bounds.second = 1.;
365  break;
366 
367  case DISTORTION:
368  bounds.first = 0.6;
369  bounds.second = 1.;
370  break;
371 
372  case TAPER:
373  bounds.first = 0.;
374  bounds.second = 0.4;
375  break;
376 
377  case STRETCH:
378  bounds.first = 0.25;
379  bounds.second = 1.;
380  break;
381 
382  case DIAGONAL:
383  bounds.first = 0.65;
384  bounds.second = 1.;
385  break;
386 
387  case SIZE:
388  bounds.first = 0.5;
389  bounds.second = 1.;
390  break;
391 
392  default:
393  libMesh::out << "Warning: Invalid quality measure chosen." << std::endl;
394  bounds.first = -1;
395  bounds.second = -1;
396  }
397  */
398 
399  return bounds;
400 }
401 
402 
403 
404 
405 
406 const unsigned short int InfHex::_second_order_adjacent_vertices[8][2] =
407  {
408  { 0, 1}, // vertices adjacent to node 8
409  { 1, 2}, // vertices adjacent to node 9
410  { 2, 3}, // vertices adjacent to node 10
411  { 0, 3}, // vertices adjacent to node 11
412 
413  { 4, 5}, // vertices adjacent to node 12
414  { 5, 6}, // vertices adjacent to node 13
415  { 6, 7}, // vertices adjacent to node 14
416  { 4, 7} // vertices adjacent to node 15
417  };
418 
419 
420 
421 const unsigned short int InfHex::_second_order_vertex_child_number[18] =
422  {
423  99,99,99,99,99,99,99,99, // Vertices
424  0,1,2,0, // Edges
425  0,1,2,0,0, // Faces
426  0 // Interior
427  };
428 
429 
430 
431 const unsigned short int InfHex::_second_order_vertex_child_index[18] =
432  {
433  99,99,99,99,99,99,99,99, // Vertices
434  1,2,3,3, // Edges
435  5,6,7,7,2, // Faces
436  6 // Interior
437  };
438 
439 
440 bool InfHex::contains_point (const Point & p, Real tol) const
441 {
442  // For infinite elements with linear base interpolation:
443  // make use of the fact that infinite elements do not
444  // live inside the envelope. Use a fast scheme to
445  // check whether point \p p is inside or outside
446  // our relevant part of the envelope. Note that
447  // this is not exclusive: only when the distance is less,
448  // we are safe. Otherwise, we cannot say anything. The
449  // envelope may be non-spherical, the physical point may lie
450  // inside the envelope, outside the envelope, or even inside
451  // this infinite element. Therefore if this fails,
452  // fall back to the FEInterface::inverse_map()
453  const Point my_origin (this->origin());
454 
455  // determine the minimal distance of the base from the origin
456  // Use norm_sq() instead of norm(), it is faster
457  Point pt0_o(this->point(0) - my_origin);
458  Point pt1_o(this->point(1) - my_origin);
459  Point pt2_o(this->point(2) - my_origin);
460  Point pt3_o(this->point(3) - my_origin);
461  const Real min_distance_sq = std::min(pt0_o.norm_sq(),
462  std::min(pt1_o.norm_sq(),
463  std::min(pt2_o.norm_sq(),
464  pt3_o.norm_sq())));
465 
466  // work with 1% allowable deviation. We can still fall
467  // back to the InfFE::inverse_map()
468  const Real conservative_p_dist_sq = 1.01 * (Point(p - my_origin).norm_sq());
469 
470 
471 
472  if (conservative_p_dist_sq < min_distance_sq)
473  {
474  // the physical point is definitely not contained in the element
475  return false;
476  }
477 
478  // this captures the case that the point is not (almost) in the direction of the element.:
479  // first, project the problem onto the unit sphere:
480  Point p_o(p - my_origin);
481  pt0_o /= pt0_o.norm();
482  pt1_o /= pt1_o.norm();
483  pt2_o /= pt2_o.norm();
484  pt3_o /= pt3_o.norm();
485  p_o /= p_o.norm();
486 
487 
488  // now, check if it is in the projected face; using that the diagonal contains
489  // the largest distance between points in it
490  Real max_h = std::max((pt0_o - pt2_o).norm_sq(),
491  (pt1_o - pt2_o).norm_sq())*1.01;
492 
493  if ((p_o - pt0_o).norm_sq() > max_h ||
494  (p_o - pt1_o).norm_sq() > max_h ||
495  (p_o - pt2_o).norm_sq() > max_h ||
496  (p_o - pt3_o).norm_sq() > max_h )
497  {
498  // the physical point is definitely not contained in the element
499  return false;
500  }
501 
502  // Declare a basic FEType. Will use default in the base,
503  // and something else (not important) in radial direction.
504  FEType fe_type(default_order());
505 
506  const Point mapped_point = FEInterface::inverse_map(dim(),
507  fe_type,
508  this,
509  p,
510  tol,
511  false);
512 
513  return FEInterface::on_reference_element(mapped_point, this->type(), tol);
514 }
515 
516 } // namespace libMesh
517 
518 
519 
520 
521 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
Manages the family, order, etc. parameters for a given FE.
Definition: fe_type.h:179
Real norm() const
Definition: type_vector.h:912
virtual dof_id_type key() const
Definition: elem.C:401
unsigned short int side
Definition: xdr_io.C:50
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
Definition: cell_inf_hex.C:331
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
Definition: cell_inf_hex.C:207
long double max(long double a, double b)
static const unsigned short int _second_order_adjacent_vertices[8][2]
Definition: cell_inf_hex.h:195
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
Definition: cell_inf_hex.C:100
static const Real _master_points[18][3]
Definition: cell_inf_hex.h:210
Real length(const unsigned int n1, const unsigned int n2) const
Definition: elem.C:390
static Point inverse_map(const unsigned int dim, const FEType &fe_t, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_interface.C:590
virtual unsigned int n_children() const override final
Definition: cell_inf_hex.h:114
static bool on_reference_element(const Point &p, const ElemType t, const Real eps=TOLERANCE)
Definition: fe_interface.C:647
virtual Point origin() const override
Definition: cell_inf.h:77
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
virtual unsigned int which_node_am_i(unsigned int side, unsigned int side_node) const override
Definition: cell_inf_hex.C:89
Real norm_sq() const
Definition: type_vector.h:943
static const unsigned short int _second_order_vertex_child_index[18]
Definition: cell_inf_hex.h:205
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
Definition: elem.h:2034
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:1957
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const override
Definition: cell_inf_hex.C:440
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override final
Definition: cell_inf_hex.C:196
virtual Real quality(const ElemQuality q) const
Definition: elem.C:1403
virtual unsigned short dim() const override
Definition: cell_inf.h:66
virtual Real quality(const ElemQuality q) const override
Definition: cell_inf_hex.C:220
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
virtual unsigned int n_edges() const override final
Definition: cell_inf_hex.h:104
static dof_id_type compute_key(dof_id_type n0)
Definition: elem.h:2754
virtual Order default_order() const =0
virtual ElemType type() const =0
long double min(long double a, double b)
A geometric point in (x,y,z) space.
Definition: point.h:38
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:1914
const Point & point(const unsigned int i) const
Definition: elem.h:1892
static const unsigned short int _second_order_vertex_child_number[18]
Definition: cell_inf_hex.h:200
std::unique_ptr< Elem > side(const unsigned int i) const
Definition: elem.h:2202
uint8_t dof_id_type
Definition: id_types.h:64
virtual unsigned int n_sides() const override final
Definition: cell_inf_hex.h:85