libMesh
Loading...
Searching...
No Matches
face_quad4.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_edge2.h"
20#include "libmesh/face_quad4.h"
21#include "libmesh/enum_io_package.h"
22#include "libmesh/enum_order.h"
23
24namespace libMesh
25{
26
27
28
29
30// ------------------------------------------------------------
31// Quad4 class static member initialization
32const int Quad4::num_nodes;
33const 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
93bool 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
99bool Quad4::is_edge(const unsigned int) const
100{
101 return false;
102}
103
104bool Quad4::is_face(const unsigned int) const
105{
106 return false;
107}
108
109bool 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
118std::vector<unsigned>
119Quad4::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
125std::vector<unsigned>
126Quad4::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
212std::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
219void 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
227void 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 // This specialization is good for Lagrange mappings only in general
315 // (consider that we might have a non-planar quad with non-equal
316 // vertex weights)
317 if (this->mapping_type() != LAGRANGE_MAP)
318 return this->Elem::volume();
319
320 // Make copies of our points. It makes the subsequent calculations a bit
321 // shorter and avoids dereferencing the same pointer multiple times.
322 Point
323 x0 = point(0), x1 = point(1),
324 x2 = point(2), x3 = point(3);
325
326 // Construct constant data vectors.
327 // \vec{x}_{\xi} = \vec{a1}*eta + \vec{b1}
328 // \vec{x}_{\eta} = \vec{a2}*xi + \vec{b2}
329 // This is copy-pasted directly from the output of a Python script.
330 Point
331 a1 = x0/4 - x1/4 + x2/4 - x3/4,
332 b1 = -x0/4 + x1/4 + x2/4 - x3/4,
333 a2 = a1,
334 b2 = -x0/4 - x1/4 + x2/4 + x3/4;
335
336 // Check for quick return for parallelogram QUAD4.
337 if (a1.relative_fuzzy_equals(Point(0,0,0)))
338 return 4. * b1.cross(b2).norm();
339
340 // Otherwise, use 2x2 quadrature to approximate the surface area.
341
342 // 4-point rule, exact for bi-cubics. The weights for this rule are
343 // all equal to 1.
344 const Real q[2] = {-std::sqrt(Real(3))/3, std::sqrt(Real(3))/3.};
345
346 Real vol=0.;
347 for (unsigned int i=0; i<2; ++i)
348 for (unsigned int j=0; j<2; ++j)
349 vol += cross_norm(q[j]*a1 + b1,
350 q[i]*a2 + b2);
351
352 return vol;
353}
354
360
361
362void Quad4::permute(unsigned int perm_num)
363{
364 libmesh_assert_less (perm_num, 4);
365
366 for (unsigned int i = 0; i != perm_num; ++i)
367 {
368 swap4nodes(0,1,2,3);
369 swap4neighbors(0,1,2,3);
370 }
371}
372
373
374void Quad4::flip(BoundaryInfo * boundary_info)
375{
376 libmesh_assert(boundary_info);
377
378 swap2nodes(0,1);
379 swap2nodes(2,3);
380 swap2neighbors(1,3);
381 swap2boundarysides(1,3,boundary_info);
382 swap2boundaryedges(1,3,boundary_info);
383}
384
385
386ElemType Quad4::side_type (const unsigned int libmesh_dbg_var(s)) const
387{
388 libmesh_assert_less (s, 4);
389 return EDGE2;
390}
391
392
393Point
394Quad4::side_vertex_average_normal(const unsigned int s) const
395{
396 libmesh_assert_less (s, 4);
397 libmesh_assert_equal_to(this->mapping_type(), LAGRANGE_MAP);
398 const Point side_t = this->point(side_nodes_map[s][1]) -
399 this->point(side_nodes_map[s][0]);
400
401 // At the vertex average, things simplify a bit
402 // We get the element "plane" normal at the two vertex, average them
403 Point normal;
404 for (auto i : make_range(2))
405 {
406 const int incr = (i == 0) ? -1 : 1;
407 const unsigned int other_side = (s + incr) % 4;
408 const Point other_side_t = this->point(side_nodes_map[other_side][1]) -
409 this->point(side_nodes_map[other_side][0]);
410 const auto sign = (incr < 0) ? -1 : 1;
411 const Point normal_at_vertex = sign * side_t.cross(other_side_t);
412 normal += normal_at_vertex;
413 }
414 normal /= 2;
415
416 const Point v = side_t.cross(normal);
417 return v.unit();
418}
419
420
421} // 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:2152
virtual BoundingBox loose_bounding_box() const
Definition elem.C:3498
static constexpr Real affine_tol
Default tolerance to use in has_affine_map().
Definition elem.h:2070
const Point & point(const unsigned int i) const
Definition elem.h:2462
void swap2nodes(unsigned int n1, unsigned int n2)
Swaps two node_ptrs.
Definition elem.h:2101
void swap2neighbors(unsigned int n1, unsigned int n2)
Swaps two neighbor_ptrs.
Definition elem.h:2111
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:3579
ElemMappingType mapping_type() const
Definition elem.h:3137
virtual Real volume() const
Definition elem.C:3462
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:3595
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
void swap4neighbors(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four neighbor_ptrs, "rotating" them.
Definition elem.h:2162
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
virtual Point side_vertex_average_normal(const unsigned int s) const override final
Definition face_quad4.C:394
virtual BoundingBox loose_bounding_box() const override
Builds a bounding box out of the nodal positions.
Definition face_quad4.C:356
virtual Order default_order() const override
Definition face_quad4.C:205
virtual bool is_edge(const unsigned int i) const override
Definition face_quad4.C:99
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Definition face_quad4.C:212
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
Definition face_quad4.C:119
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:206
virtual unsigned int n_sub_elem() const override
Definition face_quad4.h:78
virtual bool has_invertible_map(Real tol) const override
Definition face_quad4.C:139
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:374
static const int num_nodes
Geometric constants for Quad4.
Definition face_quad4.h:148
virtual bool is_vertex(const unsigned int i) const override
Definition face_quad4.C:93
ElemType side_type(const unsigned int s) const override final
Definition face_quad4.C:386
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
virtual bool is_face(const unsigned int i) const override
Definition face_quad4.C:104
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
Definition face_quad4.C:126
virtual void connectivity(const unsigned int sf, const IOPackage iop, std::vector< dof_id_type > &conn) const override
Definition face_quad4.C:227
static const int nodes_per_side
Definition face_quad4.h:149
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:362
virtual bool has_affine_map() const override
Definition face_quad4.C:131
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
Definition face_quad4.C:109
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 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
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
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
bool relative_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
auto norm() const
TypeVector< T > unit() const
The libMesh namespace provides an interface to certain functionality in the library.
IOPackage
libMesh interfaces with several different software packages for the purposes of creating,...
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
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:303
T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
Definition assembly.h:40
Definition assembly.h:70
Definition assembly.h:99
Definition assembly.h:203