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_FACE_INF_QUAD_H
21 : #define LIBMESH_FACE_INF_QUAD_H
22 :
23 : #include "libmesh/libmesh_config.h"
24 :
25 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
26 :
27 : // Local includes
28 : #include "libmesh/elem.h"
29 :
30 : namespace libMesh
31 : {
32 :
33 : /**
34 : * The \p InfQuad is an abstract element type that lives in two
35 : * dimensions. Here, an infinite face is always a quadrilateral,
36 : * so this class is directly derived from \p Elem, without an
37 : * intermediate \p InfFace class.
38 : *
39 : * It looks like this:
40 : * \verbatim
41 : * closer to infinity
42 : * | |
43 : * | |
44 : * side 2 | | side 1
45 : * | |
46 : * | |
47 : * ----------- base side
48 : *
49 : * side 0
50 : * \endverbatim
51 : *
52 : * \author Daniel Dreyer
53 : * \date 2003
54 : * \brief The base class for all 2D infinite quadrilateral element types.
55 : */
56 : class InfQuad : public Elem
57 : {
58 : public:
59 :
60 : /**
61 : * Constructor. Derived classes implement 'true' elements.
62 : */
63 : explicit
64 17460 : InfQuad (const unsigned int nn,
65 : Elem * p,
66 17460 : Node ** nodelinkdata) :
67 17460 : Elem(nn, num_sides, p, _elemlinks_data, nodelinkdata)
68 : {
69 : // Make sure the interior parent isn't undefined
70 : if (LIBMESH_DIM > 2)
71 17460 : this->set_interior_parent(nullptr);
72 17460 : }
73 :
74 : InfQuad (InfQuad &&) = delete;
75 : InfQuad (const InfQuad &) = delete;
76 : InfQuad & operator= (const InfQuad &) = delete;
77 : InfQuad & operator= (InfQuad &&) = delete;
78 17460 : virtual ~InfQuad() = default;
79 :
80 : /**
81 : * \returns The \p Point associated with local \p Node \p i,
82 : * in master element rather than physical coordinates.
83 : */
84 1200 : virtual Point master_point (const unsigned int i) const override final
85 : {
86 480 : libmesh_assert_less(i, this->n_nodes());
87 1200 : return Point(_master_points[i][0],
88 1200 : _master_points[i][1],
89 1680 : _master_points[i][2]);
90 : }
91 :
92 : /**
93 : * Geometric constants for all InfQuads.
94 : */
95 : static const int num_sides = 3;
96 : static const int num_children = 2;
97 :
98 : /**
99 : * \returns 2, the dimensionality of the object.
100 : */
101 9129 : virtual unsigned short dim() const override final { return 2; }
102 :
103 : /**
104 : * \returns 3. Infinite faces have one side less
105 : * than their conventional counterparts, since one
106 : * side is supposed to be located at infinity.
107 : */
108 30811 : virtual unsigned int n_sides() const override final { return 3; }
109 :
110 : /**
111 : * \returns 4. All infinite quads (in our setting) have 4 vertices.
112 : */
113 228 : virtual unsigned int n_vertices() const override final { return 4; }
114 :
115 : /**
116 : * \returns 3. All infinite quads have 1 edge in the
117 : * base, and 2 perpendicular to the base.
118 : */
119 1954 : virtual unsigned int n_edges() const override final { return 3; }
120 :
121 : /**
122 : * \returns 0. All 2D elements have no faces, just edges.
123 : */
124 0 : virtual unsigned int n_faces() const override final { return 0; }
125 :
126 : /**
127 : * \returns 2.
128 : */
129 2414 : virtual unsigned int n_children() const override final { return 2; }
130 :
131 : /**
132 : * We number vertices first.
133 : */
134 960 : virtual bool is_vertex(const unsigned int i) const override final { return (i < 4); }
135 :
136 : /**
137 : * We number edges next.
138 : */
139 6 : virtual bool is_edge(const unsigned int i) const override final { return (i >= 4 && i < 5); }
140 :
141 : /**
142 : * We number faces last.
143 : */
144 0 : virtual bool is_face(const unsigned int i) const override final { return (i >= 5); }
145 :
146 : /**
147 : * \returns \p true if the specified (local) node number is a
148 : * "mid-edge" node on an infinite element edge.
149 : */
150 20 : virtual bool is_mid_infinite_edge_node(const unsigned int i) const
151 20 : override final { return (i > 2 && i < 4); }
152 :
153 : /**
154 : * \returns \p true if the specified child is on the specified side.
155 : */
156 : virtual bool is_child_on_side(const unsigned int c,
157 : const unsigned int s) const override final;
158 :
159 : /**
160 : * Don't hide Elem::key() defined in the base class.
161 : */
162 : using Elem::key;
163 :
164 : /**
165 : * \returns An id associated with the \p s side of this element.
166 : * The id is not necessarily unique, but should be close.
167 : */
168 : virtual dof_id_type key (const unsigned int s) const override;
169 :
170 : /**
171 : * \returns An id associated with the \p s side of this element, as
172 : * defined solely by element vertices. The id is not necessarily
173 : * unique, but should be close. This is particularly useful in the
174 : * \p MeshBase::find_neighbors() routine.
175 : */
176 : virtual dof_id_type low_order_key (const unsigned int s) const override;
177 :
178 : /**
179 : * \returns \p InfQuad4::side_nodes_map[side][side_node] after doing some range checking.
180 : */
181 : virtual unsigned int local_side_node(unsigned int side,
182 : unsigned int side_node) const override;
183 :
184 : /**
185 : * Calls local_side_node(edge, edge_node). For 2D elements, there is an implied
186 : * equivalence between edges and sides, e.g. n_edges() == n_sides(), so we treat
187 : * these two functions the same.
188 : */
189 : virtual unsigned int local_edge_node(unsigned int edge,
190 : unsigned int edge_node) const override;
191 :
192 : /**
193 : * \returns A primitive (2-noded) edge or infedge for edge \p i.
194 : */
195 : virtual std::unique_ptr<Elem> side_ptr (const unsigned int i) override final;
196 :
197 : /**
198 : * Rebuilds a primitive (2-noded) edge or infedge for edge \p i.
199 : */
200 : virtual void side_ptr (std::unique_ptr<Elem> & side, const unsigned int i) override final;
201 :
202 : /**
203 : * build_edge_ptr() and build_side_ptr() are identical in 2D.
204 : */
205 360 : virtual std::unique_ptr<Elem> build_edge_ptr (const unsigned int i) override final
206 360 : { return build_side_ptr(i); }
207 :
208 : /**
209 : * side and edge are identical for faces.
210 : */
211 0 : virtual void build_edge_ptr (std::unique_ptr<Elem> & edge, const unsigned int i) override final
212 0 : { build_side_ptr(edge, i); }
213 :
214 : // Avoid hiding deprecated version with different signature
215 : using Elem::build_side_ptr;
216 :
217 : /**
218 : * is_edge_on_side is trivial in 2D.
219 : */
220 442 : virtual bool is_edge_on_side(const unsigned int e,
221 : const unsigned int s) const override final
222 442 : { return (e == s); }
223 :
224 : /**
225 : * sides_on_edge is trivial in 2D.
226 : */
227 36 : virtual std::vector<unsigned int> sides_on_edge(const unsigned int e) const override final
228 36 : { return {e}; }
229 :
230 : /**
231 : * \returns A quantitative assessment of element quality based on
232 : * the quality metric \p q specified by the user.
233 : */
234 : virtual Real quality (const ElemQuality q) const override;
235 :
236 : /**
237 : * \returns The suggested quality bounds for
238 : * the hex based on quality measure q. These are
239 : * the values suggested by the CUBIT User's Manual.
240 : */
241 : virtual std::pair<Real, Real> qual_bounds (const ElemQuality q) const override;
242 :
243 : /**
244 : * \returns \p true. All classes derived from \p InfQuad
245 : * are infinite elements.
246 : */
247 1196 : virtual bool infinite () const override final { return true; }
248 :
249 : /**
250 : * \returns The origin of this infinite element.
251 : */
252 0 : virtual Point origin () const override final
253 : {
254 0 : return ( this->point(0)*2 - this->point(this->n_vertices()/2) );
255 : }
256 :
257 : /**
258 : * One non-infinite side; any orientation change flips the mapping
259 : * Jacobian negative.
260 : */
261 0 : virtual unsigned int n_permutations() const override final { return 0; }
262 :
263 0 : virtual void permute(unsigned int) override final { libmesh_error(); }
264 :
265 : virtual bool is_flipped() const override final;
266 :
267 : virtual std::vector<unsigned int> edges_adjacent_to_node(const unsigned int n) const override;
268 :
269 : virtual bool on_reference_element(const Point & p,
270 : const Real eps = TOLERANCE) const override final;
271 :
272 : protected:
273 :
274 : /**
275 : * Data for links to parent/neighbor/interior_parent elements.
276 : */
277 : Elem * _elemlinks_data[4+(LIBMESH_DIM>2)];
278 :
279 : /**
280 : * Master element node locations
281 : */
282 : static const Real _master_points[6][3];
283 :
284 : /**
285 : * This maps the \f$ j^{th} \f$ node to the one or two side id(s)
286 : * adjacent to the node. The side numbering matches the one used in
287 : * the derived classes' side_nodes_map. A side index of 99 is used
288 : * to indicate that there is no adjacent side. This data structure
289 : * is used in the InfQuad::edges_adjacent_to_node() override and is
290 : * shared by all the derived Quad types.
291 : */
292 : static const unsigned int adjacent_sides_map[/*num_vertices*/4][/*max_adjacent_sides*/2];
293 : };
294 :
295 : } // namespace libMesh
296 :
297 :
298 : #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
299 :
300 : #endif // LIBMESH_FACE_INF_QUAD_H
|