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