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