libMesh
Loading...
Searching...
No Matches
fe_hermite_shape_2D.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
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
26namespace
27{
28using namespace libMesh;
29
30// Compute the static coefficients for an element
31void 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
86Real 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
187namespace libMesh
188{
189
190
192
193
194template <>
195Real 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
247template <>
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
258template <>
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
269template <>
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 *
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)) *
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
334template <>
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
346template <>
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
363template <>
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 *
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
432template <>
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
444template <>
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
This is the base class from which all geometric element types are derived.
Definition elem.h:96
const Point & point(const unsigned int i) const
Definition elem.h:2462
virtual Order default_order() const =0
virtual ElemType type() const =0
unsigned int p_level() const
Definition elem.h:3125
static Real hermite_raw_shape(const unsigned int basis_num, const Real xi)
static Real hermite_raw_shape_deriv(const unsigned int basis_num, const Real xi)
static Real hermite_raw_shape_second_deriv(const unsigned int basis_num, const Real xi)
1D hermite functions on unit interval
static shape_deriv_ptr shape_deriv_function(const unsigned int dim, const FEType &fe_t, const ElemType t)
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.
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
static FEFamily map_fe_type(const Elem &elem)
Definition fe_map.C:46
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
OrderWrapper order
The approximation order of the element (at 0 p-refinement level).
Definition fe_type.h:203
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
LIBMESH_DEFAULT_VECTORIZED_FE(template<>Real FE< 0, BERNSTEIN)
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
const unsigned char square_number_row[]
const unsigned char square_number_column[]
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real