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