libMesh
cell_tet.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 // Local includes
20 #include "libmesh/cell_tet.h"
21 #include "libmesh/cell_tet4.h"
22 #include "libmesh/face_tri3.h"
23 #include "libmesh/enum_elem_quality.h"
24 
25 namespace libMesh
26 {
27 
28 
29 
30 // ------------------------------------------------------------
31 // Tet class static member initializations
32 const int Tet::num_sides;
33 const int Tet::num_edges;
34 const int Tet::num_children;
35 
36 const Real Tet::_master_points[14][3] =
37  {
38  {0, 0, 0},
39  {1, 0, 0},
40  {0, 1, 0},
41  {0, 0, 1},
42  {0.5, 0, 0},
43  {0.5, 0.5, 0},
44  {0, 0.5, 0},
45  {0, 0, 0.5},
46  {0.5, 0, 0.5},
47  {0, 0.5, 0.5},
48  {1/Real(3), 1/Real(3), 0},
49  {1/Real(3), 0, 1/Real(3)},
50  {1/Real(3), 1/Real(3), 1/Real(3)},
51  {0, 1/Real(3), 1/Real(3)}
52  };
53 
54 const unsigned int Tet::edge_sides_map[6][2] =
55  {
56  {0, 1}, // Edge 0
57  {0, 2}, // Edge 1
58  {0, 3}, // Edge 2
59  {1, 3}, // Edge 3
60  {1, 2}, // Edge 4
61  {2, 3} // Edge 5
62  };
63 
64 const unsigned int Tet::adjacent_edges_map[/*num_vertices*/4][/*n_adjacent_edges*/3] =
65  {
66  {0, 2, 3}, // Edges adjacent to node 0
67  {0, 1, 4}, // Edges adjacent to node 1
68  {1, 2, 5}, // Edges adjacent to node 2
69  {3, 4, 5}, // Edges adjacent to node 3
70  };
71 
72 // ------------------------------------------------------------
73 // Tet class member functions
74 dof_id_type Tet::key (const unsigned int s) const
75 {
76  libmesh_assert_less (s, this->n_sides());
77 
78  return this->compute_key(this->node_id(Tet4::side_nodes_map[s][0]),
79  this->node_id(Tet4::side_nodes_map[s][1]),
80  this->node_id(Tet4::side_nodes_map[s][2]));
81 }
82 
83 
84 
85 dof_id_type Tet::low_order_key (const unsigned int s) const
86 {
87  libmesh_assert_less (s, this->n_sides());
88 
89  return this->compute_key(this->node_id(Tet4::side_nodes_map[s][0]),
90  this->node_id(Tet4::side_nodes_map[s][1]),
91  this->node_id(Tet4::side_nodes_map[s][2]));
92 }
93 
94 
95 
96 unsigned int Tet::local_side_node(unsigned int side,
97  unsigned int side_node) const
98 {
99  libmesh_assert_less (side, this->n_sides());
100  libmesh_assert_less (side_node, Tet4::nodes_per_side);
101 
102  return Tet4::side_nodes_map[side][side_node];
103 }
104 
105 
106 
107 unsigned int Tet::local_edge_node(unsigned int edge,
108  unsigned int edge_node) const
109 {
110  libmesh_assert_less (edge, this->n_edges());
111  libmesh_assert_less (edge_node, Tet4::nodes_per_edge);
112 
113  return Tet4::edge_nodes_map[edge][edge_node];
114 }
115 
116 
117 std::unique_ptr<Elem> Tet::side_ptr (const unsigned int i)
118 {
119  libmesh_assert_less (i, this->n_sides());
120 
121  std::unique_ptr<Elem> face = std::make_unique<Tri3>();
122 
123  for (auto n : face->node_index_range())
124  face->set_node(n, this->node_ptr(Tet4::side_nodes_map[i][n]));
125 
126  return face;
127 }
128 
129 
130 
131 void Tet::side_ptr (std::unique_ptr<Elem> & side,
132  const unsigned int i)
133 {
134  this->simple_side_ptr<Tet,Tet4>(side, i, TRI3);
135 }
136 
137 
138 
139 void Tet::select_diagonal (const Diagonal diag) const
140 {
141  libmesh_assert_equal_to (_diagonal_selection, INVALID_DIAG);
142  _diagonal_selection = diag;
143 }
144 
145 
146 
147 
148 
149 #ifdef LIBMESH_ENABLE_AMR
150 
151 
152 bool Tet::is_child_on_side_helper(const unsigned int c,
153  const unsigned int s,
154  const unsigned int checked_nodes[][3]) const
155 {
156  libmesh_assert_less (c, this->n_children());
157  libmesh_assert_less (s, this->n_sides());
158 
159  // For the 4 vertices, child c touches vertex c, so we can return
160  // true if that vertex is on side s
161  for (unsigned int i = 0; i != 3; ++i)
162  if (Tet4::side_nodes_map[s][i] == c)
163  return true;
164 
165  // If we are a "vertex child" and we didn't already return true,
166  // we must not be on the side in question
167  if (c < 4)
168  return false;
169 
170  // For the 4 non-vertex children, the child ordering depends on the
171  // diagonal selection. We'll let the embedding matrix figure that
172  // out: if this child has three nodes that don't depend on the
173  // position of the node_facing_side[s], then we're on side s. Which
174  // three nodes those are depends on the subclass, so their responsibility
175  // is to call this function with the proper check_nodes array
176  const unsigned int node_facing_side[4] = {3, 2, 0, 1};
177  const unsigned int n = node_facing_side[s];
178 
179  // Add up the absolute values of the entries of the embedding matrix for the
180  // nodes opposite node n. If it is equal to zero, then the child in question is
181  // on side s, so return true.
182  Real embedding_sum = 0.;
183  for (unsigned i=0; i<3; ++i)
184  embedding_sum += std::abs(this->embedding_matrix(c, checked_nodes[n][i], n));
185 
186  return ( std::abs(embedding_sum) < 1.e-3 );
187 }
188 
189 #else
190 
191 bool Tet::is_child_on_side_helper(const unsigned int /*c*/,
192  const unsigned int /*s*/,
193  const unsigned int /*checked_nodes*/[][3]) const
194 {
195  libmesh_not_implemented();
196  return false;
197 }
198 
199 #endif //LIBMESH_ENABLE_AMR
200 
201 
202 
203 
205 {
206  // If uninitialized diagonal selection, select the shortest octahedron diagonal
208  {
209  Real diag_01_23 = (this->point(0) + this->point(1) - this->point(2) - this->point(3)).norm_sq();
210  Real diag_02_13 = (this->point(0) - this->point(1) + this->point(2) - this->point(3)).norm_sq();
211  Real diag_03_12 = (this->point(0) - this->point(1) - this->point(2) + this->point(3)).norm_sq();
212 
213  std::array<Real, 3> D = {diag_02_13, diag_03_12, diag_01_23};
214 
215  this->_diagonal_selection =
216  Diagonal(std::distance(D.begin(), std::min_element(D.begin(), D.end())));
217  }
218 }
219 
220 
221 
222 bool Tet::is_edge_on_side(const unsigned int e,
223  const unsigned int s) const
224 {
225  libmesh_assert_less (e, this->n_edges());
226  libmesh_assert_less (s, this->n_sides());
227 
228  return (edge_sides_map[e][0] == s || edge_sides_map[e][1] == s);
229 }
230 
231 
232 
233 std::vector<unsigned int> Tet::sides_on_edge(const unsigned int e) const
234 {
235  libmesh_assert_less (e, this->n_edges());
236  return {edge_sides_map[e][0], edge_sides_map[e][1]};
237 }
238 
239 
240 
241 bool
243 {
244  return (triple_product(this->point(1)-this->point(0),
245  this->point(2)-this->point(0),
246  this->point(3)-this->point(0)) < 0);
247 }
248 
249 
250 std::vector<unsigned int>
251 Tet::edges_adjacent_to_node(const unsigned int n) const
252 {
253  libmesh_assert_less(n, this->n_nodes());
254 
255  // For vertices, we use the Tet::adjacent_sides_map, otherwise each
256  // of the mid-edge nodes is adjacent only to the edge it is on, and the
257  // mid-face nodes are not adjacent to any edges.
258  if (this->is_vertex(n))
259  return {std::begin(adjacent_edges_map[n]), std::end(adjacent_edges_map[n])};
260  else if (this->is_edge(n))
261  return {n - this->n_vertices()};
262 
263  // Current Tets have only vertex, edge, and face nodes.
264  libmesh_assert(this->is_face(n));
265  return {};
266 }
267 
268 
270 {
271  return Elem::quality(q); // Not implemented
272 }
273 
274 
275 
276 
277 std::pair<Real, Real> Tet::qual_bounds (const ElemQuality q) const
278 {
279  std::pair<Real, Real> bounds;
280 
281  switch (q)
282  {
283 
284  case ASPECT_RATIO_BETA:
285  case ASPECT_RATIO_GAMMA:
286  bounds.first = 1.;
287  bounds.second = 3.;
288  break;
289 
290  case SIZE:
291  case SHAPE:
292  bounds.first = 0.2;
293  bounds.second = 1.;
294  break;
295 
296  case CONDITION:
297  bounds.first = 1.;
298  bounds.second = 3.;
299  break;
300 
301  case DISTORTION:
302  bounds.first = 0.6;
303  bounds.second = 1.;
304  break;
305 
306  case JACOBIAN:
307  case SCALED_JACOBIAN:
308  bounds.first = 0.5;
309  bounds.second = 1.414;
310  break;
311 
312  default:
313  libMesh::out << "Warning: Invalid quality measure chosen." << std::endl;
314  bounds.first = -1;
315  bounds.second = -1;
316  }
317 
318  return bounds;
319 }
320 
321 
322 
324  const Real eps) const
325 {
326  const Real & xi = p(0);
327  const Real & eta = p(1);
328  const Real & zeta = p(2);
329  // The reference tetrahedral is isosceles
330  // and is bound by xi=0, eta=0, zeta=0,
331  // and xi+eta+zeta=1.
332  return ((xi >= 0.-eps) &&
333  (eta >= 0.-eps) &&
334  (zeta >= 0.-eps) &&
335  ((xi + eta + zeta) <= 1.+eps));
336 }
337 
338 
339 } // namespace libMesh
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
Definition: cell_tet.C:222
virtual Real quality(const ElemQuality q) const override
Definition: cell_tet.C:269
static const unsigned int edge_sides_map[6][2]
This maps each edge to the sides that contain said edge.
Definition: cell_tet.h:220
virtual bool is_face(const unsigned int i) const =0
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
Definition: cell_tet.C:96
virtual dof_id_type key() const
Definition: elem.C:753
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_tet4.h:195
virtual unsigned int n_sides() const override final
Definition: cell_tet.h:81
static const int num_sides
Geometric constants for all Tets.
Definition: cell_tet.h:74
Diagonal
This enumeration keeps track of which diagonal is selected during refinement.
Definition: cell_tet.h:169
static const int num_edges
Definition: cell_tet.h:75
virtual unsigned int n_children() const override final
Definition: cell_tet.h:101
Diagonal _diagonal_selection
The currently-selected diagonal used during refinement.
Definition: cell_tet.h:249
The libMesh namespace provides an interface to certain functionality in the library.
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
Definition: cell_tet.C:277
virtual bool is_flipped() const override final
Definition: cell_tet.C:242
Real distance(const Point &p)
static const unsigned int adjacent_edges_map[4][3]
This maps the node to the (in this case) 3 edge ids adjacent to the node.
Definition: cell_tet.h:265
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Definition: cell_tet.C:107
virtual Real embedding_matrix(const unsigned int child_num, const unsigned int child_node_num, const unsigned int parent_node_num) const =0
static const Real _master_points[14][3]
Master element node locations.
Definition: cell_tet.h:235
virtual unsigned int n_vertices() const override final
Definition: cell_tet.h:86
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
Definition: cell_tet.C:323
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
Definition: type_vector.h:1029
static const int nodes_per_side
Definition: cell_tet4.h:188
virtual dof_id_type low_order_key(const unsigned int s) const override
Definition: cell_tet.C:85
virtual unsigned int n_nodes() const =0
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
Definition: cell_tet.C:117
libmesh_assert(ctx)
virtual unsigned int n_edges() const override final
Definition: cell_tet.h:91
ElemQuality
Defines an enum for element quality metrics.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
auto norm_sq(const T &a) -> decltype(std::norm(a))
Definition: tensor_tools.h:104
virtual bool is_vertex(const unsigned int i) const =0
OStreamProxy out
virtual Real quality(const ElemQuality q) const
Definition: elem.C:1774
void select_diagonal(const Diagonal diag) const
Allows the user to select the diagonal for the refinement.
Definition: cell_tet.C:139
virtual std::vector< unsigned int > sides_on_edge(const unsigned int e) const override final
Definition: cell_tet.C:233
void choose_diagonal() const
Derived classes use this function to select an initial diagonal during refinement.
Definition: cell_tet.C:204
static const int num_children
Definition: cell_tet.h:76
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the edge to element node numbers.
Definition: cell_tet4.h:201
static dof_id_type compute_key(dof_id_type n0)
Definition: elem.h:3294
bool is_child_on_side_helper(const unsigned int c, const unsigned int s, const unsigned int checked_nodes[][3]) const
Called by descendant classes with appropriate data to determine if child c is on side s...
Definition: cell_tet.C:152
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:2475
const Point & point(const unsigned int i) const
Definition: elem.h:2453
static const int nodes_per_edge
Definition: cell_tet4.h:189
virtual bool is_edge(const unsigned int i) const =0
uint8_t dof_id_type
Definition: id_types.h:67
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
Definition: cell_tet.C:251