libMesh
edge_edge4.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 
19 
20 // Local includes
21 #include "libmesh/edge_edge4.h"
22 #include "libmesh/enum_io_package.h"
23 #include "libmesh/enum_order.h"
24 
25 namespace libMesh
26 {
27 
28 // Edge4 class static member initializations
29 const int Edge4::num_nodes;
30 const int Edge4::num_sides;
31 const int Edge4::num_edges;
32 const int Edge4::num_children;
33 const int Edge4::nodes_per_side;
34 const int Edge4::nodes_per_edge;
35 
36 #ifdef LIBMESH_ENABLE_AMR
37 
39  {
40  // embedding matrix for child 0
41 
42  {
43  // 0 1 2 3 // Shape function index
44  {1.0, 0.0, 0.0, 0.0}, // left, xi = -1
45  {-0.0625, -0.0625, 0.5625, 0.5625}, // right, xi = 0
46  {0.3125, 0.0625, 0.9375, -0.3125}, // middle left, xi = -2/3
47  {0.0, 0.0, 1.0, 0.0} // middle right, xi = -1/3
48  },
49 
50  // embedding matrix for child 1
51  {
52  // 0 1 2 3 // Shape function index
53  {-0.0625, -0.0625, 0.5625, 0.5625}, // left, xi = 0
54  {0.0, 1.0, 0.0, 0.0}, // right, xi = 1
55  {0.0, 0.0, 0.0, 1.0}, // middle left, xi = 1/3
56  {0.0625, 0.3125, -0.3125, 0.9375} // middle right, xi = 2/3
57  }
58  };
59 
60 #endif
61 
62 bool Edge4::is_vertex(const unsigned int i) const
63 {
64  return (i==0) || (i==1);
65 }
66 
67 bool Edge4::is_edge(const unsigned int i) const
68 {
69  return (i==2) || (i==3);
70 }
71 
72 bool Edge4::is_face(const unsigned int ) const
73 {
74  return false;
75 }
76 
77 bool Edge4::is_node_on_side(const unsigned int n,
78  const unsigned int s) const
79 {
80  libmesh_assert_less (s, 2);
81  libmesh_assert_less (n, Edge4::num_nodes);
82  return (s == n);
83 }
84 
85 bool Edge4::is_node_on_edge(const unsigned int,
86  const unsigned int libmesh_dbg_var(e)) const
87 {
88  libmesh_assert_equal_to (e, 0);
89  return true;
90 }
91 
92 
93 
95 {
96  Point v = this->point(1) - this->point(0);
98  ((this->point(2) - this->point(0))*3, affine_tol))
99  return false;
100  if (!v.relative_fuzzy_equals
101  ((this->point(3) - this->point(0))*1.5, affine_tol))
102  return false;
103  return true;
104 }
105 
106 
107 
109 {
110  // At the moment this only makes sense for Lagrange elements
111  libmesh_assert_equal_to(this->mapping_type(), LAGRANGE_MAP);
112 
113  // dx/dxi = a*xi^2 + b*xi + c,
114  // where a, b, and c are vector quantities that depend on the
115  // nodal positions as follows:
116  const Point & x0 = this->point(0);
117  const Point & x1 = this->point(1);
118  const Point & x2 = this->point(2);
119  const Point & x3 = this->point(3);
120 
121  Point a = Real(27)/16 * (x1 - x0 + 3*(x2 - x3));
122  Point b = Real(18)/16 * (x0 + x1 - x2 - x3);
123  Point c = Real(1)/16 * (x0 - x1 + 27*(x3 - x2));
124 
125  // Normalized midpoint value of Jacobian. If c==0, then dx/dxi(0) =
126  // 0 and the Jacobian is either zero on the whole element, or
127  // changes sign within the element. Either way, the element is not
128  // invertible. Note: use <= tol, so that if someone passes 0 for tol
129  // it still works.
130  Real c_norm = c.norm();
131  if (c_norm <= tol)
132  return false;
133 
134  // Coefficients of the quadratic scalar function
135  // j(xi) := dot(c.unit(), dx/dxi)
136  // = alpha*xi^2 + beta*xi + gamma
137  Real alpha = (a * c) / c_norm;
138  Real beta = (b * c) / c_norm;
139  Real gamma = c_norm;
140 
141  // If alpha and beta are both (approximately) zero, then the
142  // Jacobian is actually constant but it's not zero (as we already
143  // checked) so the element is invertible!
144  if ((std::abs(alpha) <= tol) && (std::abs(beta) <= tol))
145  return true;
146 
147  // If alpha is approximately zero, but beta is not, then j(xi) is
148  // actually linear and the Jacobian changes sign at the point xi =
149  // -gamma/beta, so we need to check whether that's in the
150  // element.
151  if (std::abs(alpha) <= tol)
152  {
153  // Debugging:
154  // libMesh::out << "alpha = " << alpha << ", std::abs(alpha) <= tol" << std::endl;
155 
156  Real xi_0 = -gamma / beta;
157  return ((xi_0 < -1.) || (xi_0 > 1.));
158  }
159 
160  // If alpha is not (approximately) zero, then j(xi) is quadratic
161  // and we need to solve for the roots.
162  Real sqrt_term = beta*beta - 4*alpha*gamma;
163 
164  // Debugging:
165  // libMesh::out << "sqrt_term = " << sqrt_term << std::endl;
166 
167  // If the term under the square root is negative, then the roots are
168  // imaginary and the element is invertible.
169  if (sqrt_term < 0)
170  return true;
171 
172  sqrt_term = std::sqrt(sqrt_term);
173  Real
174  xi_1 = 0.5 * (-beta + sqrt_term) / alpha,
175  xi_2 = 0.5 * (-beta - sqrt_term) / alpha;
176 
177  // libMesh::out << "xi_1 = " << xi_1 << std::endl;
178  // libMesh::out << "xi_2 = " << xi_2 << std::endl;
179 
180  // If a root is outside the reference element, it is "OK".
181  bool
182  xi_1_ok = ((xi_1 < -1.) || (xi_1 > 1.)),
183  xi_2_ok = ((xi_2 < -1.) || (xi_2 > 1.));
184 
185  // If both roots are OK, the element is invertible.
186  return xi_1_ok && xi_2_ok;
187 }
188 
189 
190 
192 {
193  return THIRD;
194 }
195 
196 
197 
198 void Edge4::connectivity(const unsigned int sc,
199  const IOPackage iop,
200  std::vector<dof_id_type> & conn) const
201 {
202  libmesh_assert_less_equal (sc, 2);
203  libmesh_assert_less (sc, this->n_sub_elem());
204  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
205 
206  // Create storage
207  conn.resize(2);
208 
209  switch(iop)
210  {
211  case TECPLOT:
212  {
213  switch (sc)
214  {
215  case 0:
216  conn[0] = this->node_id(0)+1;
217  conn[1] = this->node_id(2)+1;
218  return;
219 
220  case 1:
221  conn[0] = this->node_id(2)+1;
222  conn[1] = this->node_id(3)+1;
223  return;
224 
225  case 2:
226  conn[0] = this->node_id(3)+1;
227  conn[1] = this->node_id(1)+1;
228  return;
229 
230  default:
231  libmesh_error_msg("Invalid sc = " << sc);
232  }
233 
234  }
235 
236  case VTK:
237  {
238 
239  switch (sc)
240  {
241  case 0:
242  conn[0] = this->node_id(0);
243  conn[1] = this->node_id(2);
244  return;
245 
246  case 1:
247  conn[0] = this->node_id(2);
248  conn[1] = this->node_id(3);
249  return;
250 
251  case 2:
252  conn[0] = this->node_id(3);
253  conn[1] = this->node_id(1);
254  return;
255 
256  default:
257  libmesh_error_msg("Invalid sc = " << sc);
258  }
259  }
260 
261  default:
262  libmesh_error_msg("Unsupported IO package " << iop);
263  }
264 }
265 
266 
267 
269 {
270  // This might be a curved line through 2-space or 3-space, in which
271  // case the full bounding box can be larger than the bounding box of
272  // just the nodes.
273  //
274  // FIXME - I haven't yet proven the formula below to be correct for
275  // cubics - RHS
276  Point pmin, pmax;
277 
278  for (unsigned d=0; d<LIBMESH_DIM; ++d)
279  {
280  Real center = (this->point(2)(d) + this->point(3)(d))/2;
281  Real hd = std::max(std::abs(center - this->point(0)(d)),
282  std::abs(center - this->point(1)(d)));
283 
284  pmin(d) = center - hd;
285  pmax(d) = center + hd;
286  }
287 
288  return BoundingBox(pmin, pmax);
289 }
290 
291 
292 
294 {
295  return this->compute_key(this->node_id(0),
296  this->node_id(1),
297  this->node_id(2),
298  this->node_id(3));
299 }
300 
301 
302 
304 {
305  // Make copies of our points. It makes the subsequent calculations a bit
306  // shorter and avoids dereferencing the same pointer multiple times.
307  Point
308  x0 = point(0),
309  x1 = point(1),
310  x2 = point(2),
311  x3 = point(3);
312 
313  // Construct constant data vectors.
314  // \vec{x}_{\xi} = \vec{a1}*xi**2 + \vec{b1}*xi + \vec{c1}
315  // This is copy-pasted directly from the output of a Python script.
316  Point
317  a1 = -27*x0/16 + 27*x1/16 + 81*x2/16 - 81*x3/16,
318  b1 = 9*x0/8 + 9*x1/8 - 9*x2/8 - 9*x3/8,
319  c1 = x0/16 - x1/16 - 27*x2/16 + 27*x3/16;
320 
321  // 4 point quadrature, 7th-order accurate
322  const unsigned int N = 4;
323  const Real q[N] = {-std::sqrt(525 + 70*std::sqrt(30.)) / 35,
324  -std::sqrt(525 - 70*std::sqrt(30.)) / 35,
325  std::sqrt(525 - 70*std::sqrt(30.)) / 35,
326  std::sqrt(525 + 70*std::sqrt(30.)) / 35};
327  const Real w[N] = {(18 - std::sqrt(30.)) / 36,
328  (18 + std::sqrt(30.)) / 36,
329  (18 + std::sqrt(30.)) / 36,
330  (18 - std::sqrt(30.)) / 36};
331 
332  Real vol=0.;
333  for (unsigned int i=0; i<N; ++i)
334  vol += w[i] * (q[i]*q[i]*a1 + q[i]*b1 + c1).norm();
335 
336  return vol;
337 }
338 
339 
340 void Edge4::flip(BoundaryInfo * boundary_info)
341 {
342  swap2nodes(0,1);
343  swap2nodes(2,3);
344  swap2neighbors(0,1);
345  swap2boundarysides(0,1,boundary_info);
346 }
347 
348 
349 } // namespace libMesh
static const int num_children
Definition: edge_edge4.h:197
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
Definition: edge_edge4.C:77
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
virtual void connectivity(const unsigned int sc, const IOPackage iop, std::vector< dof_id_type > &conn) const override
Definition: edge_edge4.C:198
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:929
virtual BoundingBox loose_bounding_box() const override
Definition: edge_edge4.C:268
virtual bool is_edge(const unsigned int i) const override
Definition: edge_edge4.C:67
static const int num_nodes
Geometric constants for Edge4.
Definition: edge_edge4.h:194
IOPackage
libMesh interfaces with several different software packages for the purposes of creating, reading, and writing mesh files.
virtual dof_id_type key() const override
Definition: edge_edge4.C:293
virtual bool is_face(const unsigned int i) const override
Definition: edge_edge4.C:72
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
static const int num_edges
Definition: edge_edge4.h:196
virtual void flip(BoundaryInfo *) override final
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
Definition: edge_edge4.C:340
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.
static const int num_sides
Definition: edge_edge4.h:195
virtual bool has_invertible_map(Real tol) const override
Definition: edge_edge4.C:108
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
Definition: type_vector.h:57
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 nodes_per_edge
Definition: edge_edge4.h:199
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
static const int nodes_per_side
Definition: edge_edge4.h:198
static constexpr Real affine_tol
Default tolerance to use in has_affine_map().
Definition: elem.h:1902
static const Real _embedding_matrix[num_children][num_nodes][num_nodes]
Matrix that computes new nodal locations/solution values from current nodes/solution.
Definition: edge_edge4.h:226
void swap2neighbors(unsigned int n1, unsigned int n2)
Swaps two neighbor_ptrs.
Definition: elem.h:1943
Defines a Cartesian bounding box by the two corner extremum.
Definition: bounding_box.h:40
virtual unsigned int n_sub_elem() const override
Definition: edge_edge4.h:84
virtual Real volume() const override
An optimized method for approximating the length of an EDGE4 using quadrature.
Definition: edge_edge4.C:303
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual bool is_vertex(const unsigned int i) const override
Definition: edge_edge4.C:62
virtual bool has_affine_map() const override
Definition: edge_edge4.C:94
virtual Order default_order() const override
Definition: edge_edge4.C:191
static dof_id_type compute_key(dof_id_type n0)
Definition: elem.h:3131
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const override
Definition: edge_edge4.C:85
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
uint8_t dof_id_type
Definition: id_types.h:67