libMesh
face_quad4.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/edge_edge2.h"
20 #include "libmesh/face_quad4.h"
21 #include "libmesh/enum_io_package.h"
22 #include "libmesh/enum_order.h"
23 
24 namespace libMesh
25 {
26 
27 
28 
29 
30 // ------------------------------------------------------------
31 // Quad4 class static member initialization
32 const int Quad4::num_nodes;
33 const int Quad4::nodes_per_side;
34 
36  {
37  {0, 1}, // Side 0
38  {1, 2}, // Side 1
39  {2, 3}, // Side 2
40  {3, 0} // Side 3
41  };
42 
43 #ifdef LIBMESH_ENABLE_AMR
44 
46  {
47  // embedding matrix for child 0
48  {
49  // 0 1 2 3
50  {1.0, 0.0, 0.0, 0.0}, // 0
51  {0.5, 0.5, 0.0, 0.0}, // 1
52  {.25, .25, .25, .25}, // 2
53  {0.5, 0.0, 0.0, 0.5} // 3
54  },
55 
56  // embedding matrix for child 1
57  {
58  // 0 1 2 3
59  {0.5, 0.5, 0.0, 0.0}, // 0
60  {0.0, 1.0, 0.0, 0.0}, // 1
61  {0.0, 0.5, 0.5, 0.0}, // 2
62  {.25, .25, .25, .25} // 3
63  },
64 
65  // embedding matrix for child 2
66  {
67  // 0 1 2 3
68  {0.5, 0.0, 0.0, 0.5}, // 0
69  {.25, .25, .25, .25}, // 1
70  {0.0, 0.0, 0.5, 0.5}, // 2
71  {0.0, 0.0, 0.0, 1.0} // 3
72  },
73 
74  // embedding matrix for child 3
75  {
76  // 0 1 2 3
77  {.25, .25, .25, .25}, // 0
78  {0.0, 0.5, 0.5, 0.0}, // 1
79  {0.0, 0.0, 1.0, 0.0}, // 2
80  {0.0, 0.0, 0.5, 0.5} // 3
81  }
82  };
83 
84 #endif
85 
86 
87 
88 
89 
90 // ------------------------------------------------------------
91 // Quad4 class member functions
92 
93 bool Quad4::is_vertex(const unsigned int libmesh_dbg_var(n)) const
94 {
95  libmesh_assert_not_equal_to (n, invalid_uint);
96  return true;
97 }
98 
99 bool Quad4::is_edge(const unsigned int) const
100 {
101  return false;
102 }
103 
104 bool Quad4::is_face(const unsigned int) const
105 {
106  return false;
107 }
108 
109 bool Quad4::is_node_on_side(const unsigned int n,
110  const unsigned int s) const
111 {
112  libmesh_assert_less (s, n_sides());
113  return std::find(std::begin(side_nodes_map[s]),
114  std::end(side_nodes_map[s]),
115  n) != std::end(side_nodes_map[s]);
116 }
117 
118 std::vector<unsigned>
119 Quad4::nodes_on_side(const unsigned int s) const
120 {
121  libmesh_assert_less(s, n_sides());
122  return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
123 }
124 
125 std::vector<unsigned>
126 Quad4::nodes_on_edge(const unsigned int e) const
127 {
128  return nodes_on_side(e);
129 }
130 
132 {
133  Point v = this->point(3) - this->point(0);
134  return (v.relative_fuzzy_equals(this->point(2) - this->point(1), affine_tol));
135 }
136 
137 
138 
140 {
141  // At the moment this only makes sense for Lagrange elements
142  libmesh_assert_equal_to(this->mapping_type(), LAGRANGE_MAP);
143 
144  // Side vectors
145  Point s0 = this->point(1) - this->point(0);
146  Point s1 = this->point(2) - this->point(1);
147  Point s2 = this->point(3) - this->point(2);
148  Point s3 = this->point(0) - this->point(3);
149 
150  // Cross products of side vectors
151  Point v1 = s3.cross(s0);
152  Point v2 = s2.cross(s0);
153  Point v3 = s3.cross(s1);
154 
155  // A unit vector in the direction of:
156  // f(xi, eta) = (v1 + xi*v2 + eta*v3)
157  // at the midpoint (xi, eta) = (1/2, 1/2) of the element. (Note that
158  // we are using the [0,1]^2 reference element definition for the
159  // Quad4 instead of the [-1,1]^2 reference element that is typically
160  // used for FEM calculations.) We use this as a "reference" vector
161  // and compare the sign of dot(n,f) at each vertex.
162  Point n = v1 + Real(.5) * (v2 + v3);
163  Real norm_n = n.norm();
164 
165  // If the Jacobian vector at the midpoint of the element is zero,
166  // then it must be either zero for the entire element, or change
167  // sign at the vertices. Either way the element is non-invertible.
168  if (norm_n <= tol)
169  return false;
170 
171  n /= norm_n;
172 
173  // Debugging
174  // std::cout << "n=" << n << std::endl;
175 
176  // Compute scalar quantity n * (v1 + xi*v2 + eta*v3) at each
177  // vertex. If it is non-zero and has the same sign at each
178  // vertex, the the element is invertible, otherwise it is not.
179  std::array<Real, 4> vertex_vals;
180  unsigned int ctr = 0;
181  for (unsigned int i=0; i<2; ++i)
182  for (unsigned int j=0; j<2; ++j)
183  vertex_vals[ctr++] = n * (v1 + Real(i)*v2 + Real(j)*v3);
184 
185  // Debugging:
186  // std::cout << "Vertex values: ";
187  // for (const auto & val : vertex_vals)
188  // std::cout << val << " ";
189  // std::cout << std::endl;
190 
191  auto result = std::minmax_element(vertex_vals.begin(), vertex_vals.end());
192  Real min_vertex = *(result.first);
193  Real max_vertex = *(result.second);
194 
195  // Debugging
196  // std::cout << "min_vertex=" << min_vertex << std::endl;
197  // std::cout << "max_vertex=" << max_vertex << std::endl;
198 
199  // If max and min are both on the same side of 0, we are invertible, otherwise we are not.
200  return ((max_vertex > 0 && min_vertex > 0) || (max_vertex < 0 && min_vertex < 0));
201 }
202 
203 
204 
206 {
207  return FIRST;
208 }
209 
210 
211 
212 std::unique_ptr<Elem> Quad4::build_side_ptr (const unsigned int i)
213 {
214  return this->simple_build_side_ptr<Edge2, Quad4>(i);
215 }
216 
217 
218 
219 void Quad4::build_side_ptr (std::unique_ptr<Elem> & side,
220  const unsigned int i)
221 {
222  this->simple_build_side_ptr<Quad4>(side, i, EDGE2);
223 }
224 
225 
226 
227 void Quad4::connectivity(const unsigned int libmesh_dbg_var(sf),
228  const IOPackage iop,
229  std::vector<dof_id_type> & conn) const
230 {
231  libmesh_assert_less (sf, this->n_sub_elem());
232  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
233 
234  // Create storage.
235  conn.resize(4);
236 
237  switch (iop)
238  {
239  case TECPLOT:
240  {
241  conn[0] = this->node_id(0)+1;
242  conn[1] = this->node_id(1)+1;
243  conn[2] = this->node_id(2)+1;
244  conn[3] = this->node_id(3)+1;
245  return;
246  }
247 
248  case VTK:
249  {
250  conn[0] = this->node_id(0);
251  conn[1] = this->node_id(1);
252  conn[2] = this->node_id(2);
253  conn[3] = this->node_id(3);
254  return;
255  }
256 
257  default:
258  libmesh_error_msg("Unsupported IO package " << iop);
259  }
260 }
261 
262 
263 
265 {
266  // Convenient references to our points
267  const Point
268  &x0 = point(0), &x1 = point(1),
269  &x2 = point(2), &x3 = point(3);
270 
271  // Construct "dx/d(xi)" and "dx/d(eta)" vectors which are columns of the Jacobian.
272  // \vec{x}_{\xi} = \vec{a1}*eta + \vec{b1}
273  // \vec{x}_{\eta} = \vec{a2}*xi + \vec{b2}
274  // This is copy-pasted directly from the output of a Python script. Note: we are off
275  // by a factor of (1/4) here, but since the final result should have the same error
276  // in the numerator and denominator, it should cancel out while saving us some math
277  // operations.
278  Point
279  a1 = x0 - x1 + x2 - x3,
280  b1 = -x0 + x1 + x2 - x3,
281  a2 = a1,
282  b2 = -x0 - x1 + x2 + x3;
283 
284  // Use 2x2 quadrature to compute the integral of each basis function
285  // (as defined on the [-1,1]^2 reference domain). We use a 4-point
286  // rule, which is exact for bi-cubics. The weights for this rule are
287  // all equal to 1.
288  const Real q[2] = {-std::sqrt(Real(3))/3, std::sqrt(Real(3))/3.};
289 
290  // Nodal areas
291  Real A0 = 0., A1 = 0., A2 = 0., A3 = 0.;
292 
293  for (const auto & xi : q)
294  for (const auto & eta : q)
295  {
296  Real jxw = cross_norm(eta*a1 + b1, xi*a2 + b2);
297 
298  A0 += jxw * (1-xi) * (1-eta); // 4 * phi_0
299  A1 += jxw * (1+xi) * (1-eta); // 4 * phi_1
300  A2 += jxw * (1+xi) * (1+eta); // 4 * phi_2
301  A3 += jxw * (1-xi) * (1+eta); // 4 * phi_3
302  }
303 
304  // Compute centroid
305  return Point(x0(0)*A0 + x1(0)*A1 + x2(0)*A2 + x3(0)*A3,
306  x0(1)*A0 + x1(1)*A1 + x2(1)*A2 + x3(1)*A3,
307  x0(2)*A0 + x1(2)*A1 + x2(2)*A2 + x3(2)*A3) / (A0 + A1 + A2 + A3);
308 }
309 
310 
311 
313 {
314  // Make copies of our points. It makes the subsequent calculations a bit
315  // shorter and avoids dereferencing the same pointer multiple times.
316  Point
317  x0 = point(0), x1 = point(1),
318  x2 = point(2), x3 = point(3);
319 
320  // Construct constant data vectors.
321  // \vec{x}_{\xi} = \vec{a1}*eta + \vec{b1}
322  // \vec{x}_{\eta} = \vec{a2}*xi + \vec{b2}
323  // This is copy-pasted directly from the output of a Python script.
324  Point
325  a1 = x0/4 - x1/4 + x2/4 - x3/4,
326  b1 = -x0/4 + x1/4 + x2/4 - x3/4,
327  a2 = a1,
328  b2 = -x0/4 - x1/4 + x2/4 + x3/4;
329 
330  // Check for quick return for parallelogram QUAD4.
331  if (a1.relative_fuzzy_equals(Point(0,0,0)))
332  return 4. * b1.cross(b2).norm();
333 
334  // Otherwise, use 2x2 quadrature to approximate the surface area.
335 
336  // 4-point rule, exact for bi-cubics. The weights for this rule are
337  // all equal to 1.
338  const Real q[2] = {-std::sqrt(Real(3))/3, std::sqrt(Real(3))/3.};
339 
340  Real vol=0.;
341  for (unsigned int i=0; i<2; ++i)
342  for (unsigned int j=0; j<2; ++j)
343  vol += cross_norm(q[j]*a1 + b1,
344  q[i]*a2 + b2);
345 
346  return vol;
347 }
348 
351 {
352  return Elem::loose_bounding_box();
353 }
354 
355 
356 void Quad4::permute(unsigned int perm_num)
357 {
358  libmesh_assert_less (perm_num, 4);
359 
360  for (unsigned int i = 0; i != perm_num; ++i)
361  {
362  swap4nodes(0,1,2,3);
363  swap4neighbors(0,1,2,3);
364  }
365 }
366 
367 
368 void Quad4::flip(BoundaryInfo * boundary_info)
369 {
370  libmesh_assert(boundary_info);
371 
372  swap2nodes(0,1);
373  swap2nodes(2,3);
374  swap2neighbors(1,3);
375  swap2boundarysides(1,3,boundary_info);
376  swap2boundaryedges(1,3,boundary_info);
377 }
378 
379 
380 ElemType Quad4::side_type (const unsigned int libmesh_dbg_var(s)) const
381 {
382  libmesh_assert_less (s, 4);
383  return EDGE2;
384 }
385 
386 } // namespace libMesh
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
Definition: face_quad4.C:109
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:3550
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
Definition: assembly.h:202
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:907
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:310
Definition: assembly.h:98
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_quad4.h:155
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:1096
IOPackage
libMesh interfaces with several different software packages for the purposes of creating, reading, and writing mesh files.
virtual bool has_invertible_map(Real tol) const override
Definition: face_quad4.C:139
virtual BoundingBox loose_bounding_box() const
Definition: elem.C:3465
virtual bool has_affine_map() const override
Definition: face_quad4.C:131
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:3534
virtual bool is_edge(const unsigned int i) const override
Definition: face_quad4.C:99
The libMesh namespace provides an interface to certain functionality in the library.
ElemType side_type(const unsigned int s) const override final
Definition: face_quad4.C:380
virtual bool is_vertex(const unsigned int i) const override
Definition: face_quad4.C:93
void swap4nodes(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four node_ptrs, "rotating" them.
Definition: elem.h:2143
virtual Order default_order() const override
Definition: face_quad4.C:205
ElemMappingType mapping_type() const
Definition: elem.h:3120
void swap2nodes(unsigned int n1, unsigned int n2)
Swaps two node_ptrs.
Definition: elem.h:2092
virtual BoundingBox loose_bounding_box() const override
Builds a bounding box out of the nodal positions.
Definition: face_quad4.C:350
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
Definition: face_quad4.C:119
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
libmesh_assert(ctx)
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
Definition: type_vector.h:884
static constexpr Real affine_tol
Default tolerance to use in has_affine_map().
Definition: elem.h:2061
static const int nodes_per_side
Definition: face_quad4.h:149
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:2102
static const int num_nodes
Geometric constants for Quad4.
Definition: face_quad4.h:148
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
Definition: assembly.h:39
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Real volume() const override
An optimized method for computing the area of a 4-node quad with straight sides, but not necessarily ...
Definition: face_quad4.C:312
void swap4neighbors(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four neighbor_ptrs, "rotating" them.
Definition: elem.h:2153
virtual Point true_centroid() const override
An optimized method for computing the centroid of a 4-node quad with straight sides.
Definition: face_quad4.C:264
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_quad4.C:368
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_quad4.C:356
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_quad4.h:204
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Definition: face_quad4.C:212
virtual bool is_face(const unsigned int i) const override
Definition: face_quad4.C:104
Definition: assembly.h:69
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:2475
const Point & point(const unsigned int i) const
Definition: elem.h:2453
bool relative_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
Definition: type_vector.h:981
static const int num_children
Definition: face_quad.h:86
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
Definition: face_quad4.C:126
virtual unsigned int n_sub_elem() const override
Definition: face_quad4.h:78
virtual void connectivity(const unsigned int sf, const IOPackage iop, std::vector< dof_id_type > &conn) const override
Definition: face_quad4.C:227