libMesh
fe_hermite_shape_2D.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 
19 // Local includes
20 #include "libmesh/fe.h"
21 #include "libmesh/elem.h"
22 #include "libmesh/fe_interface.h"
23 #include "libmesh/number_lookups.h"
24 #include "libmesh/enum_to_string.h"
25 
26 namespace
27 {
28 using namespace libMesh;
29 
30 // Compute the static coefficients for an element
31 void hermite_compute_coefs(const Elem * elem, std::vector<std::vector<Real>> & dxdxi
32 #ifdef DEBUG
33  , std::vector<Real> & dxdeta, std::vector<Real> & dydxi
34 #endif
35  )
36 {
37  const FEFamily mapping_family = FEMap::map_fe_type(*elem);
38  const FEType map_fe_type(elem->default_order(), mapping_family);
39 
40  // Note: we explicitly don't consider the elem->p_level() when
41  // computing the number of mapping shape functions.
42  const int n_mapping_shape_functions =
43  FEInterface::n_shape_functions (map_fe_type, /*extra_order=*/0, elem);
44 
45  static const Point dofpt[2] = {Point(-1,-1), Point(1,1)};
46 
47  FEInterface::shape_deriv_ptr shape_deriv_ptr =
48  FEInterface::shape_deriv_function(map_fe_type, elem);
49 
50  for (int p = 0; p != 2; ++p)
51  {
52  dxdxi[0][p] = 0;
53  dxdxi[1][p] = 0;
54 #ifdef DEBUG
55  dxdeta[p] = 0;
56  dydxi[p] = 0;
57 #endif
58  for (int i = 0; i != n_mapping_shape_functions; ++i)
59  {
60  const Real ddxi = shape_deriv_ptr
61  (map_fe_type, elem, i, 0, dofpt[p], /*add_p_level=*/false);
62  const Real ddeta = shape_deriv_ptr
63  (map_fe_type, elem, i, 1, dofpt[p], /*add_p_level=*/false);
64 
65  dxdxi[0][p] += elem->point(i)(0) * ddxi;
66  dxdxi[1][p] += elem->point(i)(1) * ddeta;
67  // dxdeta and dydxi should be 0!
68 #ifdef DEBUG
69  dxdeta[p] += elem->point(i)(0) * ddeta;
70  dydxi[p] += elem->point(i)(1) * ddxi;
71 #endif
72  }
73  // No singular elements!
74  libmesh_assert(dxdxi[0][p]);
75  libmesh_assert(dxdxi[1][p]);
76  // No non-rectilinear or non-axis-aligned elements!
77 #ifdef DEBUG
78  libmesh_assert_less (std::abs(dxdeta[p]), 1e-9);
79  libmesh_assert_less (std::abs(dydxi[p]), 1e-9);
80 #endif
81  }
82 }
83 
84 
85 
86 Real hermite_bases_2D (std::vector<unsigned int> & bases1D,
87  const std::vector<std::vector<Real>> & dxdxi,
88  const Order & o,
89  unsigned int i)
90 {
91  bases1D.clear();
92  bases1D.resize(2,0);
93  Real coef = 1.0;
94 
95  unsigned int e = o-3;
96 
97  // Nodes
98  if (i < 16)
99  {
100  switch (i / 4)
101  {
102  case 0:
103  break;
104  case 1:
105  bases1D[0] = 1;
106  break;
107  case 2:
108  bases1D[0] = 1;
109  bases1D[1] = 1;
110  break;
111  case 3:
112  bases1D[1] = 1;
113  break;
114  default:
115  libmesh_error_msg("Invalid basis node = " << i/4);
116  }
117 
118  unsigned int basisnum = i%4;
119  switch (basisnum)
120  {
121  case 0: // DoF = value at node
122  coef = 1.0;
123  break;
124  case 1: // DoF = x derivative at node
125  coef = dxdxi[0][bases1D[0]];
126  bases1D[0] += 2; break;
127  case 2: // DoF = y derivative at node
128  coef = dxdxi[1][bases1D[1]];
129  bases1D[1] += 2; break;
130  case 3: // DoF = xy derivative at node
131  coef = dxdxi[0][bases1D[0]] * dxdxi[1][bases1D[1]];
132  bases1D[0] += 2; bases1D[1] += 2; break;
133  default:
134  libmesh_error_msg("Invalid basisnum = " << basisnum);
135  }
136  }
137  // Edges
138  else if (i < 16 + 4*2*e)
139  {
140  unsigned int basisnum = (i - 16) % (2*e);
141  switch ((i - 16) / (2*e))
142  {
143  case 0:
144  bases1D[0] = basisnum/2 + 4;
145  bases1D[1] = basisnum%2*2;
146  if (basisnum%2)
147  coef = dxdxi[1][0];
148  break;
149  case 1:
150  bases1D[0] = basisnum%2*2 + 1;
151  bases1D[1] = basisnum/2 + 4;
152  if (basisnum%2)
153  coef = dxdxi[0][1];
154  break;
155  case 2:
156  bases1D[0] = basisnum/2 + 4;
157  bases1D[1] = basisnum%2*2 + 1;
158  if (basisnum%2)
159  coef = dxdxi[1][1];
160  break;
161  case 3:
162  bases1D[0] = basisnum%2*2;
163  bases1D[1] = basisnum/2 + 4;
164  if (basisnum%2)
165  coef = dxdxi[0][0];
166  break;
167  default:
168  libmesh_error_msg("Invalid basisnum = " << basisnum);
169  }
170  }
171  // Interior
172  else
173  {
174  unsigned int basisnum = i - 16 - 8*e;
175  bases1D[0] = square_number_row[basisnum]+4;
176  bases1D[1] = square_number_column[basisnum]+4;
177  }
178 
179  // No singular elements
180  libmesh_assert(coef);
181  return coef;
182 }
183 
184 } // end anonymous namespace
185 
186 
187 namespace libMesh
188 {
189 
190 
192 
193 
194 template <>
195 Real FE<2,HERMITE>::shape(const Elem * elem,
196  const Order order,
197  const unsigned int i,
198  const Point & p,
199  const bool add_p_level)
200 {
201  libmesh_assert(elem);
202 
203  std::vector<std::vector<Real>> dxdxi(2, std::vector<Real>(2, 0));
204 
205 #ifdef DEBUG
206  std::vector<Real> dxdeta(2), dydxi(2);
207 #endif
208 
209  hermite_compute_coefs(elem,dxdxi
210 #ifdef DEBUG
211  ,dxdeta,dydxi
212 #endif
213  );
214 
215  const ElemType type = elem->type();
216 
217  const Order totalorder =
218  order + add_p_level*elem->p_level();
219 
220  switch (type)
221  {
222  case QUAD4:
223  case QUADSHELL4:
224  libmesh_assert_less (totalorder, 4);
225  libmesh_fallthrough();
226  case QUAD8:
227  case QUADSHELL8:
228  case QUAD9:
229  case QUADSHELL9:
230  {
231  libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));
232 
233  std::vector<unsigned int> bases1D;
234 
235  Real coef = hermite_bases_2D(bases1D, dxdxi, totalorder, i);
236 
237  return coef * FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) *
238  FEHermite<1>::hermite_raw_shape(bases1D[1],p(1));
239  }
240  default:
241  libmesh_error_msg("ERROR: Unsupported element type = " << Utility::enum_to_string(type));
242  }
243 }
244 
245 
246 
247 template <>
249  const Order,
250  const unsigned int,
251  const Point &)
252 {
253  libmesh_error_msg("Hermite elements require the real element \nto construct gradient-based degrees of freedom.");
254  return 0.;
255 }
256 
257 
258 template <>
260  const Elem * elem,
261  const unsigned int i,
262  const Point & p,
263  const bool add_p_level)
264 {
265  return FE<2,HERMITE>::shape(elem, fet.order, i, p, add_p_level);
266 }
267 
268 
269 template <>
271  const Order order,
272  const unsigned int i,
273  const unsigned int j,
274  const Point & p,
275  const bool add_p_level)
276 {
277  libmesh_assert(elem);
278  libmesh_assert (j == 0 || j == 1);
279 
280  std::vector<std::vector<Real>> dxdxi(2, std::vector<Real>(2, 0));
281 
282 #ifdef DEBUG
283  std::vector<Real> dxdeta(2), dydxi(2);
284 #endif
285 
286  hermite_compute_coefs(elem,dxdxi
287 #ifdef DEBUG
288  ,dxdeta,dydxi
289 #endif
290  );
291 
292  const ElemType type = elem->type();
293 
294  const Order totalorder =
295  order + add_p_level*elem->p_level();
296 
297  switch (type)
298  {
299  case QUAD4:
300  case QUADSHELL4:
301  libmesh_assert_less (totalorder, 4);
302  libmesh_fallthrough();
303  case QUAD8:
304  case QUADSHELL8:
305  case QUAD9:
306  case QUADSHELL9:
307  {
308  libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));
309 
310  std::vector<unsigned int> bases1D;
311 
312  Real coef = hermite_bases_2D(bases1D, dxdxi, totalorder, i);
313 
314  switch (j)
315  {
316  case 0:
317  return coef *
318  FEHermite<1>::hermite_raw_shape_deriv(bases1D[0],p(0)) *
319  FEHermite<1>::hermite_raw_shape(bases1D[1],p(1));
320  case 1:
321  return coef *
322  FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) *
323  FEHermite<1>::hermite_raw_shape_deriv(bases1D[1],p(1));
324  default:
325  libmesh_error_msg("Invalid derivative index j = " << j);
326  }
327  }
328  default:
329  libmesh_error_msg("ERROR: Unsupported element type = " << Utility::enum_to_string(type));
330  }
331 }
332 
333 
334 template <>
336  const Order,
337  const unsigned int,
338  const unsigned int,
339  const Point &)
340 {
341  libmesh_error_msg("Hermite elements require the real element \nto construct gradient-based degrees of freedom.");
342  return 0.;
343 }
344 
345 
346 template <>
348  const Elem * elem,
349  const unsigned int i,
350  const unsigned int j,
351  const Point & p,
352  const bool add_p_level)
353 {
354  return FE<2,HERMITE>::shape_deriv(elem, fet.order, i, j, p, add_p_level);
355 }
356 
357 
358 
359 
360 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
361 
362 
363 template <>
365  const Order order,
366  const unsigned int i,
367  const unsigned int j,
368  const Point & p,
369  const bool add_p_level)
370 {
371  libmesh_assert(elem);
372  libmesh_assert (j == 0 || j == 1 || j == 2);
373 
374  std::vector<std::vector<Real>> dxdxi(2, std::vector<Real>(2, 0));
375 
376 #ifdef DEBUG
377  std::vector<Real> dxdeta(2), dydxi(2);
378 #endif
379 
380  hermite_compute_coefs(elem,dxdxi
381 #ifdef DEBUG
382  ,dxdeta,dydxi
383 #endif
384  );
385 
386  const ElemType type = elem->type();
387 
388  const Order totalorder =
389  order + add_p_level*elem->p_level();
390 
391  switch (type)
392  {
393  case QUAD4:
394  case QUADSHELL4:
395  libmesh_assert_less (totalorder, 4);
396  libmesh_fallthrough();
397  case QUAD8:
398  case QUADSHELL8:
399  case QUAD9:
400  case QUADSHELL9:
401  {
402  libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));
403 
404  std::vector<unsigned int> bases1D;
405 
406  Real coef = hermite_bases_2D(bases1D, dxdxi, totalorder, i);
407 
408  switch (j)
409  {
410  case 0:
411  return coef *
413  FEHermite<1>::hermite_raw_shape(bases1D[1],p(1));
414  case 1:
415  return coef *
416  FEHermite<1>::hermite_raw_shape_deriv(bases1D[0],p(0)) *
417  FEHermite<1>::hermite_raw_shape_deriv(bases1D[1],p(1));
418  case 2:
419  return coef *
420  FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) *
422  default:
423  libmesh_error_msg("Invalid derivative index j = " << j);
424  }
425  }
426  default:
427  libmesh_error_msg("ERROR: Unsupported element type = " << Utility::enum_to_string(type));
428  }
429 }
430 
431 
432 template <>
434  const Order,
435  const unsigned int,
436  const unsigned int,
437  const Point &)
438 {
439  libmesh_error_msg("Hermite elements require the real element \nto construct gradient-based degrees of freedom.");
440  return 0.;
441 }
442 
443 
444 template <>
446  const Elem * elem,
447  const unsigned int i,
448  const unsigned int j,
449  const Point & p,
450  const bool add_p_level)
451 {
452  return FE<2,HERMITE>::shape_second_deriv(elem, fet.order, i, j, p, add_p_level);
453 }
454 
455 
456 #endif
457 
458 } // namespace libMesh
Real(* shape_deriv_ptr)(const FEType fet, const Elem *elem, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level)
Typedef for pointer to a function that returns FE shape function derivative values.
Definition: fe_interface.h:648
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
ElemType
Defines an enum for geometric element types.
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
unsigned int p_level() const
Definition: elem.h:3108
OrderWrapper order
The approximation order of the element.
Definition: fe_type.h:215
The libMesh namespace provides an interface to certain functionality in the library.
static Real hermite_raw_shape_second_deriv(const unsigned int basis_num, const Real xi)
1D hermite functions on unit interval
static Real hermite_raw_shape(const unsigned int basis_num, const Real xi)
const unsigned char square_number_column[]
LIBMESH_DEFAULT_VECTORIZED_FE(template<>Real FE< 0, BERNSTEIN)
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:272
libmesh_assert(ctx)
static shape_deriv_ptr shape_deriv_function(const unsigned int dim, const FEType &fe_t, const ElemType t)
std::string enum_to_string(const T e)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const unsigned char square_number_row[]
static Real hermite_raw_shape_deriv(const unsigned int basis_num, const Real xi)
FEFamily
defines an enum for finite element families.
virtual Order default_order() const =0
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Point & point(const unsigned int i) const
Definition: elem.h:2453
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
static FEFamily map_fe_type(const Elem &elem)
Definition: fe_map.C:46