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