Line data Source code
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 :
20 : #ifndef LIBMESH_CELL_TET_H
21 : #define LIBMESH_CELL_TET_H
22 :
23 : // Local includes
24 : #include "libmesh/cell.h"
25 :
26 : namespace libMesh
27 : {
28 :
29 : /**
30 : * The \p Tet is an element in 3D composed of 4 sides.
31 : *
32 : * \author Benjamin S. Kirk
33 : * \date 2002
34 : * \brief The base class for all tetrahedral element types.
35 : */
36 : class Tet : public Cell
37 : {
38 : public:
39 :
40 : /**
41 : * Default tetrahedral element, takes number of nodes and
42 : * parent. Derived classes implement 'true' elements.
43 : */
44 19432678 : Tet (const unsigned int nn, Elem * p, Node ** nodelinkdata) :
45 19432678 : Cell(nn, num_sides, p, _elemlinks_data, nodelinkdata),
46 19432678 : _diagonal_selection(INVALID_DIAG)
47 : {
48 : // Make sure the interior parent isn't undefined
49 : if (LIBMESH_DIM > 3)
50 : this->set_interior_parent(nullptr);
51 421842 : }
52 :
53 : Tet (Tet &&) = delete;
54 : Tet (const Tet &) = delete;
55 : Tet & operator= (const Tet &) = delete;
56 : Tet & operator= (Tet &&) = delete;
57 421842 : virtual ~Tet() = default;
58 :
59 : /**
60 : * \returns The \p Point associated with local \p Node \p i,
61 : * in master element rather than physical coordinates.
62 : */
63 2595292 : virtual Point master_point (const unsigned int i) const override final
64 : {
65 75904 : libmesh_assert_less(i, this->n_nodes());
66 2595292 : return Point(_master_points[i][0],
67 2595292 : _master_points[i][1],
68 2671196 : _master_points[i][2]);
69 : }
70 :
71 : /**
72 : * Geometric constants for all Tets
73 : */
74 : static const int num_sides = 4;
75 : static const int num_edges = 6;
76 : static const int num_children = 8;
77 :
78 : /**
79 : * \returns 4.
80 : */
81 480372922 : virtual unsigned int n_sides() const override final { return 4; }
82 :
83 : /**
84 : * \returns 4. All tetrahedra have 4 vertices.
85 : */
86 2005992573 : virtual unsigned int n_vertices() const override final { return 4; }
87 :
88 : /**
89 : * \returns 6. All tetrahedra have 6 edges.
90 : */
91 82730014 : virtual unsigned int n_edges() const override final { return 6; }
92 :
93 : /**
94 : * \returns 4. All tetrahedra have 4 faces.
95 : */
96 12031323 : virtual unsigned int n_faces() const override final { return 4; }
97 :
98 : /**
99 : * \returns 8.
100 : */
101 55206276 : virtual unsigned int n_children() const override final { return 8; }
102 :
103 : /**
104 : * \returns \p true if the specified edge is on the specified side.
105 : */
106 : virtual bool is_edge_on_side(const unsigned int e,
107 : const unsigned int s) const override final;
108 :
109 : /**
110 : * Don't hide Elem::key() defined in the base class.
111 : */
112 : using Elem::key;
113 :
114 : /**
115 : * \returns An id associated with the \p s side of this element.
116 : * The id is not necessarily unique, but should be close.
117 : */
118 : virtual dof_id_type key (const unsigned int s) const override;
119 :
120 : /**
121 : * \returns An id associated with the \p s side of this element, as
122 : * defined solely by element vertices. The id is not necessarily
123 : * unique, but should be close. This is particularly useful in the
124 : * \p MeshBase::find_neighbors() routine.
125 : */
126 : virtual dof_id_type low_order_key (const unsigned int s) const override;
127 :
128 : /**
129 : * \returns \p Tet4::side_nodes_map[side][side_node] after doing some range checking.
130 : */
131 : virtual unsigned int local_side_node(unsigned int side,
132 : unsigned int side_node) const override;
133 :
134 : /**
135 : * \returns \p Tet4::edge_nodes_map[edge][edge_node] after doing some range checking.
136 : */
137 : virtual unsigned int local_edge_node(unsigned int edge,
138 : unsigned int edge_node) const override;
139 :
140 : /**
141 : * \returns A primitive (3-noded) triangle for face i.
142 : */
143 : virtual std::unique_ptr<Elem> side_ptr (const unsigned int i) override final;
144 :
145 : /**
146 : * Rebuilds a primitive (3-noded) triangle for face i.
147 : */
148 : virtual void side_ptr (std::unique_ptr<Elem> & side, const unsigned int i) override final;
149 :
150 : /**
151 : * \returns A quantitative assessment of element quality based on
152 : * the quality metric \p q specified by the user.
153 : */
154 : virtual Real quality (const ElemQuality q) const override;
155 :
156 : /**
157 : * \returns The suggested quality bounds for the hex based on quality
158 : * measure \p q. These are the values suggested by the CUBIT User's
159 : * Manual.
160 : */
161 : virtual std::pair<Real, Real> qual_bounds (const ElemQuality q) const override;
162 :
163 : /**
164 : * This enumeration keeps track of which diagonal is selected during
165 : * refinement. In general there are three possible diagonals to
166 : * choose when splitting the octahedron, and by choosing the shortest
167 : * one we obtain the best element shape.
168 : */
169 : enum Diagonal
170 : {
171 : DIAG_02_13=0, // diagonal between edges (0,2) and (1,3)
172 : DIAG_03_12=1, // diagonal between edges (0,3) and (1,2)
173 : DIAG_01_23=2, // diagonal between edges (0,1) and (2,3)
174 : INVALID_DIAG=99 // diagonal not yet selected
175 : };
176 :
177 : /**
178 : * \returns The diagonal that has been selected during refinement.
179 : */
180 33954480 : Diagonal diagonal_selection () const { return _diagonal_selection; }
181 :
182 : /**
183 : * Allows the user to select the diagonal for the refinement. This
184 : * function may only be called before the element is ever refined.
185 : */
186 : void select_diagonal (const Diagonal diag) const;
187 :
188 : virtual std::vector<unsigned int> sides_on_edge(const unsigned int e) const override final;
189 :
190 :
191 : #ifdef LIBMESH_ENABLE_AMR
192 :
193 :
194 : /**
195 : * Tetrahedral elements permute the embedding matrix depending on which
196 : * interior diagonal is used to subdivide into child elements.
197 : * But we want to cache topology data based on that matrix. So we return a
198 : * "version number" based on the diagonal selection.
199 : */
200 36098200 : virtual unsigned int embedding_matrix_version () const override final
201 : {
202 36098200 : this->choose_diagonal();
203 36098200 : return this->diagonal_selection();
204 : }
205 :
206 : #endif // LIBMESH_ENABLE_AMR
207 :
208 : /**
209 : * Four sides, three orientations.
210 : */
211 1205053 : virtual unsigned int n_permutations() const override final { return 12; }
212 :
213 : virtual bool is_flipped() const override final;
214 :
215 : virtual std::vector<unsigned int> edges_adjacent_to_node(const unsigned int n) const override;
216 :
217 : /**
218 : * This maps each edge to the sides that contain said edge.
219 : */
220 : static const unsigned int edge_sides_map[6][2];
221 :
222 : virtual bool on_reference_element(const Point & p,
223 : const Real eps = TOLERANCE) const override final;
224 :
225 : protected:
226 :
227 : /**
228 : * Data for links to parent/neighbor/interior_parent elements.
229 : */
230 : Elem * _elemlinks_data[5+(LIBMESH_DIM>3)];
231 :
232 : /**
233 : * Master element node locations
234 : */
235 : static const Real _master_points[14][3];
236 :
237 : /**
238 : * Called by descendant classes with appropriate data to determine
239 : * if child c is on side s. Only works if LIBMESH_ENABLE_AMR.
240 : */
241 : bool is_child_on_side_helper(const unsigned int c,
242 : const unsigned int s,
243 : const unsigned int checked_nodes[][3] ) const;
244 :
245 : /**
246 : * The currently-selected diagonal used during refinement.
247 : * Initialized to INVALID_DIAG.
248 : */
249 : mutable Diagonal _diagonal_selection;
250 :
251 : /**
252 : * Derived classes use this function to select an initial
253 : * diagonal during refinement. The optimal choice is the shortest
254 : * of the three.
255 : */
256 : void choose_diagonal() const;
257 :
258 : /**
259 : * This maps the \f$ j^{th} \f$ node to the (in this case) 3 edge
260 : * ids adjacent to the node. The edge numbering matches the ones used
261 : * in the derived classes' edge_nodes_map. This data structure
262 : * is used in the Tet::edges_adjacent_to_node() override and is
263 : * shared by all the derived Tet types.
264 : */
265 : static const unsigned int adjacent_edges_map[/*num_vertices*/4][/*n_adjacent_edges*/3];
266 : };
267 :
268 : } // namespace libMesh
269 :
270 : #endif // LIBMESH_CELL_TET_H
|