libMesh
fe_hierarchic.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/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 = static_cast<Order>(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  const Number val = elem_soln[0];
61 
62  for (unsigned int n=0; n<n_nodes; n++)
63  nodal_soln[n] = val;
64 
65  return;
66  }
67 
68 
69  // For other orders do interpolation at the nodes
70  // explicitly.
71  default:
72  {
73  const unsigned int n_sf =
74  FEInterface::n_shape_functions(fe_type, elem);
75 
76  std::vector<Point> refspace_nodes;
77  FEBase::get_refspace_nodes(elem_type,refspace_nodes);
78  libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
79 
80  for (unsigned int n=0; n<n_nodes; n++)
81  {
82  libmesh_assert_equal_to (elem_soln.size(), n_sf);
83 
84  // Zero before summation
85  nodal_soln[n] = 0;
86 
87  // u_i = Sum (alpha_i phi_i)
88  for (unsigned int i=0; i<n_sf; i++)
89  nodal_soln[n] += elem_soln[i] *
90  FEInterface::shape(fe_type, elem, i, refspace_nodes[n]);
91  }
92 
93  return;
94  }
95  }
96 } // hierarchic_nodal_soln()
97 
98 
99 
100 
101 unsigned int hierarchic_n_dofs(const ElemType t, const Order o)
102 {
103  libmesh_assert_greater (o, 0);
104  switch (t)
105  {
106  case NODEELEM:
107  return 1;
108  case EDGE2:
109  case EDGE3:
110  return (o+1);
111  case QUAD4:
112  case QUADSHELL4:
113  libmesh_assert_less (o, 2);
114  libmesh_fallthrough();
115  case QUAD8:
116  case QUADSHELL8:
117  case QUAD9:
118  return ((o+1)*(o+1));
119  case HEX8:
120  libmesh_assert_less (o, 2);
121  libmesh_fallthrough();
122  case HEX20:
123  libmesh_assert_less (o, 2);
124  libmesh_fallthrough();
125  case HEX27:
126  return ((o+1)*(o+1)*(o+1));
127  case PRISM6:
128  case PRISM15:
129  libmesh_assert_less (o, 2);
130  libmesh_fallthrough();
131  case PRISM18:
132  libmesh_assert_less (o, 3);
133  libmesh_fallthrough();
134  case PRISM20:
135  case PRISM21:
136  return ((o+1)*(o+1)*(o+2)/2);
137  case TRI3:
138  libmesh_assert_less (o, 2);
139  libmesh_fallthrough();
140  case TRI6:
141  case TRI7:
142  return ((o+1)*(o+2)/2);
143  case TET4:
144  libmesh_assert_less (o, 2);
145  libmesh_fallthrough();
146  case TET10:
147  libmesh_assert_less (o, 3);
148  libmesh_fallthrough();
149  case TET14:
150  return ((o+1)*(o+2)*(o+3)/6);
151  case INVALID_ELEM:
152  return 0;
153  default:
154  libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for HIERARCHIC FE family!");
155  }
156 } // hierarchic_n_dofs()
157 
158 
159 
160 
161 unsigned int hierarchic_n_dofs_at_node(const ElemType t,
162  const Order o,
163  const unsigned int n)
164 {
165  libmesh_assert_greater (o, 0);
166  switch (t)
167  {
168  case NODEELEM:
169  return 1;
170  case EDGE2:
171  case EDGE3:
172  switch (n)
173  {
174  case 0:
175  case 1:
176  return 1;
177  // Internal DoFs are associated with the elem, not its nodes
178  case 2:
179  libmesh_assert_equal_to(t, EDGE3);
180  return 0;
181  default:
182  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for EDGE2/3!");
183  }
184  case TRI3:
185  libmesh_assert_less (n, 3);
186  libmesh_assert_less (o, 2);
187  libmesh_fallthrough();
188  case TRI6:
189  // Internal DoFs are associated with the elem on a Tri6, or node 6 on a Tri7
190  libmesh_assert_less (n, 6);
191  libmesh_fallthrough();
192  case TRI7:
193  switch (n)
194  {
195  case 0:
196  case 1:
197  case 2:
198  return 1;
199 
200  case 3:
201  case 4:
202  case 5:
203  return (o-1);
204 
205  case 6:
206  return ((o-1)*(o-2)/2);
207  default:
208  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI!");
209  }
210  case QUAD4:
211  case QUADSHELL4:
212  libmesh_assert_less (n, 4);
213  libmesh_assert_less (o, 2);
214  libmesh_fallthrough();
215  case QUAD8:
216  case QUADSHELL8:
217  case QUAD9:
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 
390 unsigned int hierarchic_n_dofs_per_elem(const ElemType t,
391  const Order o)
392 {
393  libmesh_assert_greater (o, 0);
394  switch (t)
395  {
396  case NODEELEM:
397  return 0;
398  case EDGE2:
399  case EDGE3:
400  return (o-1);
401  case TRI3:
402  case TRISHELL3:
403  case QUAD4:
404  case QUADSHELL4:
405  return 0;
406  case TRI6:
407  return ((o-1)*(o-2)/2);
408  case TRI7:
409  return 0;
410  case QUAD8:
411  case QUADSHELL8:
412  case QUAD9:
413  return ((o-1)*(o-1));
414  case HEX8:
415  case HEX20:
416  libmesh_assert_less (o, 2);
417  return 0;
418  case HEX27:
419  return ((o-1)*(o-1)*(o-1));
420  case PRISM6:
421  case PRISM15:
422  libmesh_assert_less (o, 2);
423  libmesh_fallthrough();
424  case PRISM18:
425  libmesh_assert_less (o, 3);
426  return 0;
427  case PRISM20:
428  return ((o-1)*(o-1)*(o-2)/2);
429  case PRISM21: // Store interior DoFs on interior node
430  return 0;
431  case TET4:
432  libmesh_assert_less (o, 2);
433  libmesh_fallthrough();
434  case TET10:
435  libmesh_assert_less (o, 3);
436  libmesh_fallthrough();
437  case TET14:
438  return ((o-3)*(o-2)*(o-1)/6);
439  case INVALID_ELEM:
440  return 0;
441  default:
442  libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
443  }
444 } // hierarchic_n_dofs_per_elem()
445 
446 } // anonymous namespace
447 
448 
449 // Instantiate (side_) nodal_soln() function for every dimension
450 LIBMESH_FE_NODAL_SOLN(HIERARCHIC, hierarchic_nodal_soln)
452 
453 
454 // Full specialization of n_dofs() function for every dimension
455 template <> unsigned int FE<0,HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return hierarchic_n_dofs(t, o); }
456 template <> unsigned int FE<1,HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return hierarchic_n_dofs(t, o); }
457 template <> unsigned int FE<2,HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return hierarchic_n_dofs(t, o); }
458 template <> unsigned int FE<3,HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return hierarchic_n_dofs(t, o); }
459 
460 // Full specialization of n_dofs_at_node() function for every dimension.
461 template <> unsigned int FE<0,HIERARCHIC>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hierarchic_n_dofs_at_node(t, o, n); }
462 template <> unsigned int FE<1,HIERARCHIC>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hierarchic_n_dofs_at_node(t, o, n); }
463 template <> unsigned int FE<2,HIERARCHIC>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hierarchic_n_dofs_at_node(t, o, n); }
464 template <> unsigned int FE<3,HIERARCHIC>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hierarchic_n_dofs_at_node(t, o, n); }
465 
466 // Full specialization of n_dofs_per_elem() function for every dimension.
467 template <> unsigned int FE<0,HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return hierarchic_n_dofs_per_elem(t, o); }
468 template <> unsigned int FE<1,HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return hierarchic_n_dofs_per_elem(t, o); }
469 template <> unsigned int FE<2,HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return hierarchic_n_dofs_per_elem(t, o); }
470 template <> unsigned int FE<3,HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return hierarchic_n_dofs_per_elem(t, o); }
471 
472 // Hierarchic FEMs are C^0 continuous
473 template <> FEContinuity FE<0,HIERARCHIC>::get_continuity() const { return C_ZERO; }
474 template <> FEContinuity FE<1,HIERARCHIC>::get_continuity() const { return C_ZERO; }
475 template <> FEContinuity FE<2,HIERARCHIC>::get_continuity() const { return C_ZERO; }
476 template <> FEContinuity FE<3,HIERARCHIC>::get_continuity() const { return C_ZERO; }
477 
478 // Hierarchic FEMs are hierarchic (duh!)
479 template <> bool FE<0,HIERARCHIC>::is_hierarchic() const { return true; }
480 template <> bool FE<1,HIERARCHIC>::is_hierarchic() const { return true; }
481 template <> bool FE<2,HIERARCHIC>::is_hierarchic() const { return true; }
482 template <> bool FE<3,HIERARCHIC>::is_hierarchic() const { return true; }
483 
484 #ifdef LIBMESH_ENABLE_AMR
485 // compute_constraints() specializations are only needed for 2 and 3D
486 template <>
488  DofMap & dof_map,
489  const unsigned int variable_number,
490  const Elem * elem)
491 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
492 
493 template <>
495  DofMap & dof_map,
496  const unsigned int variable_number,
497  const Elem * elem)
498 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
499 #endif // #ifdef LIBMESH_ENABLE_AMR
500 
501 // Hierarchic FEM shapes need reinit
502 template <> bool FE<0,HIERARCHIC>::shapes_need_reinit() const { return true; }
503 template <> bool FE<1,HIERARCHIC>::shapes_need_reinit() const { return true; }
504 template <> bool FE<2,HIERARCHIC>::shapes_need_reinit() const { return true; }
505 template <> bool FE<3,HIERARCHIC>::shapes_need_reinit() const { return true; }
506 
507 } // namespace libMesh
static unsigned int n_dofs(const ElemType t, const Order o)
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
static unsigned int n_dofs_at_node(const ElemType t, const Order o, const unsigned int n)
virtual bool shapes_need_reinit() const override
The libMesh namespace provides an interface to certain functionality in the library.
virtual bool is_hierarchic() const override
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:169
LIBMESH_FE_NODAL_SOLN(BERNSTEIN, bernstein_nodal_soln)
Definition: fe_bernstein.C:397
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:515
static Real shape(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const Point &p)
static void get_refspace_nodes(const ElemType t, std::vector< Point > &nodes)
Definition: fe_abstract.C:373
static unsigned int n_dofs_per_elem(const ElemType t, const Order o)
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:98