Loading [MathJax]/extensions/tex2jax.js
libMesh
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
face_quad.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/face_quad.h"
20 #include "libmesh/edge_edge2.h"
21 #include "libmesh/face_quad4.h"
22 #include "libmesh/enum_elem_quality.h"
23 
24 // C++ includes
25 #include <array>
26 
27 
28 namespace libMesh
29 {
30 
31 // ------------------------------------------------------------
32 // Quad class static member initializations
33 const int Quad::num_sides;
34 const int Quad::num_children;
35 
36 // Note: we can omit initialization of the third entry of each row because
37 // static variables are automatically zero-initialized.
38 const Real Quad::_master_points[9][3] =
39  {
40  {-1, -1},
41  {1, -1},
42  {1, 1},
43  {-1, 1},
44  {0, -1},
45  {1, 0},
46  {0, 1},
47  {-1, 0},
48  {0, 0}
49  };
50 
51 const unsigned int Quad::adjacent_sides_map[/*num_vertices*/4][/*n_adjacent_sides*/2] =
52  {
53  {0, 3}, // Sides adjacent to node 0
54  {0, 1}, // Sides adjacent to node 1
55  {1, 2}, // Sides adjacent to node 2
56  {2, 3} // Sides adjacent to node 3
57  };
58 
59 
60 
61 // ------------------------------------------------------------
62 // Quad class member functions
63 dof_id_type Quad::key (const unsigned int s) const
64 {
65  libmesh_assert_less (s, this->n_sides());
66 
67  return this->compute_key(this->node_id(Quad4::side_nodes_map[s][0]),
68  this->node_id(Quad4::side_nodes_map[s][1]));
69 }
70 
71 
72 
73 dof_id_type Quad::low_order_key (const unsigned int s) const
74 {
75  libmesh_assert_less (s, this->n_sides());
76 
77  return this->compute_key(this->node_id(Quad4::side_nodes_map[s][0]),
78  this->node_id(Quad4::side_nodes_map[s][1]));
79 }
80 
81 
82 
83 unsigned int Quad::local_side_node(unsigned int side,
84  unsigned int side_node) const
85 {
86  libmesh_assert_less (side, this->n_sides());
87  libmesh_assert_less (side_node, Quad4::nodes_per_side);
88 
89  return Quad4::side_nodes_map[side][side_node];
90 }
91 
92 
93 
94 unsigned int Quad::local_edge_node(unsigned int edge,
95  unsigned int edge_node) const
96 {
97  return local_side_node(edge, edge_node);
98 }
99 
100 
101 
103 {
104  return this->compute_key(this->node_id(0),
105  this->node_id(1),
106  this->node_id(2),
107  this->node_id(3));
108 }
109 
110 
111 
112 std::unique_ptr<Elem> Quad::side_ptr (const unsigned int i)
113 {
114  libmesh_assert_less (i, this->n_sides());
115 
116  std::unique_ptr<Elem> edge = std::make_unique<Edge2>();
117 
118  for (auto n : edge->node_index_range())
119  edge->set_node(n) = this->node_ptr(Quad4::side_nodes_map[i][n]);
120 
121  return edge;
122 }
123 
124 
125 
126 void Quad::side_ptr (std::unique_ptr<Elem> & side,
127  const unsigned int i)
128 {
129  this->simple_side_ptr<Quad,Quad4>(side, i, EDGE2);
130 }
131 
132 
133 
134 bool Quad::is_child_on_side(const unsigned int c,
135  const unsigned int s) const
136 {
137  libmesh_assert_less (c, this->n_children());
138  libmesh_assert_less (s, this->n_sides());
139 
140  // A quad's children and nodes don't share the same ordering:
141  // child 2 and 3 are swapped;
142  unsigned int n = (c < 2) ? c : 5-c;
143  return (n == s || n == (s+1)%4);
144 }
145 
146 
147 
148 unsigned int Quad::opposite_side(const unsigned int side_in) const
149 {
150  libmesh_assert_less (side_in, 4);
151 
152  return (side_in + 2) % 4;
153 }
154 
155 
156 
157 unsigned int Quad::opposite_node(const unsigned int node_in,
158  const unsigned int side_in) const
159 {
160  libmesh_assert_less (node_in, 8);
161  libmesh_assert_less (node_in, this->n_nodes());
162  libmesh_assert_less (side_in, this->n_sides());
163  libmesh_assert(this->is_node_on_side(node_in, side_in));
164 
165  static const unsigned char side02_nodes_map[] =
166  {3, 2, 1, 0, 6, 255, 4, 255};
167  static const unsigned char side13_nodes_map[] =
168  {1, 0, 3, 2, 255, 7, 255, 5};
169 
170  switch (side_in)
171  {
172  case 0:
173  case 2:
174  return side02_nodes_map[node_in];
175  case 1:
176  case 3:
177  return side13_nodes_map[node_in];
178  default:
179  libmesh_error_msg("Unsupported side_in = " << side_in);
180  }
181 }
182 
183 
184 bool Quad::is_flipped() const
185 {
186  return (
187 #if LIBMESH_DIM > 2
188  // Don't bother outside the XY plane
189  !this->point(0)(2) && !this->point(1)(2) &&
190  !this->point(2)(2) && !this->point(3)(2) &&
191 #endif
192  ((this->point(1)(0)-this->point(0)(0))*
193  (this->point(3)(1)-this->point(0)(1)) <
194  (this->point(3)(0)-this->point(0)(0))*
195  (this->point(1)(1)-this->point(0)(1))));
196 }
197 
198 
199 std::vector<unsigned int>
200 Quad::edges_adjacent_to_node(const unsigned int n) const
201 {
202  libmesh_assert_less(n, this->n_nodes());
203 
204  // For vertices, we use the Quad::adjacent_sides_map, otherwise each
205  // of the mid-edge nodes is adjacent only to the edge it is on, and the
206  // center node is not adjacent to any edge.
207  if (this->is_vertex(n))
208  return {std::begin(adjacent_sides_map[n]), std::end(adjacent_sides_map[n])};
209  else if (this->is_edge(n))
210  return {n - this->n_vertices()};
211 
212  libmesh_assert(this->is_face(n));
213  return {};
214 }
215 
217 {
218  switch (q)
219  {
220  // The EDGE_LENGTH_RATIO metric is handled by the base class.
221  //
222  // The CUBIT 15.1 User Documentation refers to the
223  // EDGE_LENGTH_RATIO as the "Aspect Ratio" metric for Quads,
224  // however, we prefer the slightly more robust aspect ratio
225  // formula employed by Ansys, and have therefore designated that
226  // as our ASPECT_RATIO metric here.
227  //
228  // As a counter-example for employing the EDGE_LENGTH_RATIO in
229  // Quads, consider a "rhombus". All four side lengths are equal,
230  // so the EDGE_LENGTH_RATIO of this element is always (the
231  // optimal value) 1.0, regardless of the internal angle "theta"
232  // of the rhombus. A more sensitive shape quality metric should
233  // take this internal angle into account, so that very thin
234  // rhombus-shaped Quads are not considered optimal.
235 
236  case ASPECT_RATIO:
237  {
238  // Aspect Ratio definition from Ansys Theory Manual.
239  // Reference: Ansys, Inc. Theory Reference, Ansys Release 9.0, 2004 (Chapter: 13.7.3)
240  //
241  // For the rhombus case described above, the aspect ratio of
242  // the element using the Ansys Aspect Ratio metric is
243  // 1/sin(theta), where theta is the acute interior angle of
244  // the rhombus. The aspect ratio therefore has a minimum value
245  // of 1.0 (when theta = pi/2), and blows up to infinity as
246  // sin(theta) -> 0, rather than remaining equal to 1.0 as in
247  // the CUBIT formula.
248 
249  // Compute midpoint positions along each edge
250  Point m0 = 0.5 * (this->point(0) + this->point(1));
251  Point m1 = 0.5 * (this->point(1) + this->point(2));
252  Point m2 = 0.5 * (this->point(2) + this->point(3));
253  Point m3 = 0.5 * (this->point(3) + this->point(0));
254 
255  // Compute vectors adjoining opposite side midpoints
256  Point v0 = m2 - m0;
257  Point v1 = m1 - m3;
258 
259  // Compute the length of the midlines
260  Real v0_norm = v0.norm();
261  Real v1_norm = v1.norm();
262 
263  // Instead of dividing by zero in the next step, just return
264  // 0. The optimal aspect ratio is 1.0, and "high" aspect
265  // ratios are bad, but an aspect ratio of 0 should also be
266  // considered bad.
267  if (v0_norm == 0. || v1_norm == 0.)
268  return 0.;
269 
270  // Compute sine of the angle between v0, v1. For rectangular
271  // elements, sin_theta == 1.
272  Real sin_theta = cross_norm(v0, v1) / v0_norm / v1_norm;
273  Real v0s = v0_norm*sin_theta;
274  Real v1s = v1_norm*sin_theta;
275 
276  // Determine the min, max of each midline length and its
277  // projection.
278  //
279  // Note: The return values min{0,1} and max{0,1} here are
280  // *references* and we cannot pass a temporary to
281  // std::minmax() since the reference returned becomes a
282  // dangling reference at "the end of the full expression that
283  // contains the call to std::minmax()"
284  // https://en.cppreference.com/w/cpp/algorithm/minmax
285  auto [min0, max0] = std::minmax(v0_norm, v1s);
286  auto [min1, max1] = std::minmax(v0s, v1_norm);
287 
288  // Return the max of the two quotients
289  return std::max(max0/min0, max1/min1);
290  }
291 
292  // Compute the min/max diagonal ratio.
293  // This is modeled after the Hex element
294  case DISTORTION:
295  case DIAGONAL:
296  {
297  // Diagonal between node 0 and node 2
298  const Real d02 = this->length(0,2);
299 
300  // Diagonal between node 1 and node 3
301  const Real d13 = this->length(1,3);
302 
303  // Find the biggest and smallest diagonals
304  if ((d02 > 0.) && (d13 >0.))
305  if (d02 < d13) return d02 / d13;
306  else return d13 / d02;
307  else
308  return 0.;
309  break;
310  }
311 
312  // CUBIT 15.1 User Documentation:
313  // Stretch: Sqrt(2) * minimum edge length / maximum diagonal length
314  case STRETCH:
315  {
316  Real lengths[4] = {this->length(0,1), this->length(1,2), this->length(2,3), this->length(3,0)};
317  Real min_edge = *std::min_element(lengths, lengths+4);
318  Real d_max = std::max(this->length(0,2), this->length(1,3));
319 
320  // Return 0. instead of dividing by zero.
321  if (d_max == 0.)
322  return 0.;
323  else
324  return std::sqrt(2) * min_edge / d_max;
325  }
326 
327  case SHAPE:
328  case SKEW:
329  {
330  // From: P. Knupp, "Algebraic mesh quality metrics for
331  // unstructured initial meshes," Finite Elements in Analysis
332  // and Design 39, 2003, p. 217-241, Sections 5.2 and 5.3.
333  typedef std::array<Real, 4> Array4;
334  typedef std::array<Real, 6> Array6;
335 
336  // x, y, z node coordinates.
337  std::vector<Real>
338  x = {this->point(0)(0), this->point(1)(0), this->point(2)(0), this->point(3)(0)},
339  y = {this->point(0)(1), this->point(1)(1), this->point(2)(1), this->point(3)(1)},
340  z = {this->point(0)(2), this->point(1)(2), this->point(2)(2), this->point(3)(2)};
341 
342  // Nodal Jacobians. These are 3x2 matrices, hence we represent
343  // them by Array6.
344  std::array<Array6, 4> A;
345  for (unsigned int k=0; k<4; ++k)
346  {
347  unsigned int
348  kp1 = k+1 > 3 ? k+1-4 : k+1,
349  kp3 = k+3 > 3 ? k+3-4 : k+3;
350 
351  // To initialize std::array we need double curly braces in
352  // C++11 but not C++14 apparently.
353  A[k] = {{x[kp1] - x[k], x[kp3] - x[k],
354  y[kp1] - y[k], y[kp3] - y[k],
355  z[kp1] - z[k], z[kp3] - z[k]}};
356  }
357 
358  // Compute metric tensors, T_k = A_k^T * A_k. These are 2x2
359  // square matrices, hence we represent them by Array4.
360  std::array<Array4, 4> T;
361  for (unsigned int k=0; k<4; ++k)
362  {
363  Real
364  top_left = A[k][0]*A[k][0] + A[k][2]*A[k][2] + A[k][4]*A[k][4],
365  off_diag = A[k][0]*A[k][1] + A[k][2]*A[k][3] + A[k][4]*A[k][5],
366  bot_rigt = A[k][1]*A[k][1] + A[k][3]*A[k][3] + A[k][5]*A[k][5];
367 
368  T[k] = {{top_left, off_diag,
369  off_diag, bot_rigt}};
370  }
371 
372 
373  // Nodal areas. These are approximated as sqrt(det(A^T * A))
374  // to handle the general case of a 2D element living in 3D.
375  Array4 alpha;
376  for (unsigned int k=0; k<4; ++k)
377  alpha[k] = std::sqrt(T[k][0]*T[k][3] - T[k][1]*T[k][2]);
378 
379  // All nodal areas must be strictly positive. Return 0 (the
380  // lowest quality) otherwise. We know they can't be negative
381  // because they are the result of a sqrt, but they might be
382  // identically 0.
383  if (*std::min_element(alpha.begin(), alpha.end()) == 0.)
384  return 0.;
385 
386  // Compute and return the shape metric. These only use the
387  // diagonal entries of the T_k.
388  Real den = 0.;
389  if (q == SHAPE)
390  {
391  for (unsigned int k=0; k<4; ++k)
392  den += (T[k][0] + T[k][3]) / alpha[k];
393  return (den == 0.) ? 0 : (8. / den);
394  }
395  else
396  {
397  for (unsigned int k=0; k<4; ++k)
398  den += std::sqrt(T[k][0] * T[k][3]) / alpha[k];
399  return (den == 0.) ? 0 : (4. / den);
400  }
401  }
402 
403  // This test returns 0 if a Quad:
404  // 1) Is "twisted" (i.e. has an invalid numbering)
405  // 2) Has nearly parallel adjacent edges
406  // 3) Has a nearly zero length edge
407  // Otherwise, it returns 1.
408  case TWIST:
409  {
410  // Compute the cross product induced by each "corner" of the QUAD
411  // and check that:
412  // 1) None of the cross products are zero (within a tolernace), and
413  // 2) all of the cross products point in the same direction.
414 
415  // Corner 0
416  Point vec_01 = point(1) - point(0);
417  Point vec_03 = point(3) - point(0);
418  Point corner_0_vec = vec_01.cross(vec_03);
419 
420  // Corner 1
421  Point vec_12 = point(2) - point(1);
422  Point vec_10 = point(0) - point(1);
423  Point corner_1_vec = vec_12.cross(vec_10);
424 
425  // Corner 2
426  Point vec_23 = point(3) - point(2);
427  Point vec_21 = point(1) - point(2);
428  Point corner_2_vec = vec_23.cross(vec_21);
429 
430  // Corner 3
431  Point vec_30 = point(0) - point(3);
432  Point vec_32 = point(2) - point(3);
433  Point corner_3_vec = vec_30.cross(vec_32);
434 
435  // If any of these cross products is nearly zero, then either
436  // we have nearly parallel adjacent edges or a nearly zero
437  // length edge. We return 0 in this case.
438  if ((corner_0_vec.norm() < TOLERANCE*TOLERANCE) ||
439  (corner_1_vec.norm() < TOLERANCE*TOLERANCE) ||
440  (corner_2_vec.norm() < TOLERANCE*TOLERANCE) ||
441  (corner_3_vec.norm() < TOLERANCE*TOLERANCE))
442  {
443  return 0.;
444  }
445 
446  // Now check whether the element is twisted.
447  Real dot_01 = corner_0_vec * corner_1_vec;
448  Real dot_02 = corner_0_vec * corner_2_vec;
449  Real dot_03 = corner_0_vec * corner_3_vec;
450 
451  if ((dot_01 <= 0.) || (dot_02 <= 0.) || (dot_03 <= 0.))
452  return 0.;
453 
454  // If we made it here, then Elem is not twisted.
455  return 1.;
456  }
457 
458  case WARP:
459  {
460  // We compute the angle between the two planes formed by
461  // drawing an imaginary diagonal separating opposite vertices
462  // A and B, where (A,B) = (0,2) and (1,3). The element warpage
463  // is then taken to be the smaller of these two angles. For a
464  // flat quadrilateral, the planes are parallel, thus the angle
465  // between them is zero, and the element warpage is therefore
466  // 1.
467  //
468  // Reference: https://cubit.sandia.gov/files/cubit/16.08/help_manual/WebHelp/mesh_generation/mesh_quality_assessment/quadrilateral_metrics.htm
469  Point
470  n0 = (this->point(1) - this->point(0)).cross(this->point(3) - this->point(0)).unit(),
471  n1 = (this->point(2) - this->point(1)).cross(this->point(0) - this->point(1)).unit(),
472  n2 = (this->point(3) - this->point(2)).cross(this->point(1) - this->point(2)).unit(),
473  n3 = (this->point(0) - this->point(3)).cross(this->point(2) - this->point(3)).unit();
474 
475  return std::min(n0*n2, n1*n3);
476  }
477 
478  default:
479  return Elem::quality(q);
480  }
481 }
482 
483 
484 
485 
486 
487 
488 std::pair<Real, Real> Quad::qual_bounds (const ElemQuality q) const
489 {
490  std::pair<Real, Real> bounds;
491 
492  switch (q)
493  {
494  case EDGE_LENGTH_RATIO:
495  case ASPECT_RATIO:
496  bounds.first = 1.;
497  bounds.second = 4.;
498  break;
499 
500  case TAPER:
501  bounds.first = 0.;
502  bounds.second = 0.7;
503  break;
504 
505  case WARP:
506  bounds.first = 0.9;
507  bounds.second = 1.;
508  break;
509 
510  case STRETCH:
511  bounds.first = 0.25;
512  bounds.second = 1.;
513  break;
514 
515  case MIN_ANGLE:
516  bounds.first = 45.;
517  bounds.second = 90.;
518  break;
519 
520  case MAX_ANGLE:
521  bounds.first = 90.;
522  bounds.second = 135.;
523  break;
524 
525  case CONDITION:
526  bounds.first = 1.;
527  bounds.second = 4.;
528  break;
529 
530  case JACOBIAN:
531  case SCALED_JACOBIAN:
532  bounds.first = 0.5;
533  bounds.second = 1.;
534  break;
535 
536  case SHEAR:
537  case SHAPE:
538  case SKEW:
539  case SIZE:
540  bounds.first = 0.3;
541  bounds.second = 1.;
542  break;
543 
544  case DISTORTION:
545  bounds.first = 0.6;
546  bounds.second = 1.;
547  break;
548 
549  case TWIST:
550  bounds.first = 0.;
551  bounds.second = 1.;
552  break;
553 
554  default:
555  libMesh::out << "Warning: Invalid quality measure chosen." << std::endl;
556  bounds.first = -1;
557  bounds.second = -1;
558  }
559 
560  return bounds;
561 }
562 
563 
564 
566  const Real eps) const
567 {
568  const Real & xi = p(0);
569  const Real & eta = p(1);
570 
571  // The reference quadrilateral element is [-1,1]^2.
572  return ((xi >= -1.-eps) &&
573  (xi <= 1.+eps) &&
574  (eta >= -1.-eps) &&
575  (eta <= 1.+eps));
576 }
577 
578 
579 
580 const unsigned short int Quad::_second_order_adjacent_vertices[4][2] =
581  {
582  {0, 1}, // vertices adjacent to node 4
583  {1, 2}, // vertices adjacent to node 5
584  {2, 3}, // vertices adjacent to node 6
585  {0, 3} // vertices adjacent to node 7
586  };
587 
588 
589 
590 const unsigned short int Quad::_second_order_vertex_child_number[9] =
591  {
592  99,99,99,99, // Vertices
593  0,1,2,0, // Edges
594  0 // Interior
595  };
596 
597 
598 
599 const unsigned short int Quad::_second_order_vertex_child_index[9] =
600  {
601  99,99,99,99, // Vertices
602  1,2,3,3, // Edges
603  2 // Interior
604  };
605 
606 
607 
608 #ifdef LIBMESH_ENABLE_AMR
609 
610 // We number 25 "possible node locations" for a 2x2 refinement of
611 // quads with up to 3x3 nodes each
612 const int Quad::_child_node_lookup[4][9] =
613  {
614  // node lookup for child 0 (near node 0)
615  { 0, 2, 12, 10, 1, 7, 11, 5, 6},
616 
617  // node lookup for child 1 (near node 1)
618  { 2, 4, 14, 12, 3, 9, 13, 7, 8},
619 
620  // node lookup for child 2 (near node 3)
621  { 10, 12, 22, 20, 11, 17, 21, 15, 16},
622 
623  // node lookup for child 3 (near node 2)
624  { 12, 14, 24, 22, 13, 19, 23, 17, 18}
625  };
626 
627 
628 #endif
629 
630 } // namespace libMesh
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
Definition: face_quad.C:488
virtual bool is_flipped() const override final
Definition: face_quad.C:184
virtual unsigned int n_vertices() const override final
Definition: face_quad.h:102
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:907
virtual bool is_face(const unsigned int i) const =0
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:153
static const int _child_node_lookup[4][9]
Lookup table from child id, child node id to "possible node location" (a simple dictionary-index in a...
Definition: face_quad.h:245
static constexpr Real TOLERANCE
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 std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
Definition: face_quad.C:112
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
virtual dof_id_type key() const override
Definition: face_quad.C:102
static const Real _master_points[9][3]
Master element node locations.
Definition: face_quad.h:239
The libMesh namespace provides an interface to certain functionality in the library.
virtual unsigned int n_children() const override final
Definition: face_quad.h:112
Real length(const unsigned int n1, const unsigned int n2) const
Definition: elem.C:613
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
libmesh_assert(ctx)
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
Definition: face_quad.C:200
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
ElemQuality
Defines an enum for element quality metrics.
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
Definition: face_quad.C:83
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
Definition: type_vector.h:884
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 Real quality(const ElemQuality q) const override
Definition: face_quad.C:216
static const int nodes_per_side
Definition: face_quad4.h:147
virtual dof_id_type low_order_key(const unsigned int s) const override
Definition: face_quad.C:73
virtual unsigned int n_sides() const override final
Definition: face_quad.h:97
static const int num_sides
Geometric constants for Quad4.
Definition: face_quad.h:85
static const unsigned int adjacent_sides_map[4][2]
This maps the node to the (in this case) 2 side ids adjacent to the node.
Definition: face_quad.h:254
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2444
virtual bool is_vertex(const unsigned int i) const =0
OStreamProxy out
virtual Real quality(const ElemQuality q) const
Definition: elem.C:1645
virtual unsigned int opposite_side(const unsigned int s) const override final
Definition: face_quad.C:148
virtual unsigned int opposite_node(const unsigned int n, const unsigned int s) const override final
Definition: face_quad.C:157
virtual unsigned int n_nodes() const override
Definition: face_quad.h:92
static dof_id_type compute_key(dof_id_type n0)
Definition: elem.h:3244
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
Definition: face_quad.C:565
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
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Calls local_side_node(edge, edge_node).
Definition: face_quad.C:94
virtual bool is_edge(const unsigned int i) const =0
static const int num_children
Definition: face_quad.h:86
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override final
Definition: face_quad.C:134
uint8_t dof_id_type
Definition: id_types.h:67