libMesh
fe_nedelec_one.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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/dof_map.h"
22 #include "libmesh/fe.h"
23 #include "libmesh/fe_interface.h"
24 #include "libmesh/elem.h"
25 #include "libmesh/tensor_value.h"
26 #include "libmesh/enum_to_string.h"
27 
28 namespace libMesh
29 {
30 
31 // Anonymous namespace for local helper functions
32 namespace {
33 void nedelec_one_nodal_soln(const Elem * elem,
34  const Order order,
35  const std::vector<Number> & elem_soln,
36  const int dim,
37  std::vector<Number> & nodal_soln)
38 {
39  const unsigned int n_nodes = elem->n_nodes();
40  const ElemType elem_type = elem->type();
41 
42  const Order totalorder = static_cast<Order>(order+elem->p_level());
43 
44  nodal_soln.resize(n_nodes*dim);
45 
46  FEType fe_type(totalorder, NEDELEC_ONE);
47 
48  switch (totalorder)
49  {
50  case FIRST:
51  {
52  switch (elem_type)
53  {
54  case TRI6:
55  {
56  libmesh_assert_equal_to (elem_soln.size(), 3);
57  libmesh_assert_equal_to (nodal_soln.size(), 6*2);
58  break;
59  }
60  case QUAD8:
61  case QUAD9:
62  {
63  libmesh_assert_equal_to (elem_soln.size(), 4);
64 
65  if (elem_type == QUAD8)
66  libmesh_assert_equal_to (nodal_soln.size(), 8*2);
67  else
68  libmesh_assert_equal_to (nodal_soln.size(), 9*2);
69  break;
70  }
71  case TET10:
72  {
73  libmesh_assert_equal_to (elem_soln.size(), 6);
74  libmesh_assert_equal_to (nodal_soln.size(), 10*3);
75 
76  libmesh_not_implemented();
77 
78  break;
79  }
80 
81 
82  case HEX20:
83  case HEX27:
84  {
85  libmesh_assert_equal_to (elem_soln.size(), 12);
86 
87  if (elem_type == HEX20)
88  libmesh_assert_equal_to (nodal_soln.size(), 20*3);
89  else
90  libmesh_assert_equal_to (nodal_soln.size(), 27*3);
91 
92  break;
93  }
94 
95  default:
96  libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(elem_type) << " selected for NEDELEC_ONE FE family!");
97 
98  } // switch(elem_type)
99 
100  const unsigned int n_sf =
101  FEInterface::n_shape_functions(dim, fe_type, elem_type);
102 
103  std::vector<Point> refspace_nodes;
104  FEVectorBase::get_refspace_nodes(elem_type,refspace_nodes);
105  libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
106 
107 
108  // Need to create new fe object so the shape function as the FETransformation
109  // applied to it.
110  std::unique_ptr<FEVectorBase> vis_fe = FEVectorBase::build(dim,fe_type);
111 
112  const std::vector<std::vector<RealGradient>> & vis_phi = vis_fe->get_phi();
113 
114  vis_fe->reinit(elem,&refspace_nodes);
115 
116  for (unsigned int n = 0; n < n_nodes; n++)
117  {
118  libmesh_assert_equal_to (elem_soln.size(), n_sf);
119 
120  // Zero before summation
121  for (int d = 0; d < dim; d++)
122  {
123  nodal_soln[dim*n+d] = 0;
124  }
125 
126  // u = Sum (u_i phi_i)
127  for (unsigned int i=0; i<n_sf; i++)
128  {
129  for (int d = 0; d < dim; d++)
130  {
131  nodal_soln[dim*n+d] += elem_soln[i]*(vis_phi[i][n](d));
132  }
133  }
134  }
135 
136  return;
137  } // case FIRST
138 
139  default:
140  libmesh_error_msg("ERROR: Invalid total order " << Utility::enum_to_string(totalorder) << " selected for NEDELEC_ONE FE family!");
141 
142  }//switch (totalorder)
143 
144  return;
145 } // nedelec_one_nodal_soln
146 
147 
148 unsigned int nedelec_one_n_dofs(const ElemType t, const Order o)
149 {
150  switch (o)
151  {
152  case FIRST:
153  {
154  switch (t)
155  {
156  case TRI6:
157  return 3;
158 
159  case QUAD8:
160  case QUAD9:
161  return 4;
162 
163  case TET10:
164  return 6;
165 
166  case HEX20:
167  case HEX27:
168  return 12;
169 
170  case INVALID_ELEM:
171  return 0;
172 
173  default:
174  libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
175  }
176  }
177 
178  default:
179  libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for NEDELEC_ONE FE family!");
180  }
181 }
182 
183 
184 
185 
186 unsigned int nedelec_one_n_dofs_at_node(const ElemType t,
187  const Order o,
188  const unsigned int n)
189 {
190  switch (o)
191  {
192  case FIRST:
193  {
194  switch (t)
195  {
196  case TRI6:
197  {
198  switch (n)
199  {
200  case 0:
201  case 1:
202  case 2:
203  return 0;
204  case 3:
205  case 4:
206  case 5:
207  return 1;
208 
209  default:
210  libmesh_error_msg("ERROR: Invalid node ID " << n);
211  }
212  }
213  case QUAD8:
214  {
215  switch (n)
216  {
217  case 0:
218  case 1:
219  case 2:
220  case 3:
221  return 0;
222  case 4:
223  case 5:
224  case 6:
225  case 7:
226  return 1;
227 
228  default:
229  libmesh_error_msg("ERROR: Invalid node ID " << n);
230  }
231  }
232  case QUAD9:
233  {
234  switch (n)
235  {
236  case 0:
237  case 1:
238  case 2:
239  case 3:
240  case 8:
241  return 0;
242  case 4:
243  case 5:
244  case 6:
245  case 7:
246  return 1;
247 
248  default:
249  libmesh_error_msg("ERROR: Invalid node ID " << n);
250  }
251  }
252  case TET10:
253  {
254  switch (n)
255  {
256  case 0:
257  case 1:
258  case 2:
259  case 3:
260  return 0;
261  case 4:
262  case 5:
263  case 6:
264  case 7:
265  case 8:
266  case 9:
267  return 1;
268 
269  default:
270  libmesh_error_msg("ERROR: Invalid node ID " << n);
271  }
272  }
273 
274  case HEX20:
275  {
276  switch (n)
277  {
278  case 0:
279  case 1:
280  case 2:
281  case 3:
282  case 4:
283  case 5:
284  case 6:
285  case 7:
286  return 0;
287  case 8:
288  case 9:
289  case 10:
290  case 11:
291  case 12:
292  case 13:
293  case 14:
294  case 15:
295  case 16:
296  case 17:
297  case 18:
298  case 19:
299  return 1;
300 
301  default:
302  libmesh_error_msg("ERROR: Invalid node ID " << n);
303  }
304  }
305  case HEX27:
306  {
307  switch (n)
308  {
309  case 0:
310  case 1:
311  case 2:
312  case 3:
313  case 4:
314  case 5:
315  case 6:
316  case 7:
317  case 20:
318  case 21:
319  case 22:
320  case 23:
321  case 24:
322  case 25:
323  case 26:
324  return 0;
325  case 8:
326  case 9:
327  case 10:
328  case 11:
329  case 12:
330  case 13:
331  case 14:
332  case 15:
333  case 16:
334  case 17:
335  case 18:
336  case 19:
337  return 1;
338 
339  default:
340  libmesh_error_msg("ERROR: Invalid node ID " << n);
341  }
342  }
343 
344  case INVALID_ELEM:
345  return 0;
346 
347  default:
348  libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
349  }
350  }
351 
352  default:
353  libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for NEDELEC_ONE FE family!");
354  }
355 }
356 
357 
358 
359 #ifdef LIBMESH_ENABLE_AMR
360 void nedelec_one_compute_constraints (DofConstraints & /*constraints*/,
361  DofMap & /*dof_map*/,
362  const unsigned int /*variable_number*/,
363  const Elem * libmesh_dbg_var(elem),
364  const unsigned Dim)
365 {
366  // Only constrain elements in 2,3D.
367  if (Dim == 1)
368  return;
369 
370  libmesh_assert(elem);
371 
372  libmesh_not_implemented();
373 
374  /*
375  // Only constrain active and ancestor elements
376  if (elem->subactive())
377  return;
378 
379  FEType fe_type = dof_map.variable_type(variable_number);
380  fe_type.order = static_cast<Order>(fe_type.order + elem->p_level());
381 
382  std::vector<unsigned int> my_dof_indices, parent_dof_indices;
383 
384  // Look at the element faces. Check to see if we need to
385  // build constraints.
386  for (unsigned int s=0; s<elem->n_sides(); s++)
387  if (elem->neighbor(s) != nullptr)
388  if (elem->neighbor(s)->level() < elem->level()) // constrain dofs shared between
389  { // this element and ones coarser
390  // than this element.
391  // Get pointers to the elements of interest and its parent.
392  const Elem * parent = elem->parent();
393 
394  // This can't happen... Only level-0 elements have nullptr
395  // parents, and no level-0 elements can be at a higher
396  // level than their neighbors!
397  libmesh_assert(parent);
398 
399  const std::unique_ptr<const Elem> my_side (elem->build_side_ptr(s));
400  const std::unique_ptr<const Elem> parent_side (parent->build_side_ptr(s));
401 
402  // This function gets called element-by-element, so there
403  // will be a lot of memory allocation going on. We can
404  // at least minimize this for the case of the dof indices
405  // by efficiently preallocating the requisite storage.
406  my_dof_indices.reserve (my_side->n_nodes());
407  parent_dof_indices.reserve (parent_side->n_nodes());
408 
409  dof_map.dof_indices (my_side.get(), my_dof_indices,
410  variable_number);
411  dof_map.dof_indices (parent_side.get(), parent_dof_indices,
412  variable_number);
413 
414  for (unsigned int my_dof=0;
415  my_dof<FEInterface::n_dofs(Dim-1, fe_type, my_side->type());
416  my_dof++)
417  {
418  libmesh_assert_less (my_dof, my_side->n_nodes());
419 
420  // My global dof index.
421  const unsigned int my_dof_g = my_dof_indices[my_dof];
422 
423  // The support point of the DOF
424  const Point & support_point = my_side->point(my_dof);
425 
426  // Figure out where my node lies on their reference element.
427  const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type,
428  parent_side.get(),
429  support_point);
430 
431  // Compute the parent's side shape function values.
432  for (unsigned int their_dof=0;
433  their_dof<FEInterface::n_dofs(Dim-1, fe_type, parent_side->type());
434  their_dof++)
435  {
436  libmesh_assert_less (their_dof, parent_side->n_nodes());
437 
438  // Their global dof index.
439  const unsigned int their_dof_g =
440  parent_dof_indices[their_dof];
441 
442  const Real their_dof_value = FEInterface::shape(Dim-1,
443  fe_type,
444  parent_side->type(),
445  their_dof,
446  mapped_point);
447 
448  // Only add non-zero and non-identity values
449  // for Lagrange basis functions.
450  if ((std::abs(their_dof_value) > 1.e-5) &&
451  (std::abs(their_dof_value) < .999))
452  {
453  // since we may be running this method concurrently
454  // on multiple threads we need to acquire a lock
455  // before modifying the shared constraint_row object.
456  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
457 
458  // A reference to the constraint row.
459  DofConstraintRow & constraint_row = constraints[my_dof_g].first;
460 
461  constraint_row.insert(std::make_pair (their_dof_g,
462  their_dof_value));
463  }
464  #ifdef DEBUG
465  // Protect for the case u_i = 0.999 u_j,
466  // in which case i better equal j.
467  else if (their_dof_value >= .999)
468  libmesh_assert_equal_to (my_dof_g, their_dof_g);
469  #endif
470  }
471  }
472  }
473  */
474 } // nedelec_one_compute_constraints()
475 #endif // #ifdef LIBMESH_ENABLE_AMR
476 
477 } // anonymous namespace
478 
479 #define NEDELEC_LOW_D_ERROR_MESSAGE \
480  libmesh_error_msg("ERROR: This method makes no sense for low-D elements!");
481 
482 
483 // Do full-specialization for every dimension, instead
484 // of explicit instantiation at the end of this file.
485 template <>
487  const Order,
488  const std::vector<Number> &,
489  std::vector<Number> &)
490 { NEDELEC_LOW_D_ERROR_MESSAGE }
491 
492 template <>
494  const Order,
495  const std::vector<Number> &,
496  std::vector<Number> &)
497 { NEDELEC_LOW_D_ERROR_MESSAGE }
498 
499 template <>
501  const Order order,
502  const std::vector<Number> & elem_soln,
503  std::vector<Number> & nodal_soln)
504 { nedelec_one_nodal_soln(elem, order, elem_soln, 2 /*dim*/, nodal_soln); }
505 
506 template <>
508  const Order order,
509  const std::vector<Number> & elem_soln,
510  std::vector<Number> & nodal_soln)
511 { nedelec_one_nodal_soln(elem, order, elem_soln, 3 /*dim*/, nodal_soln); }
512 
513 
514 // Do full-specialization for every dimension, instead
515 // of explicit instantiation at the end of this function.
516 // This could be macro-ified.
517 template <> unsigned int FE<0,NEDELEC_ONE>::n_dofs(const ElemType, const Order) { NEDELEC_LOW_D_ERROR_MESSAGE }
518 template <> unsigned int FE<1,NEDELEC_ONE>::n_dofs(const ElemType, const Order) { NEDELEC_LOW_D_ERROR_MESSAGE }
519 template <> unsigned int FE<2,NEDELEC_ONE>::n_dofs(const ElemType t, const Order o) { return nedelec_one_n_dofs(t, o); }
520 template <> unsigned int FE<3,NEDELEC_ONE>::n_dofs(const ElemType t, const Order o) { return nedelec_one_n_dofs(t, o); }
521 
522 
523 // Do full-specialization for every dimension, instead
524 // of explicit instantiation at the end of this function.
525 template <> unsigned int FE<0,NEDELEC_ONE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { NEDELEC_LOW_D_ERROR_MESSAGE }
526 template <> unsigned int FE<1,NEDELEC_ONE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { NEDELEC_LOW_D_ERROR_MESSAGE }
527 template <> unsigned int FE<2,NEDELEC_ONE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return nedelec_one_n_dofs_at_node(t, o, n); }
528 template <> unsigned int FE<3,NEDELEC_ONE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return nedelec_one_n_dofs_at_node(t, o, n); }
529 
530 
531 // Nedelec first type elements have no dofs per element
532 // FIXME: Only for first order!
533 template <> unsigned int FE<0,NEDELEC_ONE>::n_dofs_per_elem(const ElemType, const Order) { NEDELEC_LOW_D_ERROR_MESSAGE }
534 template <> unsigned int FE<1,NEDELEC_ONE>::n_dofs_per_elem(const ElemType, const Order) { NEDELEC_LOW_D_ERROR_MESSAGE }
535 template <> unsigned int FE<2,NEDELEC_ONE>::n_dofs_per_elem(const ElemType, const Order) { return 0; }
536 template <> unsigned int FE<3,NEDELEC_ONE>::n_dofs_per_elem(const ElemType, const Order) { return 0; }
537 
538 // Nedelec first type FEMs are always tangentially continuous
539 template <> FEContinuity FE<0,NEDELEC_ONE>::get_continuity() const { NEDELEC_LOW_D_ERROR_MESSAGE }
540 template <> FEContinuity FE<1,NEDELEC_ONE>::get_continuity() const { NEDELEC_LOW_D_ERROR_MESSAGE }
543 
544 // Nedelec first type FEMs are not hierarchic
545 template <> bool FE<0,NEDELEC_ONE>::is_hierarchic() const { NEDELEC_LOW_D_ERROR_MESSAGE }
546 template <> bool FE<1,NEDELEC_ONE>::is_hierarchic() const { NEDELEC_LOW_D_ERROR_MESSAGE }
547 template <> bool FE<2,NEDELEC_ONE>::is_hierarchic() const { return false; }
548 template <> bool FE<3,NEDELEC_ONE>::is_hierarchic() const { return false; }
549 
550 // Nedelec first type FEM shapes always need to be reinit'ed (because of orientation dependence)
551 template <> bool FE<0,NEDELEC_ONE>::shapes_need_reinit() const { NEDELEC_LOW_D_ERROR_MESSAGE }
552 template <> bool FE<1,NEDELEC_ONE>::shapes_need_reinit() const { NEDELEC_LOW_D_ERROR_MESSAGE }
553 template <> bool FE<2,NEDELEC_ONE>::shapes_need_reinit() const { return true; }
554 template <> bool FE<3,NEDELEC_ONE>::shapes_need_reinit() const { return true; }
555 
556 #ifdef LIBMESH_ENABLE_AMR
557 template <>
559  DofMap &,
560  const unsigned int,
561  const Elem *)
562 { NEDELEC_LOW_D_ERROR_MESSAGE }
563 
564 template <>
566  DofMap &,
567  const unsigned int,
568  const Elem *)
569 { NEDELEC_LOW_D_ERROR_MESSAGE }
570 
571 template <>
573  DofMap & dof_map,
574  const unsigned int variable_number,
575  const Elem * elem)
576 { nedelec_one_compute_constraints(constraints, dof_map, variable_number, elem, /*Dim=*/2); }
577 
578 template <>
580  DofMap & dof_map,
581  const unsigned int variable_number,
582  const Elem * elem)
583 { nedelec_one_compute_constraints(constraints, dof_map, variable_number, elem, /*Dim=*/3); }
584 #endif // LIBMESH_ENABLE_AMR
585 
586 // Specialize useless shape function methods
587 template <>
588 RealGradient FE<0,NEDELEC_ONE>::shape(const ElemType, const Order,const unsigned int,const Point &)
589 { NEDELEC_LOW_D_ERROR_MESSAGE }
590 template <>
591 RealGradient FE<0,NEDELEC_ONE>::shape(const Elem *,const Order,const unsigned int,const Point &,const bool)
592 { NEDELEC_LOW_D_ERROR_MESSAGE }
593 template <>
595  const unsigned int,const Point &)
596 { NEDELEC_LOW_D_ERROR_MESSAGE }
597 template <>
598 RealGradient FE<0,NEDELEC_ONE>::shape_deriv(const Elem *,const Order,const unsigned int,
599  const unsigned int,const Point &,const bool)
600 { NEDELEC_LOW_D_ERROR_MESSAGE }
601 
602 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
603 template <>
605  const unsigned int,const Point &)
606 { NEDELEC_LOW_D_ERROR_MESSAGE }
607 template <>
609  const unsigned int,const Point &,const bool)
610 { NEDELEC_LOW_D_ERROR_MESSAGE }
611 
612 #endif
613 
614 template <>
615 RealGradient FE<1,NEDELEC_ONE>::shape(const ElemType, const Order,const unsigned int,const Point &)
616 { NEDELEC_LOW_D_ERROR_MESSAGE }
617 template <>
618 RealGradient FE<1,NEDELEC_ONE>::shape(const Elem *,const Order,const unsigned int,const Point &,const bool)
619 { NEDELEC_LOW_D_ERROR_MESSAGE }
620 template <>
622  const unsigned int,const Point &)
623 { NEDELEC_LOW_D_ERROR_MESSAGE }
624 template <>
625 RealGradient FE<1,NEDELEC_ONE>::shape_deriv(const Elem *,const Order,const unsigned int,
626  const unsigned int,const Point &,const bool)
627 { NEDELEC_LOW_D_ERROR_MESSAGE }
628 
629 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
630 template <>
632  const unsigned int,const Point &)
633 { NEDELEC_LOW_D_ERROR_MESSAGE }
634 template <>
636  const unsigned int,const Point &,const bool)
637 { NEDELEC_LOW_D_ERROR_MESSAGE }
638 
639 #endif
640 
641 } // namespace libMesh
libMesh::DofConstraints
The constraint matrix storage format.
Definition: dof_map.h:105
libMesh::FE::shape_second_deriv
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
libMesh::HEX20
Definition: enum_elem_type.h:48
libMesh::FEInterface::n_shape_functions
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:446
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::TET10
Definition: enum_elem_type.h:46
libMesh::Order
Order
Definition: enum_order.h:40
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::VectorValue< Real >
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::FE::shape
static OutputShape shape(const ElemType t, const Order o, const unsigned int i, const Point &p)
libMesh::HEX27
Definition: enum_elem_type.h:49
libMesh::FE::shape_deriv
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
libMesh::FEGenericBase::build
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::H_CURL
Definition: enum_fe_family.h:81
libMesh::FE::compute_constraints
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...
n_nodes
const dof_id_type n_nodes
Definition: tecplot_io.C:68
libMesh::Utility::enum_to_string
std::string enum_to_string(const T e)
libMesh::TRI6
Definition: enum_elem_type.h:40
libMesh::FE::shapes_need_reinit
virtual bool shapes_need_reinit() const override
libMesh::INVALID_ELEM
Definition: enum_elem_type.h:75
libMesh::FE::n_dofs_at_node
static unsigned int n_dofs_at_node(const ElemType t, const Order o, const unsigned int n)
libMesh::FE::nodal_soln
static void nodal_soln(const Elem *elem, const Order o, const std::vector< Number > &elem_soln, std::vector< Number > &nodal_soln)
Build the nodal soln from the element soln.
libMesh::FE::get_continuity
virtual FEContinuity get_continuity() const override
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::FE::n_dofs_per_elem
static unsigned int n_dofs_per_elem(const ElemType t, const Order o)
libMesh::NEDELEC_ONE
Definition: enum_fe_family.h:61
libMesh::FE::is_hierarchic
virtual bool is_hierarchic() const override
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::FEAbstract::get_refspace_nodes
static void get_refspace_nodes(const ElemType t, std::vector< Point > &nodes)
Definition: fe_abstract.C:308
libMesh::FE::n_dofs
static unsigned int n_dofs(const ElemType t, const Order o)
libMesh::QUAD9
Definition: enum_elem_type.h:43
libMesh::FEContinuity
FEContinuity
Definition: enum_fe_family.h:77
libMesh::FIRST
Definition: enum_order.h:42
libMesh::QUAD8
Definition: enum_elem_type.h:42
libMesh::ElemType
ElemType
Defines an enum for geometric element types.
Definition: enum_elem_type.h:33