libMesh
Loading...
Searching...
No Matches
cell_inf_hex.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
37namespace libMesh
38{
39
40
41
42// ------------------------------------------------------------
43// InfHex class static member initializations
44const int InfHex::num_sides;
45const int InfHex::num_edges;
46const int InfHex::num_children;
47
48const Real InfHex::_master_points[18][3] =
49 {
50 {-1, -1, 0},
51 {1, -1, 0},
52 {1, 1, 0},
53 {-1, 1, 0},
54 {-1, -1, 1},
55 {1, -1, 1},
56 {1, 1, 1},
57 {-1, 1, 1},
58 {0, -1, 0},
59 {1, 0, 0},
60 {0, 1, 0},
61 {-1, 0, 0},
62 {0, -1, 1},
63 {1, 0, 1},
64 {0, 1, 1},
65 {-1, 0, 1},
66 {0, 0, 0},
67 {0, 0, 1}
68 };
69
70const unsigned int InfHex::edge_sides_map[8][2] =
71 {
72 {0, 1}, // Edge 0
73 {0, 2}, // Edge 1
74 {0, 3}, // Edge 2
75 {0, 4}, // Edge 3
76 {1, 4}, // Edge 4
77 {1, 2}, // Edge 5
78 {2, 3}, // Edge 6
79 {3, 4} // Edge 7
80 };
81
82const unsigned int InfHex::adjacent_edges_map[/*num_vertices*/8][/*max_adjacent_edges*/3] =
83 {
84 {0, 3, 4}, // Edges adjacent to node 0
85 {0, 1, 5}, // Edges adjacent to node 1
86 {1, 2, 6}, // Edges adjacent to node 2
87 {2, 3, 7}, // Edges adjacent to node 3
88 {4, 99, 99}, // Edges adjacent to node 4
89 {5, 99, 99}, // Edges adjacent to node 5
90 {6, 99, 99}, // Edges adjacent to node 6
91 {7, 99, 99} // Edges adjacent to node 7
92 };
93
94// ------------------------------------------------------------
95// InfHex class member functions
96dof_id_type InfHex::key (const unsigned int s) const
97{
98 libmesh_assert_less (s, this->n_sides());
99
100 // The order of the node ids does not matter, they are sorted by the
101 // compute_key() function.
102 return this->compute_key(this->node_id(InfHex8::side_nodes_map[s][0]),
103 this->node_id(InfHex8::side_nodes_map[s][1]),
104 this->node_id(InfHex8::side_nodes_map[s][2]),
105 this->node_id(InfHex8::side_nodes_map[s][3]));
106}
107
108
109
110dof_id_type InfHex::low_order_key (const unsigned int s) const
111{
112 libmesh_assert_less (s, this->n_sides());
113
114 // The order of the node ids does not matter, they are sorted by the
115 // compute_key() function.
116 return this->compute_key(this->node_id(InfHex8::side_nodes_map[s][0]),
117 this->node_id(InfHex8::side_nodes_map[s][1]),
118 this->node_id(InfHex8::side_nodes_map[s][2]),
119 this->node_id(InfHex8::side_nodes_map[s][3]));
120}
121
122
123
124unsigned int InfHex::local_side_node(unsigned int side,
125 unsigned int side_node) const
126{
127 libmesh_assert_less (side, this->n_sides());
128 libmesh_assert_less (side_node, InfHex8::nodes_per_side);
129
130 return InfHex8::side_nodes_map[side][side_node];
131}
132
133
134
135unsigned int InfHex::local_edge_node(unsigned int edge,
136 unsigned int edge_node) const
137{
138 libmesh_assert_less (edge, this->n_edges());
139 libmesh_assert_less (edge_node, InfHex8::nodes_per_edge);
140
141 return InfHex8::edge_nodes_map[edge][edge_node];
142}
143
144
145
146std::unique_ptr<Elem> InfHex::side_ptr (const unsigned int i)
147{
148 libmesh_assert_less (i, this->n_sides());
149
150 // Return value
151 std::unique_ptr<Elem> face;
152
153 // Think of a unit cube: (-1,1) x (-1,1) x (-1,1),
154 // with (in general) the normals pointing outwards
155 switch (i)
156 {
157 // the face at z = -1
158 // the base, where the infinite element couples to conventional
159 // elements
160 case 0:
161 {
162 // Oops, here we are, claiming the normal of the face
163 // elements point outwards -- and this is the exception:
164 // For the side built from the base face,
165 // the normal is pointing _into_ the element!
166 // Why is that? - In agreement with build_side_ptr(),
167 // which in turn _has_ to build the face in this
168 // way as to enable the cool way \p InfFE re-uses \p FE.
169 face = std::make_unique<Quad4>();
170 break;
171 }
172
173 // These faces connect to other infinite elements.
174 case 1: // the face at y = -1
175 case 2: // the face at x = 1
176 case 3: // the face at y = 1
177 case 4: // the face at x = -1
178 {
179 face = std::make_unique<InfQuad4>();
180 break;
181 }
182
183 default:
184 libmesh_error_msg("Invalid side i = " << i);
185 }
186
187 // Set the nodes
188 for (auto n : face->node_index_range())
189 face->set_node(n, this->node_ptr(InfHex8::side_nodes_map[i][n]));
190
191 return face;
192}
193
194
195
196void InfHex::side_ptr (std::unique_ptr<Elem> & side,
197 const unsigned int i)
198{
199 libmesh_assert_less (i, this->n_sides());
200
201 // Think of a unit cube: (-1,1) x (-1,1) x (1,1)
202 switch (i)
203 {
204 // the base face
205 case 0:
206 {
207 if (!side.get() || side->type() != QUAD4)
208 {
209 side = this->side_ptr(i);
210 return;
211 }
212 break;
213 }
214
215 // connecting to another infinite element
216 case 1:
217 case 2:
218 case 3:
219 case 4:
220 {
221 if (!side.get() || side->type() != INFQUAD4)
222 {
223 side = this->side_ptr(i);
224 return;
225 }
226 break;
227 }
228
229 default:
230 libmesh_error_msg("Invalid side i = " << i);
231 }
232
233 side->subdomain_id() = this->subdomain_id();
234
235 // Set the nodes
236 for (auto n : side->node_index_range())
237 side->set_node(n, this->node_ptr(InfHex8::side_nodes_map[i][n]));
238}
239
240
241
242bool InfHex::is_child_on_side(const unsigned int c,
243 const unsigned int s) const
244{
245 libmesh_assert_less (c, this->n_children());
246 libmesh_assert_less (s, this->n_sides());
247
248 return (s == 0 || c+1 == s || c == s%4);
249}
250
251
252
253bool InfHex::is_edge_on_side (const unsigned int e,
254 const unsigned int s) const
255{
256 libmesh_assert_less (e, this->n_edges());
257 libmesh_assert_less (s, this->n_sides());
258
259 return (edge_sides_map[e][0] == s || edge_sides_map[e][1] == s);
260}
261
262
263
264std::vector<unsigned int> InfHex::sides_on_edge(const unsigned int e) const
265{
266 libmesh_assert_less(e, this->n_edges());
267
268 return {edge_sides_map[e][0], edge_sides_map[e][1]};
269}
270
271
272bool
274{
275 return (triple_product(this->point(1)-this->point(0),
276 this->point(3)-this->point(0),
277 this->point(4)-this->point(0)) < 0);
278}
279
280std::vector<unsigned int>
281InfHex::edges_adjacent_to_node(const unsigned int n) const
282{
283 libmesh_assert_less(n, this->n_nodes());
284
285 // For vertices, we use the InfHex::adjacent_edges_map with
286 // appropriate "trimming" based on whether the vertices are "at
287 // infinity" or not. Otherwise each of the mid-edge nodes is
288 // adjacent only to the edge it is on, and the remaining nodes are
289 // not adjacent to any edge.
290 if (this->is_vertex(n))
291 {
292 auto trim = (n < 4) ? 0 : 2;
293 return {std::begin(adjacent_edges_map[n]), std::end(adjacent_edges_map[n]) - trim};
294 }
295 else if (this->is_edge(n))
296 return {n - this->n_vertices()};
297
298 libmesh_assert(this->is_face(n) || this->is_internal(n));
299 return {};
300}
301
303{
304 switch (q)
305 {
306
316 case DIAGONAL:
317 {
318 // Diagonal between node 0 and node 2
319 const Real d02 = this->length(0,2);
320
321 // Diagonal between node 1 and node 3
322 const Real d13 = this->length(1,3);
323
324 // Find the biggest and smallest diagonals
325 const Real min = std::min(d02, d13);
326 const Real max = std::max(d02, d13);
327
328 libmesh_assert_not_equal_to (max, 0.0);
329
330 return min / max;
331
332 break;
333 }
334
342 case TAPER:
343 {
344
348 const Real d01 = this->length(0,1);
349 const Real d12 = this->length(1,2);
350 const Real d23 = this->length(2,3);
351 const Real d03 = this->length(0,3);
352
353 std::vector<Real> edge_ratios(2);
354
355 // Bottom
356 edge_ratios[0] = std::min(d01, d23) / std::max(d01, d23);
357 edge_ratios[1] = std::min(d03, d12) / std::max(d03, d12);
358
359 return *(std::min_element(edge_ratios.begin(), edge_ratios.end())) ;
360
361 break;
362 }
363
364
372 case STRETCH:
373 {
377 const Real sqrt3 = 1.73205080756888;
378
382 const Real d02 = this->length(0,2);
383 const Real d13 = this->length(1,3);
384 const Real max_diag = std::max(d02, d13);
385
386 libmesh_assert_not_equal_to ( max_diag, 0.0 );
387
391 std::vector<Real> edges(4);
392 edges[0] = this->length(0,1);
393 edges[1] = this->length(1,2);
394 edges[2] = this->length(2,3);
395 edges[3] = this->length(0,3);
396
397 const Real min_edge = *(std::min_element(edges.begin(), edges.end()));
398 return sqrt3 * min_edge / max_diag ;
399 }
400
401
406 default:
407 return Elem::quality(q);
408 }
409}
410
411
412
413std::pair<Real, Real> InfHex::qual_bounds (const ElemQuality) const
414{
415 libmesh_not_implemented();
416
417 // We'll never get here
418 return {0., 0.};
419}
420
421
422
423
424
425const unsigned short int InfHex::_second_order_adjacent_vertices[8][2] =
426 {
427 { 0, 1}, // vertices adjacent to node 8
428 { 1, 2}, // vertices adjacent to node 9
429 { 2, 3}, // vertices adjacent to node 10
430 { 0, 3}, // vertices adjacent to node 11
431
432 { 4, 5}, // vertices adjacent to node 12
433 { 5, 6}, // vertices adjacent to node 13
434 { 6, 7}, // vertices adjacent to node 14
435 { 4, 7} // vertices adjacent to node 15
436 };
437
438
439
440const unsigned short int InfHex::_second_order_vertex_child_number[18] =
441 {
442 99,99,99,99,99,99,99,99, // Vertices
443 0,1,2,0, // Edges
444 0,1,2,0,0, // Faces
445 0 // Interior
446 };
447
448
449
450const unsigned short int InfHex::_second_order_vertex_child_index[18] =
451 {
452 99,99,99,99,99,99,99,99, // Vertices
453 1,2,3,3, // Edges
454 5,6,7,7,2, // Faces
455 6 // Interior
456 };
457
458
459bool InfHex::contains_point (const Point & p, Real tol) const
460{
461 // For infinite elements with linear base interpolation:
462 // make use of the fact that infinite elements do not
463 // live inside the envelope. Use a fast scheme to
464 // check whether point \p p is inside or outside
465 // our relevant part of the envelope. Note that
466 // this is not exclusive: only when the distance is less,
467 // we are safe. Otherwise, we cannot say anything. The
468 // envelope may be non-spherical, the physical point may lie
469 // inside the envelope, outside the envelope, or even inside
470 // this infinite element. Therefore if this fails,
471 // fall back to the inverse_map()
472 const Point my_origin (this->origin());
473
474 // determine the minimal distance of the base from the origin
475 // Use norm_sq() instead of norm(), it is faster
476 Point pt0_o(this->point(0) - my_origin);
477 Point pt1_o(this->point(1) - my_origin);
478 Point pt2_o(this->point(2) - my_origin);
479 Point pt3_o(this->point(3) - my_origin);
480 const Real tmp_min_distance_sq = std::min(pt0_o.norm_sq(),
481 std::min(pt1_o.norm_sq(),
482 std::min(pt2_o.norm_sq(),
483 pt3_o.norm_sq())));
484
485 // For a coarse grid, it is important to account for the fact
486 // that the sides are not spherical, thus the closest point
487 // can be closer than all edges.
488 // This is an estimator using Pythagoras:
489 const Real min_distance_sq = tmp_min_distance_sq
490 - .5*std::max((point(0)-point(2)).norm_sq(),
491 (point(1)-point(3)).norm_sq());
492
493 // work with 1% allowable deviation. We can still fall
494 // back to the InfFE::inverse_map()
495 const Real conservative_p_dist_sq = 1.01 * (Point(p - my_origin).norm_sq());
496
497
498
499 if (conservative_p_dist_sq < min_distance_sq)
500 {
501 // the physical point is definitely not contained in the element
502 return false;
503 }
504
505 // this captures the case that the point is not (almost) in the direction of the element.:
506 // first, project the problem onto the unit sphere:
507 Point p_o(p - my_origin);
508 pt0_o /= pt0_o.norm();
509 pt1_o /= pt1_o.norm();
510 pt2_o /= pt2_o.norm();
511 pt3_o /= pt3_o.norm();
512 p_o /= p_o.norm();
513
514
515 // now, check if it is in the projected face; using that the diagonal contains
516 // the largest distance between points in it
517 Real max_h = std::max((pt0_o - pt2_o).norm_sq(),
518 (pt1_o - pt3_o).norm_sq())*1.01;
519
520 if ((p_o - pt0_o).norm_sq() > max_h ||
521 (p_o - pt1_o).norm_sq() > max_h ||
522 (p_o - pt2_o).norm_sq() > max_h ||
523 (p_o - pt3_o).norm_sq() > max_h )
524 {
525 // the physical point is definitely not contained in the element
526 return false;
527 }
528
529 // Declare a basic FEType. Will use default in the base,
530 // and something else (not important) in radial direction.
531 FEType fe_type(default_order());
532
533 const Point mapped_point = InfFEMap::inverse_map(dim(), this, p,
534 tol, false);
535
536 return this->on_reference_element(mapped_point, tol);
537}
538
539
540
542 const Real eps) const
543{
544 const Real & xi = p(0);
545 const Real & eta = p(1);
546 const Real & zeta = p(2);
547
548 // The reference infhex is a [-1,1]^3.
549 return ((xi >= -1.-eps) &&
550 (xi <= 1.+eps) &&
551 (eta >= -1.-eps) &&
552 (eta <= 1.+eps) &&
553 (zeta >= -1.-eps) &&
554 (zeta <= 1.+eps));
555}
556
557
558
559} // namespace libMesh
560
561
562
563
564#endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
const Point & point(const unsigned int i) const
Definition elem.h:2462
virtual unsigned int n_nodes() const =0
virtual Order default_order() const =0
virtual Real quality(const ElemQuality q) const
Definition elem.C:1783
subdomain_id_type subdomain_id() const
Definition elem.h:2591
static dof_id_type compute_key(dof_id_type n0)
Definition elem.h:3311
bool is_internal(const unsigned int i) const
Definition elem.C:3611
Real length(const unsigned int n1, const unsigned int n2) const
Definition elem.C:727
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
virtual Point origin() const override
Definition cell_inf.h:77
virtual unsigned short dim() const override
Definition cell_inf.h:66
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:96
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the side to element node numbers.
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
static const int nodes_per_edge
static const int nodes_per_side
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...
virtual std::vector< unsigned int > sides_on_edge(const unsigned int e) const override final
static const unsigned short int _second_order_vertex_child_index[18]
Vector that names the child vertex index for each second order node.
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
static const unsigned int edge_sides_map[8][2]
This maps each edge to the sides that contain said edge.
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
static const int num_children
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override final
virtual dof_id_type low_order_key(const unsigned int s) const override
virtual unsigned int n_edges() const override final
virtual bool is_flipped() const override final
static const unsigned int adjacent_edges_map[8][3]
This maps the node to the 3 (or fewer) edge ids adjacent to the node.
virtual dof_id_type key() const
Don't hide Elem::key() defined in the base class.
Definition elem.C:738
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
virtual bool is_face(const unsigned int i) const override final
We number faces last.
static const int num_edges
virtual unsigned int n_sides() const override final
virtual bool is_edge(const unsigned int i) const override final
We number edges next.
virtual unsigned int n_children() const override final
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const override
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
virtual bool is_vertex(const unsigned int i) const override final
We number vertices first.
virtual Real quality(const ElemQuality q) const override
static const unsigned short int _second_order_vertex_child_number[18]
Vector that names a child sharing each second order node.
static const int num_sides
Geometric constants for all InfHexes.
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
static const Real _master_points[18][3]
Master element node locations.
virtual unsigned int n_vertices() const override final
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
auto norm_sq() const
auto norm() const
The libMesh namespace provides an interface to certain functionality in the library.
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
libmesh_assert(ctx)
ElemQuality
Defines an enum for element quality metrics.
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real