libMesh
fe_hierarchic.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 
20 // Local includes
21 #include "libmesh/elem.h"
22 #include "libmesh/enum_to_string.h"
23 #include "libmesh/fe.h"
24 #include "libmesh/fe_interface.h"
25 #include "libmesh/fe_macro.h"
26 
27 namespace libMesh
28 {
29 
30 // ------------------------------------------------------------
31 // Hierarchic-specific implementations
32 
33 // Anonymous namespace for local helper functions
34 namespace {
35 
36 void hierarchic_nodal_soln(const Elem * elem,
37  const Order order,
38  const std::vector<Number> & elem_soln,
39  std::vector<Number> & nodal_soln,
40  const bool add_p_level)
41 {
42  const unsigned int n_nodes = elem->n_nodes();
43 
44  const ElemType elem_type = elem->type();
45 
46  nodal_soln.resize(n_nodes);
47 
48  const Order totalorder = order + add_p_level*elem->p_level();
49 
50  // FEType object to be passed to various FEInterface functions below.
51  FEType fe_type(order, HIERARCHIC);
52 
53  switch (totalorder)
54  {
55  // Constant shape functions
56  case CONSTANT:
57  {
58  libmesh_assert_equal_to (elem_soln.size(), 1);
59 
60  std::fill(nodal_soln.begin(), nodal_soln.end(), elem_soln[0]);
61 
62  return;
63  }
64 
65 
66  // For other orders do interpolation at the nodes
67  // explicitly.
68  default:
69  {
70  const unsigned int n_sf =
71  FEInterface::n_shape_functions(fe_type, elem);
72 
73  std::vector<Point> refspace_nodes;
74  FEBase::get_refspace_nodes(elem_type,refspace_nodes);
75  libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
76  libmesh_assert_equal_to (elem_soln.size(), n_sf);
77 
78  // Zero before summation
79  std::fill(nodal_soln.begin(), nodal_soln.end(), 0);
80 
81  for (unsigned int n=0; n<n_nodes; n++)
82  // u_i = Sum (alpha_i phi_i)
83  for (unsigned int i=0; i<n_sf; i++)
84  nodal_soln[n] += elem_soln[i] *
85  FEInterface::shape(fe_type, elem, i, refspace_nodes[n]);
86 
87  return;
88  }
89  }
90 } // hierarchic_nodal_soln()
91 
92 
93 
94 unsigned int HIERARCHIC_n_dofs(const ElemType t, const Order o)
95 {
96  libmesh_assert_greater (o, 0);
97  switch (t)
98  {
99  case NODEELEM:
100  return 1;
101  case EDGE2:
102  case EDGE3:
103  return (o+1);
104  case QUAD4:
105  case QUADSHELL4:
106  libmesh_assert_less (o, 2);
107  libmesh_fallthrough();
108  case QUAD8:
109  case QUADSHELL8:
110  case QUAD9:
111  case QUADSHELL9:
112  return ((o+1)*(o+1));
113  case HEX8:
114  case HEX20:
115  libmesh_assert_less (o, 2);
116  libmesh_fallthrough();
117  case HEX27:
118  return ((o+1)*(o+1)*(o+1));
119  case PRISM6:
120  case PRISM15:
121  libmesh_assert_less (o, 2);
122  libmesh_fallthrough();
123  case PRISM18:
124  libmesh_assert_less (o, 3);
125  libmesh_fallthrough();
126  case PRISM20:
127  case PRISM21:
128  return ((o+1)*(o+1)*(o+2)/2);
129  case TRI3:
130  libmesh_assert_less (o, 2);
131  libmesh_fallthrough();
132  case TRI6:
133  case TRI7:
134  return ((o+1)*(o+2)/2);
135  case TET4:
136  libmesh_assert_less (o, 2);
137  libmesh_fallthrough();
138  case TET10:
139  libmesh_assert_less (o, 3);
140  libmesh_fallthrough();
141  case TET14:
142  return ((o+1)*(o+2)*(o+3)/6);
143  case INVALID_ELEM:
144  return 0;
145  default:
146  libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for HIERARCHIC FE family!");
147  }
148 } // HIERARCHIC_n_dofs()
149 
150 
151 
152 unsigned int HIERARCHIC_n_dofs(const Elem * e, const Order o)
153 {
154  libmesh_assert(e);
155  return HIERARCHIC_n_dofs(e->type(), o);
156 }
157 
158 
159 
160 unsigned int HIERARCHIC_n_dofs_at_node(const ElemType t,
161  const Order o,
162  const unsigned int n)
163 {
164  libmesh_assert_greater (o, 0);
165  switch (t)
166  {
167  case NODEELEM:
168  return 1;
169  case EDGE2:
170  case EDGE3:
171  switch (n)
172  {
173  case 0:
174  case 1:
175  return 1;
176  // Internal DoFs are associated with the elem, not its nodes
177  case 2:
178  libmesh_assert_equal_to(t, EDGE3);
179  return 0;
180  default:
181  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for EDGE2/3!");
182  }
183  case TRI3:
184  libmesh_assert_less (n, 3);
185  libmesh_assert_less (o, 2);
186  libmesh_fallthrough();
187  case TRI6:
188  // Internal DoFs are associated with the elem on a Tri6, or node 6 on a Tri7
189  libmesh_assert_less (n, 6);
190  libmesh_fallthrough();
191  case TRI7:
192  switch (n)
193  {
194  case 0:
195  case 1:
196  case 2:
197  return 1;
198 
199  case 3:
200  case 4:
201  case 5:
202  return (o-1);
203 
204  case 6:
205  return ((o-1)*(o-2)/2);
206  default:
207  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI!");
208  }
209  case QUAD4:
210  case QUADSHELL4:
211  libmesh_assert_less (n, 4);
212  libmesh_assert_less (o, 2);
213  libmesh_fallthrough();
214  case QUAD8:
215  case QUADSHELL8:
216  case QUAD9:
217  case QUADSHELL9:
218  switch (n)
219  {
220  case 0:
221  case 1:
222  case 2:
223  case 3:
224  return 1;
225 
226  case 4:
227  case 5:
228  case 6:
229  case 7:
230  return (o-1);
231 
232  // Internal DoFs are associated with the elem, not its nodes
233  case 8:
234  return 0;
235 
236  default:
237  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for QUAD4/8/9!");
238  }
239  case HEX8:
240  libmesh_assert_less (n, 8);
241  libmesh_assert_less (o, 2);
242  libmesh_fallthrough();
243  case HEX20:
244  libmesh_assert_less (n, 20);
245  libmesh_assert_less (o, 2);
246  libmesh_fallthrough();
247  case HEX27:
248  switch (n)
249  {
250  case 0:
251  case 1:
252  case 2:
253  case 3:
254  case 4:
255  case 5:
256  case 6:
257  case 7:
258  return 1;
259 
260  case 8:
261  case 9:
262  case 10:
263  case 11:
264  case 12:
265  case 13:
266  case 14:
267  case 15:
268  case 16:
269  case 17:
270  case 18:
271  case 19:
272  return (o-1);
273 
274  case 20:
275  case 21:
276  case 22:
277  case 23:
278  case 24:
279  case 25:
280  return ((o-1)*(o-1));
281 
282  // Internal DoFs are associated with the elem, not its nodes
283  case 26:
284  return 0;
285  default:
286  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for HEX8/20/27!");
287  }
288 
289  case PRISM6:
290  libmesh_assert_less (n, 6);
291  libmesh_fallthrough();
292  case PRISM15:
293  libmesh_assert_less (n, 15);
294  libmesh_assert_less (o, 2);
295  libmesh_fallthrough();
296  case PRISM18:
297  libmesh_assert_less (n, 18);
298  libmesh_assert_less (o, 3);
299  libmesh_fallthrough();
300  case PRISM20:
301  // Internal DoFs are associated with the elem on a Prism20, or
302  // node 20 on a Prism21
303  libmesh_assert_less (n, 20);
304  libmesh_fallthrough();
305  case PRISM21:
306  libmesh_assert_less (n, 21);
307  switch (n)
308  {
309  case 0:
310  case 1:
311  case 2:
312  case 3:
313  case 4:
314  case 5:
315  return 1;
316 
317  case 6:
318  case 7:
319  case 8:
320  case 9:
321  case 10:
322  case 11:
323  case 12:
324  case 13:
325  case 14:
326  return (o-1);
327 
328  case 15:
329  case 16:
330  case 17:
331  return ((o-1)*(o-1));
332 
333  case 18:
334  case 19:
335  return ((o-1)*(o-2)/2);
336  case 20:
337  return ((o-1)*(o-1)*(o-2)/2);
338  default:
339  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI!");
340  }
341 
342  case TET4:
343  libmesh_assert_less (o, 2);
344  libmesh_assert_less (n, 4);
345  libmesh_fallthrough();
346  case TET10:
347  libmesh_assert_less (o, 3);
348  libmesh_assert_less (n, 10);
349  libmesh_fallthrough();
350  case TET14:
351  libmesh_assert_less (n, 14);
352  switch (n)
353  {
354  case 0:
355  case 1:
356  case 2:
357  case 3:
358  return 1;
359 
360  case 4:
361  case 5:
362  case 6:
363  case 7:
364  case 8:
365  case 9:
366  return (o-1);
367 
368  case 10:
369  case 11:
370  case 12:
371  case 13:
372  return ((o-1)*(o-2)/2);
373 
374  default:
375  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TET!");
376  }
377 
378 
379  case INVALID_ELEM:
380  return 0;
381 
382  default:
383  libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
384  }
385 } // HIERARCHIC_n_dofs_at_node()
386 
387 
388 
389 unsigned int HIERARCHIC_n_dofs_at_node(const Elem & e,
390  const Order o,
391  const unsigned int n)
392 {
393  return HIERARCHIC_n_dofs_at_node(e.type(), o, n);
394 }
395 
396 
397 
398 unsigned int HIERARCHIC_n_dofs_per_elem(const ElemType t,
399  const Order o)
400 {
401  libmesh_assert_greater (o, 0);
402  switch (t)
403  {
404  case NODEELEM:
405  return 0;
406  case EDGE2:
407  case EDGE3:
408  return (o-1);
409  case TRI3:
410  case TRISHELL3:
411  case QUAD4:
412  case QUADSHELL4:
413  return 0;
414  case TRI6:
415  return ((o-1)*(o-2)/2);
416  case TRI7:
417  return 0;
418  case QUAD8:
419  case QUADSHELL8:
420  case QUAD9:
421  case QUADSHELL9:
422  return ((o-1)*(o-1));
423  case HEX8:
424  case HEX20:
425  libmesh_assert_less (o, 2);
426  return 0;
427  case HEX27:
428  return ((o-1)*(o-1)*(o-1));
429  case PRISM6:
430  case PRISM15:
431  libmesh_assert_less (o, 2);
432  libmesh_fallthrough();
433  case PRISM18:
434  libmesh_assert_less (o, 3);
435  return 0;
436  case PRISM20:
437  return ((o-1)*(o-1)*(o-2)/2);
438  case PRISM21: // Store interior DoFs on interior node
439  return 0;
440  case TET4:
441  libmesh_assert_less (o, 2);
442  libmesh_fallthrough();
443  case TET10:
444  libmesh_assert_less (o, 3);
445  libmesh_fallthrough();
446  case TET14:
447  return ((o-3)*(o-2)*(o-1)/6);
448  case INVALID_ELEM:
449  return 0;
450  default:
451  libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
452  }
453 } // HIERARCHIC_n_dofs_per_elem()
454 
455 
456 
457 unsigned int HIERARCHIC_n_dofs_per_elem(const Elem & e,
458  const Order o)
459 {
460  return HIERARCHIC_n_dofs_per_elem(e.type(), o);
461 }
462 
463 } // anonymous namespace
464 
465 
466 // Instantiate (side_) nodal_soln() function for every dimension
467 LIBMESH_FE_NODAL_SOLN(HIERARCHIC, hierarchic_nodal_soln)
469 
470 
471 // Instantiate n_dofs*() functions for every dimension
472 LIBMESH_DEFAULT_NDOFS(HIERARCHIC)
473 
474 
475 // Hierarchic FEMs are C^0 continuous
476 template <> FEContinuity FE<0,HIERARCHIC>::get_continuity() const { return C_ZERO; }
477 template <> FEContinuity FE<1,HIERARCHIC>::get_continuity() const { return C_ZERO; }
478 template <> FEContinuity FE<2,HIERARCHIC>::get_continuity() const { return C_ZERO; }
479 template <> FEContinuity FE<3,HIERARCHIC>::get_continuity() const { return C_ZERO; }
480 
481 // Hierarchic FEMs are hierarchic (duh!)
482 template <> bool FE<0,HIERARCHIC>::is_hierarchic() const { return true; }
483 template <> bool FE<1,HIERARCHIC>::is_hierarchic() const { return true; }
484 template <> bool FE<2,HIERARCHIC>::is_hierarchic() const { return true; }
485 template <> bool FE<3,HIERARCHIC>::is_hierarchic() const { return true; }
486 
487 #ifdef LIBMESH_ENABLE_AMR
488 // compute_constraints() specializations are only needed for 2 and 3D
489 template <>
491  DofMap & dof_map,
492  const unsigned int variable_number,
493  const Elem * elem)
494 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
495 
496 template <>
498  DofMap & dof_map,
499  const unsigned int variable_number,
500  const Elem * elem)
501 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
502 #endif // #ifdef LIBMESH_ENABLE_AMR
503 
504 // Hierarchic FEM shapes need reinit
505 template <> bool FE<0,HIERARCHIC>::shapes_need_reinit() const { return true; }
506 template <> bool FE<1,HIERARCHIC>::shapes_need_reinit() const { return true; }
507 template <> bool FE<2,HIERARCHIC>::shapes_need_reinit() const { return true; }
508 template <> bool FE<3,HIERARCHIC>::shapes_need_reinit() const { return true; }
509 
510 } // namespace libMesh
ElemType
Defines an enum for geometric element types.
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
virtual bool shapes_need_reinit() const override
The libMesh namespace provides an interface to certain functionality in the library.
LIBMESH_FE_NODAL_SOLN(LIBMESH_FE_SIDE_NODAL_SOLN() LIBMESH_DEFAULT_NDOFS(BERNSTEIN) template<> FEContinuity FE< 0 BERNSTEIN, bernstein_nodal_soln)
Definition: fe_bernstein.C:415
virtual bool is_hierarchic() const override
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
LIBMESH_FE_SIDE_NODAL_SOLN(HIERARCHIC_VEC)
const dof_id_type n_nodes
Definition: tecplot_io.C:67
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:272
static Real shape(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const Point &p)
Definition: fe_interface.C:760
static void get_refspace_nodes(const ElemType t, std::vector< Point > &nodes)
Definition: fe_abstract.C:400
libmesh_assert(ctx)
virtual FEContinuity get_continuity() const override
std::string enum_to_string(const T e)
static void compute_constraints(DofConstraints &constraints, DofMap &dof_map, const unsigned int variable_number, const Elem *elem)
Computes the constraint matrix contributions (for non-conforming adapted meshes) corresponding to var...
FEContinuity
defines an enum for finite element types to libmesh_assert a certain level (or type? Hcurl?) of continuity.
The constraint matrix storage format.
Definition: dof_map.h:108