libMesh
Loading...
Searching...
No Matches
cell_tet.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
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
25namespace libMesh
26{
27
28
29
30// ------------------------------------------------------------
31// Tet class static member initializations
32const int Tet::num_sides;
33const int Tet::num_edges;
34const int Tet::num_children;
35
36const 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
54const 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
64const 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
74dof_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
85dof_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
96unsigned 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
107unsigned 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
117std::unique_ptr<Elem> Tet::side_ptr (const unsigned int i)
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
131void 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
139void 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
152bool 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
191bool 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
222bool 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
233std::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
241bool
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
250std::vector<unsigned int>
251Tet::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
277std::pair<Real, Real> Tet::qual_bounds (const ElemQuality q) const
278{
279 std::pair<Real, Real> bounds;
280
281 switch (q)
282 {
283
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
const Point & point(const unsigned int i) const
Definition elem.h:2462
virtual unsigned int n_nodes() const =0
virtual bool is_face(const unsigned int i) const =0
virtual Real embedding_matrix(const unsigned int child_num, const unsigned int child_node_num, const unsigned int parent_node_num) const =0
virtual Real quality(const ElemQuality q) const
Definition elem.C:1783
virtual bool is_edge(const unsigned int i) const =0
static dof_id_type compute_key(dof_id_type n0)
Definition elem.h:3311
virtual bool is_vertex(const unsigned int i) const =0
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
static const int nodes_per_side
Definition cell_tet4.h:188
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
static const int nodes_per_edge
Definition cell_tet4.h:189
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
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
Definition cell_tet.C:96
static const int num_edges
Definition cell_tet.h:75
virtual unsigned int n_children() const override final
Definition cell_tet.h:101
static const Real _master_points[14][3]
Master element node locations.
Definition cell_tet.h:235
virtual unsigned int n_edges() const override final
Definition cell_tet.h:91
void choose_diagonal() const
Derived classes use this function to select an initial diagonal during refinement.
Definition cell_tet.C:204
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Definition cell_tet.C:107
virtual unsigned int n_vertices() const override final
Definition cell_tet.h:86
void select_diagonal(const Diagonal diag) const
Allows the user to select the diagonal for the refinement.
Definition cell_tet.C:139
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
Definition cell_tet.C:277
virtual Real quality(const ElemQuality q) const override
Definition cell_tet.C:269
virtual bool is_flipped() const override final
Definition cell_tet.C:242
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 std::vector< unsigned int > sides_on_edge(const unsigned int e) const override final
Definition cell_tet.C:233
static const int num_sides
Geometric constants for all Tets.
Definition cell_tet.h:74
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 dof_id_type key() const
Don't hide Elem::key() defined in the base class.
Definition elem.C:738
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
Definition cell_tet.C:251
Diagonal
This enumeration keeps track of which diagonal is selected during refinement.
Definition cell_tet.h:170
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
Definition cell_tet.C:117
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
Definition cell_tet.C:323
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
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
Definition cell_tet.C:222
virtual unsigned int n_sides() const override final
Definition cell_tet.h:81
virtual dof_id_type low_order_key(const unsigned int s) const override
Definition cell_tet.C:85
Diagonal _diagonal_selection
The currently-selected diagonal used during refinement.
Definition cell_tet.h:249
static const int num_children
Definition cell_tet.h:76
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)
OStreamProxy out
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