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