libMesh
fe_bernstein.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/libmesh_config.h"
22 
23 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
24 
25 #include "libmesh/elem.h"
26 #include "libmesh/enum_to_string.h"
27 #include "libmesh/fe.h"
28 #include "libmesh/fe_interface.h"
29 #include "libmesh/fe_macro.h"
30 
31 namespace libMesh
32 {
33 
34 // ------------------------------------------------------------
35 // Bernstein-specific implementations, Steffen Petersen 2005
36 
37 // Anonymous namespace for local helper functions
38 namespace {
39 
40 void bernstein_nodal_soln(const Elem * elem,
41  const Order order,
42  const std::vector<Number> & elem_soln,
43  std::vector<Number> & nodal_soln,
44  const bool add_p_level)
45 {
46  const unsigned int n_nodes = elem->n_nodes();
47 
48  const ElemType elem_type = elem->type();
49 
50  nodal_soln.resize(n_nodes);
51 
52  const Order totalorder = static_cast<Order>(order + add_p_level*elem->p_level());
53 
54  // FEType object to be passed to various FEInterface functions below.
55  FEType fe_type(order, BERNSTEIN);
56 
57  switch (totalorder)
58  {
59  // Constant shape functions
60  case CONSTANT:
61  {
62  libmesh_assert_equal_to (elem_soln.size(), 1);
63 
64  const Number val = elem_soln[0];
65 
66  for (unsigned int n=0; n<n_nodes; n++)
67  nodal_soln[n] = val;
68 
69  return;
70  }
71 
72 
73  // For other bases do interpolation at the nodes
74  // explicitly.
75  case FIRST:
76  case SECOND:
77  case THIRD:
78  case FOURTH:
79  case FIFTH:
80  case SIXTH:
81  {
82  const unsigned int n_sf =
83  FEInterface::n_shape_functions(fe_type, elem);
84 
85  std::vector<Point> refspace_nodes;
86  FEBase::get_refspace_nodes(elem_type,refspace_nodes);
87  libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
88 
89  for (unsigned int n=0; n<n_nodes; n++)
90  {
91  libmesh_assert_equal_to (elem_soln.size(), n_sf);
92 
93  // Zero before summation
94  nodal_soln[n] = 0;
95 
96  // u_i = Sum (alpha_i phi_i)
97  for (unsigned int i=0; i<n_sf; i++)
98  nodal_soln[n] += elem_soln[i] *
99  FEInterface::shape(fe_type, elem, i, refspace_nodes[n]);
100  }
101 
102  return;
103  }
104 
105  default:
106  libmesh_error_msg("ERROR: Invalid total order " << totalorder);
107  }
108 } // bernstein_nodal_soln()
109 
110 
111 
112 unsigned int bernstein_n_dofs(const ElemType t, const Order o)
113 {
114  switch (t)
115  {
116  case NODEELEM:
117  return 1;
118  case EDGE2:
119  case EDGE3:
120  return (o+1);
121  case QUAD4:
122  case QUADSHELL4:
123  libmesh_assert_less (o, 2);
124  libmesh_fallthrough();
125  case QUAD8:
126  case QUADSHELL8:
127  {
128  if (o == 1)
129  return 4;
130  else if (o == 2)
131  return 8;
132  else
133  libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for BERNSTEIN FE family!");
134  }
135  case QUAD9:
136  return ((o+1)*(o+1));
137  case HEX8:
138  libmesh_assert_less (o, 2);
139  libmesh_fallthrough();
140  case HEX20:
141  {
142  if (o == 1)
143  return 8;
144  else if (o == 2)
145  return 20;
146  else
147  libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for BERNSTEIN FE family!");
148  }
149  case HEX27:
150  return ((o+1)*(o+1)*(o+1));
151  case TRI3:
152  case TRISHELL3:
153  libmesh_assert_less (o, 2);
154  libmesh_fallthrough();
155  case TRI6:
156  case TRI7:
157  return ((o+1)*(o+2)/2);
158  case TET4:
159  libmesh_assert_less (o, 2);
160  libmesh_fallthrough();
161  case TET10:
162  case TET14:
163  libmesh_assert_less (o, 3);
164  return ((o+1)*(o+2)*(o+3)/6);
165  case INVALID_ELEM:
166  return 0;
167  default:
168  libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!");
169  }
170 } // bernstein_n_dofs()
171 
172 
173 
174 
175 unsigned int bernstein_n_dofs_at_node(const ElemType t,
176  const Order o,
177  const unsigned int n)
178 {
179  switch (t)
180  {
181  case NODEELEM:
182  return 1;
183 
184  case EDGE2:
185  case EDGE3:
186  switch (n)
187  {
188  case 0:
189  case 1:
190  return 1;
191  case 2:
192  libmesh_assert (o>1);
193  return (o-1);
194  default:
195  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for EDGE2/3!");
196  }
197  case TRI3:
198  libmesh_assert_less (n, 3);
199  libmesh_assert_less (o, 2);
200  libmesh_fallthrough();
201  case TRI6:
202  // Internal DoFs are associated with the elem on a Tri6, or node 6 on a Tri7
203  libmesh_assert_less (n, 6);
204  libmesh_fallthrough();
205  case TRI7:
206  switch (n)
207  {
208  case 0:
209  case 1:
210  case 2:
211  return 1;
212 
213  case 3:
214  case 4:
215  case 5:
216  return (o-1);
217 
218  case 6:
219  return ((o-1)*(o-2)/2);
220  default:
221  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI!");
222  }
223  case QUAD4:
224  libmesh_assert_less (n, 4);
225  libmesh_assert_less (o, 2);
226  libmesh_fallthrough();
227  case QUAD8:
228  libmesh_assert_less (n, 8);
229  libmesh_assert_less (o, 3);
230  libmesh_fallthrough();
231  case QUAD9:
232  {
233  switch (n)
234  {
235  case 0:
236  case 1:
237  case 2:
238  case 3:
239  return 1;
240 
241  case 4:
242  case 5:
243  case 6:
244  case 7:
245  return (o-1);
246 
247  case 8:
248  return ((o-1)*(o-1));
249 
250  default:
251  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for QUAD9!");
252  }
253  }
254  case HEX8:
255  libmesh_assert_less (n, 8);
256  libmesh_assert_less (o, 2);
257  libmesh_fallthrough();
258  case HEX20:
259  libmesh_assert_less (n, 20);
260  libmesh_assert_less (o, 3);
261  libmesh_fallthrough();
262  case HEX27:
263  switch (n)
264  {
265  case 0:
266  case 1:
267  case 2:
268  case 3:
269  case 4:
270  case 5:
271  case 6:
272  case 7:
273  return 1;
274 
275  case 8:
276  case 9:
277  case 10:
278  case 11:
279  case 12:
280  case 13:
281  case 14:
282  case 15:
283  case 16:
284  case 17:
285  case 18:
286  case 19:
287  return (o-1);
288 
289  case 20:
290  case 21:
291  case 22:
292  case 23:
293  case 24:
294  case 25:
295  return ((o-1)*(o-1));
296 
297  case 26:
298  return ((o-1)*(o-1)*(o-1));
299 
300  default:
301  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for HEX27!");
302  }
303  case TET4:
304  libmesh_assert_less (n, 4);
305  libmesh_assert_less (o, 2);
306  libmesh_fallthrough();
307  case TET10:
308  libmesh_assert_less (n, 10);
309  libmesh_fallthrough();
310  case TET14:
311  libmesh_assert_less (o, 3);
312  switch (n)
313  {
314  case 0:
315  case 1:
316  case 2:
317  case 3:
318  return 1;
319 
320  case 4:
321  case 5:
322  case 6:
323  case 7:
324  case 8:
325  case 9:
326  return (o-1);
327 
328  case 10:
329  case 11:
330  case 12:
331  case 13:
332  return 0;
333 
334  default:
335  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TET4/10/14!");
336  }
337  case INVALID_ELEM:
338  return 0;
339  default:
340  libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!");
341  }
342 } // bernstein_n_dofs_at_node()
343 
344 
345 
346 
347 unsigned int bernstein_n_dofs_per_elem(const ElemType t, const Order o)
348 {
349  switch (t)
350  {
351  case NODEELEM:
352  case EDGE2:
353  case EDGE3:
354  return 0;
355  case TRI3:
356  case TRISHELL3:
357  case QUAD4:
358  case QUADSHELL4:
359  return 0;
360  case TRI6:
361  return ((o-1)*(o-2)/2);
362  case TRI7:
363  return 0;
364  case QUAD8:
365  case QUADSHELL8:
366  if (o <= 2)
367  return 0;
368  libmesh_fallthrough();
369  case QUAD9:
370  return 0;
371  case HEX8:
372  libmesh_assert_less (o, 2);
373  return 0;
374  case HEX20:
375  libmesh_assert_less (o, 3);
376  return 0;
377  case HEX27:
378  return 0;
379  case TET4:
380  libmesh_assert_less (o, 2);
381  libmesh_fallthrough();
382  case TET10:
383  case TET14:
384  libmesh_assert_less (o, 3);
385  return 0;
386  case INVALID_ELEM:
387  return 0;
388  default:
389  libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!");
390  }
391 } // bernstein_n_dofs_per_elem
392 
393 } // anonymous namespace
394 
395 
396 // Instantiate (side_) nodal_soln() function for every dimension
397 LIBMESH_FE_NODAL_SOLN(BERNSTEIN, bernstein_nodal_soln)
399 
400 
401 // Full specialization of n_dofs() function for every dimension
402 template <> unsigned int FE<0,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
403 template <> unsigned int FE<1,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
404 template <> unsigned int FE<2,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
405 template <> unsigned int FE<3,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
406 
407 // Full specialization of n_dofs_at_node() function for every dimension.
408 template <> unsigned int FE<0,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
409 template <> unsigned int FE<1,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
410 template <> unsigned int FE<2,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
411 template <> unsigned int FE<3,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
412 
413 // Full specialization of n_dofs_per_elem() function for every dimension.
414 template <> unsigned int FE<0,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
415 template <> unsigned int FE<1,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
416 template <> unsigned int FE<2,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
417 template <> unsigned int FE<3,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
418 
419 // Bernstein FEMs are C^0 continuous
420 template <> FEContinuity FE<0,BERNSTEIN>::get_continuity() const { return C_ZERO; }
421 template <> FEContinuity FE<1,BERNSTEIN>::get_continuity() const { return C_ZERO; }
422 template <> FEContinuity FE<2,BERNSTEIN>::get_continuity() const { return C_ZERO; }
423 template <> FEContinuity FE<3,BERNSTEIN>::get_continuity() const { return C_ZERO; }
424 
425 // Bernstein FEMs are not hierarchic
426 template <> bool FE<0,BERNSTEIN>::is_hierarchic() const { return false; }
427 template <> bool FE<1,BERNSTEIN>::is_hierarchic() const { return false; }
428 template <> bool FE<2,BERNSTEIN>::is_hierarchic() const { return false; }
429 template <> bool FE<3,BERNSTEIN>::is_hierarchic() const { return false; }
430 
431 #ifdef LIBMESH_ENABLE_AMR
432 // compute_constraints() specializations are only needed for 2 and 3D
433 template <>
435  DofMap & dof_map,
436  const unsigned int variable_number,
437  const Elem * elem)
438 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
439 
440 template <>
442  DofMap & dof_map,
443  const unsigned int variable_number,
444  const Elem * elem)
445 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
446 #endif // #ifdef LIBMESH_ENABLE_AMR
447 
448 // Bernstein shapes need reinit only for approximation orders >= 3,
449 // but we might reach that with p refinement
450 template <> bool FE<0,BERNSTEIN>::shapes_need_reinit() const { return true; }
451 template <> bool FE<1,BERNSTEIN>::shapes_need_reinit() const { return true; }
452 template <> bool FE<2,BERNSTEIN>::shapes_need_reinit() const { return true; }
453 template <> bool FE<3,BERNSTEIN>::shapes_need_reinit() const { return true; }
454 
455 } // namespace libMesh
456 
457 #endif //LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
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
libmesh_assert(ctx)
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