libMesh
Loading...
Searching...
No Matches
face_quad8.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/edge_edge3.h"
20#include "libmesh/face_quad8.h"
21#include "libmesh/enum_io_package.h"
22#include "libmesh/enum_order.h"
23
24namespace libMesh
25{
26
27
28
29
30// ------------------------------------------------------------
31// Quad8 class static member initializations
32const int Quad8::num_nodes;
33const int Quad8::nodes_per_side;
34
35
36#ifdef LIBMESH_ENABLE_AMR
37
39 {
40 // embedding matrix for child 0
41 {
42 // 0 1 2 3 4 5 6 7
43 { 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 0
44 { 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000 }, // 1
45 { -0.250000, -0.250000, -0.250000, -0.250000, 0.500000, 0.500000, 0.500000, 0.500000 }, // 2
46 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000 }, // 3
47 { 0.375000, -0.125000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000, 0.00000 }, // 4
48 { -0.187500, -0.187500, -0.187500, -0.187500, 0.750000, 0.375000, 0.250000, 0.375000 }, // 5
49 { -0.187500, -0.187500, -0.187500, -0.187500, 0.375000, 0.250000, 0.375000, 0.750000 }, // 6
50 { 0.375000, 0.00000, 0.00000, -0.125000, 0.00000, 0.00000, 0.00000, 0.750000 } // 7
51 },
52
53 // embedding matrix for child 1
54 {
55 // 0 1 2 3 4 5 6 7
56 { 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000 }, // 0
57 { 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 1
58 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000 }, // 2
59 { -0.250000, -0.250000, -0.250000, -0.250000, 0.500000, 0.500000, 0.500000, 0.500000 }, // 3
60 { -0.125000, 0.375000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000, 0.00000 }, // 4
61 { 0.00000, 0.375000, -0.125000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000 }, // 5
62 { -0.187500, -0.187500, -0.187500, -0.187500, 0.375000, 0.750000, 0.375000, 0.250000 }, // 6
63 { -0.187500, -0.187500, -0.187500, -0.187500, 0.750000, 0.375000, 0.250000, 0.375000 } // 7
64 },
65
66 // embedding matrix for child 2
67 {
68 // 0 1 2 3 4 5 6 7
69 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000 }, // 0
70 { -0.250000, -0.250000, -0.250000, -0.250000, 0.500000, 0.500000, 0.500000, 0.500000 }, // 1
71 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000 }, // 2
72 { 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 3
73 { -0.187500, -0.187500, -0.187500, -0.187500, 0.375000, 0.250000, 0.375000, 0.750000 }, // 4
74 { -0.187500, -0.187500, -0.187500, -0.187500, 0.250000, 0.375000, 0.750000, 0.375000 }, // 5
75 { 0.00000, 0.00000, -0.125000, 0.375000, 0.00000, 0.00000, 0.750000, 0.00000 }, // 6
76 { -0.125000, 0.00000, 0.00000, 0.375000, 0.00000, 0.00000, 0.00000, 0.750000 } // 7
77 },
78
79 // embedding matrix for child 3
80 {
81 // 0 1 2 3 4 5 6 7
82 { -0.250000, -0.250000, -0.250000, -0.250000, 0.500000, 0.500000, 0.500000, 0.500000 }, // 0
83 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000 }, // 1
84 { 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 2
85 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000 }, // 3
86 { -0.187500, -0.187500, -0.187500, -0.187500, 0.375000, 0.750000, 0.375000, 0.250000 }, // 4
87 { 0.00000, -0.125000, 0.375000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000 }, // 5
88 { 0.00000, 0.00000, 0.375000, -0.125000, 0.00000, 0.00000, 0.750000, 0.00000 }, // 6
89 { -0.187500, -0.187500, -0.187500, -0.187500, 0.250000, 0.375000, 0.750000, 0.375000 } // 7
90 }
91 };
92
93
94#endif
95
96
97// ------------------------------------------------------------
98// Quad8 class member functions
99
100bool Quad8::is_vertex(const unsigned int i) const
101{
102 if (i < 4)
103 return true;
104 return false;
105}
106
107bool Quad8::is_edge(const unsigned int i) const
108{
109 if (i < 4)
110 return false;
111 return true;
112}
113
114bool Quad8::is_face(const unsigned int) const
115{
116 return false;
117}
118
119bool Quad8::is_node_on_side(const unsigned int n,
120 const unsigned int s) const
121{
122 libmesh_assert_less (s, n_sides());
123 return std::find(std::begin(side_nodes_map[s]),
124 std::end(side_nodes_map[s]),
125 n) != std::end(side_nodes_map[s]);
126}
127
128std::vector<unsigned>
129Quad8::nodes_on_side(const unsigned int s) const
130{
131 libmesh_assert_less(s, n_sides());
132 return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
133}
134
135std::vector<unsigned>
136Quad8::nodes_on_edge(const unsigned int e) const
137{
138 return nodes_on_side(e);
139}
140
142{
143 // make sure corners form a parallelogram
144 Point v = this->point(1) - this->point(0);
145 if (!v.relative_fuzzy_equals(this->point(2) - this->point(3), affine_tol))
146 return false;
147 // make sure sides are straight
148 v /= 2;
149 if (!v.relative_fuzzy_equals(this->point(4) - this->point(0), affine_tol) ||
150 !v.relative_fuzzy_equals(this->point(6) - this->point(3), affine_tol))
151 return false;
152 v = (this->point(3) - this->point(0))/2;
153 if (!v.relative_fuzzy_equals(this->point(7) - this->point(0), affine_tol) ||
154 !v.relative_fuzzy_equals(this->point(5) - this->point(1), affine_tol))
155 return false;
156 return true;
157}
158
159
160
162{
163 return SECOND;
164}
165
166
167
168dof_id_type Quad8::key (const unsigned int s) const
169{
170 libmesh_assert_less (s, this->n_sides());
171
172 switch (s)
173 {
174 case 0:
175
176 return
177 this->compute_key (this->node_id(4));
178
179 case 1:
180
181 return
182 this->compute_key (this->node_id(5));
183
184 case 2:
185
186 return
187 this->compute_key (this->node_id(6));
188
189 case 3:
190
191 return
192 this->compute_key (this->node_id(7));
193
194 default:
195 libmesh_error_msg("Invalid side s = " << s);
196 }
197}
198
199
200
201unsigned int Quad8::local_side_node(unsigned int side,
202 unsigned int side_node) const
203{
204 libmesh_assert_less (side, this->n_sides());
205 libmesh_assert_less (side_node, Quad8::nodes_per_side);
206
207 return Quad8::side_nodes_map[side][side_node];
208}
209
210
211
212std::unique_ptr<Elem> Quad8::build_side_ptr (const unsigned int i)
213{
214 return this->simple_build_side_ptr<Edge3, Quad8>(i);
215}
216
217
218
219void Quad8::build_side_ptr (std::unique_ptr<Elem> & side,
220 const unsigned int i)
221{
222 this->simple_build_side_ptr<Quad8>(side, i, EDGE3);
223}
224
225
226
227
228
229
230void Quad8::connectivity(const unsigned int sf,
231 const IOPackage iop,
232 std::vector<dof_id_type> & conn) const
233{
234 libmesh_assert_less (sf, this->n_sub_elem());
235 libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
236
237 switch (iop)
238 {
239 // Note: TECPLOT connectivity is output as four triangles with
240 // a central quadrilateral. Therefore, the first four connectivity
241 // arrays are degenerate quads (triangles in Tecplot).
242 case TECPLOT:
243 {
244 // Create storage
245 conn.resize(4);
246
247 switch(sf)
248 {
249 case 0:
250 // linear sub-tri 0
251 conn[0] = this->node_id(0)+1;
252 conn[1] = this->node_id(4)+1;
253 conn[2] = this->node_id(7)+1;
254 conn[3] = this->node_id(7)+1;
255
256 return;
257
258 case 1:
259 // linear sub-tri 1
260 conn[0] = this->node_id(4)+1;
261 conn[1] = this->node_id(1)+1;
262 conn[2] = this->node_id(5)+1;
263 conn[3] = this->node_id(5)+1;
264
265 return;
266
267 case 2:
268 // linear sub-tri 2
269 conn[0] = this->node_id(5)+1;
270 conn[1] = this->node_id(2)+1;
271 conn[2] = this->node_id(6)+1;
272 conn[3] = this->node_id(6)+1;
273
274 return;
275
276 case 3:
277 // linear sub-tri 3
278 conn[0] = this->node_id(7)+1;
279 conn[1] = this->node_id(6)+1;
280 conn[2] = this->node_id(3)+1;
281 conn[3] = this->node_id(3)+1;
282
283 return;
284
285 case 4:
286 // linear sub-quad
287 conn[0] = this->node_id(4)+1;
288 conn[1] = this->node_id(5)+1;
289 conn[2] = this->node_id(6)+1;
290 conn[3] = this->node_id(7)+1;
291
292 return;
293
294 default:
295 libmesh_error_msg("Invalid sf = " << sf);
296 }
297 }
298
299
300 // VTK connectivity for this element matches libmesh's own.
301 case VTK:
302 {
303 conn.resize(Quad8::num_nodes);
304 for (auto i : index_range(conn))
305 conn[i] = this->node_id(i);
306
307 return;
308 }
309
310 default:
311 libmesh_error_msg("Unsupported IO package " << iop);
312 }
313}
314
315
316
318{
319 // This might have curved edges, or might be a curved surface in
320 // 3-space, in which case the full bounding box can be larger than
321 // the bounding box of just the nodes.
322 //
323 //
324 // FIXME - I haven't yet proven the formula below to be correct for
325 // biquadratics - RHS
326 Point pmin, pmax;
327
328 for (unsigned d=0; d<LIBMESH_DIM; ++d)
329 {
330 Real center = this->point(0)(d);
331 for (unsigned int p=1; p != 8; ++p)
332 center += this->point(p)(d);
333 center /= 8;
334
335 Real hd = std::abs(center - this->point(0)(d));
336 for (unsigned int p=0; p != 8; ++p)
337 hd = std::max(hd, std::abs(center - this->point(p)(d)));
338
339 pmin(d) = center - hd;
340 pmax(d) = center + hd;
341 }
342
343 return BoundingBox(pmin, pmax);
344}
345
346
348{
349 // This specialization is good for Lagrange mappings only
350 if (this->mapping_type() != LAGRANGE_MAP)
351 return this->Elem::volume();
352
353 // Make copies of our points. It makes the subsequent calculations a bit
354 // shorter and avoids dereferencing the same pointer multiple times.
355 Point
356 x0 = point(0),
357 x1 = point(1),
358 x2 = point(2),
359 x3 = point(3),
360 x4 = point(4),
361 x5 = point(5),
362 x6 = point(6),
363 x7 = point(7);
364
365 // Construct constant data vectors.
366 // \vec{x}_{\xi} = \vec{a1}*eta**2 + \vec{b1}*xi*eta + \vec{c1}*xi + \vec{d1}*eta + \vec{e1}
367 // \vec{x}_{\eta} = \vec{a2}*xi**2 + \vec{b2}*xi*eta + \vec{c2}*xi + \vec{d2}*eta + \vec{e2}
368 // This is copy-pasted directly from the output of a Python script.
369 Point
370 a1 = -x0/4 + x1/4 + x2/4 - x3/4 - x5/2 + x7/2,
371 b1 = -x0/2 - x1/2 + x2/2 + x3/2 + x4 - x6,
372 c1 = x0/2 + x1/2 + x2/2 + x3/2 - x4 - x6,
373 d1 = x0/4 - x1/4 + x2/4 - x3/4,
374 e1 = x5/2 - x7/2,
375 a2 = -x0/4 - x1/4 + x2/4 + x3/4 + x4/2 - x6/2,
376 b2 = -x0/2 + x1/2 + x2/2 - x3/2 - x5 + x7,
377 c2 = x0/4 - x1/4 + x2/4 - x3/4,
378 d2 = x0/2 + x1/2 + x2/2 + x3/2 - x5 - x7,
379 e2 = -x4/2 + x6/2;
380
381 // 3x3 quadrature, exact for bi-quintics
382 const unsigned int N = 3;
383 const Real q[N] = {-std::sqrt(15)/5., 0., std::sqrt(15)/5.};
384 const Real w[N] = {5./9, 8./9, 5./9};
385
386 Real vol=0.;
387 for (unsigned int i=0; i<N; ++i)
388 for (unsigned int j=0; j<N; ++j)
389 vol += w[i] * w[j] * cross_norm(q[j]*q[j]*a1 + q[i]*q[j]*b1 + q[i]*c1 + q[j]*d1 + e1,
390 q[i]*q[i]*a2 + q[i]*q[j]*b2 + q[i]*c2 + q[j]*d2 + e2);
391
392 return vol;
393}
394
395
396
397unsigned short int Quad8::second_order_adjacent_vertex (const unsigned int n,
398 const unsigned int v) const
399{
400 libmesh_assert_greater_equal (n, this->n_vertices());
401 libmesh_assert_less (n, this->n_nodes());
402 libmesh_assert_less (v, 2);
403 // use the matrix from \p face_quad.C
404 return _second_order_adjacent_vertices[n-this->n_vertices()][v];
405}
406
407
408
409std::pair<unsigned short int, unsigned short int>
410Quad8::second_order_child_vertex (const unsigned int n) const
411{
412 libmesh_assert_greater_equal (n, this->n_vertices());
413 libmesh_assert_less (n, this->n_nodes());
414 /*
415 * the _second_order_vertex_child_* vectors are
416 * stored in face_quad.C, since they are identical
417 * for Quad8 and Quad9 (for the first 4 higher-order nodes)
418 */
419 return std::pair<unsigned short int, unsigned short int>
422}
423
424
425void Quad8::permute(unsigned int perm_num)
426{
427 libmesh_assert_less (perm_num, 4);
428
429 for (unsigned int i = 0; i != perm_num; ++i)
430 {
431 swap4nodes(0,1,2,3);
432 swap4nodes(4,5,6,7);
433 swap4neighbors(0,1,2,3);
434 }
435}
436
437
438void Quad8::flip(BoundaryInfo * boundary_info)
439{
440 libmesh_assert(boundary_info);
441
442 swap2nodes(0,1);
443 swap2nodes(2,3);
444 swap2nodes(5,7);
445 swap2neighbors(1,3);
446 swap2boundarysides(1,3,boundary_info);
447 swap2boundaryedges(1,3,boundary_info);
448}
449
450
451unsigned int Quad8::center_node_on_side(const unsigned short side) const
452{
453 libmesh_assert_less (side, Quad8::num_sides);
454 return side + 4;
455}
456
457
458
459ElemType Quad8::side_type (const unsigned int libmesh_dbg_var(s)) const
460{
461 libmesh_assert_less (s, 4);
462 return EDGE3;
463}
464
465
466} // namespace libMesh
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Defines a Cartesian bounding box by the two corner extremum.
void swap4nodes(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four node_ptrs, "rotating" them.
Definition elem.h:2273
static constexpr Real affine_tol
Default tolerance to use in has_affine_map().
Definition elem.h:2191
const Point & point(const unsigned int i) const
Definition elem.h:2583
void swap2nodes(unsigned int n1, unsigned int n2)
Swaps two node_ptrs.
Definition elem.h:2222
void swap2neighbors(unsigned int n1, unsigned int n2)
Swaps two neighbor_ptrs.
Definition elem.h:2232
void swap2boundarysides(unsigned short s1, unsigned short s2, BoundaryInfo *boundary_info) const
Swaps two sides in boundary_info, if it is non-null.
Definition elem.C:3982
ElemMappingType mapping_type() const
Definition elem.h:3258
static dof_id_type compute_key(dof_id_type n0)
Definition elem.h:3432
virtual Real volume() const
Definition elem.C:3865
void swap2boundaryedges(unsigned short e1, unsigned short e2, BoundaryInfo *boundary_info) const
Swaps two edges in boundary_info, if it is non-null.
Definition elem.C:3998
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2605
void swap4neighbors(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four neighbor_ptrs, "rotating" them.
Definition elem.h:2283
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
virtual unsigned int n_sub_elem() const override
Definition face_quad8.h:83
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
Definition face_quad8.C:136
virtual void flip(BoundaryInfo *) override final
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
Definition face_quad8.C:438
virtual unsigned int n_nodes() const override
Definition face_quad8.h:78
unsigned int center_node_on_side(const unsigned short side) const override final
Definition face_quad8.C:451
static const int nodes_per_side
Definition face_quad8.h:193
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
Definition face_quad8.C:129
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Definition face_quad8.C:212
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
Definition face_quad8.C:201
virtual void permute(unsigned int perm_num) override final
Permutes the element (by swapping node and neighbor pointers) according to the specified index.
Definition face_quad8.C:425
static constexpr const unsigned int(& side_nodes_map)[num_sides][nodes_per_side]
Definition face_quad8.h:202
virtual Order default_order() const override
Definition face_quad8.C:161
virtual BoundingBox loose_bounding_box() const override
Definition face_quad8.C:317
static const int num_nodes
Geometric constants for Quad8.
Definition face_quad8.h:192
virtual void connectivity(const unsigned int sf, const IOPackage iop, std::vector< dof_id_type > &conn) const override
Definition face_quad8.C:230
virtual dof_id_type key() const
Don't hide Elem::key() defined in the base class.
Definition elem.C:678
virtual bool is_edge(const unsigned int i) const override
Definition face_quad8.C:107
virtual std::pair< unsigned short int, unsigned short int > second_order_child_vertex(const unsigned int n) const override
Definition face_quad8.C:410
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const override
Definition face_quad8.C:397
virtual bool is_face(const unsigned int i) const override
Definition face_quad8.C:114
virtual bool is_vertex(const unsigned int i) const override
Definition face_quad8.C:100
virtual bool has_affine_map() const override
Definition face_quad8.C:141
virtual Real volume() const override
An optimized method for approximating the area of a QUAD8 using quadrature.
Definition face_quad8.C:347
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
Definition face_quad8.C:119
ElemType side_type(const unsigned int s) const override final
Definition face_quad8.C:459
static const Real _embedding_matrix[num_children][num_nodes][num_nodes]
Matrix that computes new nodal locations/solution values from current nodes/solution.
Definition face_quad8.h:247
virtual unsigned int n_vertices() const override final
Definition face_quad.h:102
static const int num_children
Definition face_quad.h:86
static const int num_sides
Geometric constants for Quad4.
Definition face_quad.h:85
virtual unsigned int n_sides() const override final
Definition face_quad.h:97
static const unsigned short int _second_order_adjacent_vertices[4][2]
Matrix that tells which vertices define the location of mid-side (or second-order) nodes.
Definition face_quad.h:224
static const unsigned short int _second_order_vertex_child_number[9]
Vector that names a child sharing each second order node.
Definition face_quad.h:229
static const unsigned short int _second_order_vertex_child_index[9]
Vector that names the child vertex index for each second order node.
Definition face_quad.h:234
bool relative_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
The libMesh namespace provides an interface to certain functionality in the library.
LIBMESH_DEVICE_INLINE T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
IOPackage
libMesh interfaces with several different software packages for the purposes of creating,...
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real