libMesh
fe.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/fe.h"
23 #include "libmesh/fe_interface.h"
24 #include "libmesh/fe_macro.h"
25 #include "libmesh/libmesh_logging.h"
26 #include "libmesh/quadrature.h"
27 #include "libmesh/tensor_value.h"
28 #include "libmesh/enum_elem_type.h"
29 #include "libmesh/quadrature_gauss.h"
30 #include "libmesh/libmesh_singleton.h"
31 
32 namespace {
33  // Put this outside a templated class, so we only get 1 warning
34  // during our unit tests, not 1 warning for each of the zillion FE
35  // specializations we test.
36  void nonlagrange_dual_warning () {
37  libmesh_warning("dual calculations have only been verified for the LAGRANGE family");
38  }
39 }
40 
41 
42 namespace libMesh
43 {
44 // ------------------------------------------------------------
45 // Whether we cache the node locations, edge and face orientations of the last
46 // element we computed on as needed to avoid calling init_shape_functions and
47 // compute_shape_functions
48 static const bool * caching = nullptr;
49 
51 {
52  private:
53  void setup() { caching = new bool(!on_command_line("--disable-caching")); }
54  public:
55  ~CachingSetup() { delete caching; caching = nullptr; }
57 
58 
59 // ------------------------------------------------------------
60 // FE class members
61 template <unsigned int Dim, FEFamily T>
62 FE<Dim,T>::FE (const FEType & fet) :
63  FEGenericBase<typename FEOutputType<T>::type> (Dim,fet),
64  last_side(INVALID_ELEM),
65  last_edge(INVALID_ELEM)
66 {
67  // Sanity check. Make sure the
68  // Family specified in the template instantiation
69  // matches the one in the FEType object
70  libmesh_assert_equal_to (T, this->get_family());
71 }
72 
73 
74 template <unsigned int Dim, FEFamily T>
75 unsigned int FE<Dim,T>::n_shape_functions () const
76 {
77  if (this->_elem)
78  return this->n_dofs (this->_elem,
79  this->fe_type.order + this->_p_level);
80 
81  return this->n_dofs (this->get_type(),
82  this->fe_type.order + this->_p_level);
83 }
84 
85 
86 template <unsigned int Dim, FEFamily T>
88 {
89  libmesh_assert(q);
90  this->qrule = q;
91  // make sure we don't cache results from a previous quadrature rule
92  this->_elem = nullptr;
93  this->_elem_type = INVALID_ELEM;
94  return;
95 }
96 
97 
98 template <unsigned int Dim, FEFamily T>
99 void FE<Dim,T>::dofs_on_side(const Elem * const elem,
100  const Order o,
101  unsigned int s,
102  std::vector<unsigned int> & di,
103  const bool add_p_level)
104 {
105  libmesh_assert(elem);
106  libmesh_assert_less (s, elem->n_sides());
107 
108  di.clear();
109  unsigned int nodenum = 0;
110  const unsigned int n_nodes = elem->n_nodes();
111  for (unsigned int n = 0; n != n_nodes; ++n)
112  {
113  const unsigned int n_dofs =
114  n_dofs_at_node(*elem, static_cast<Order>(o + add_p_level*elem->p_level()), n);
115  if (elem->is_node_on_side(n, s))
116  for (unsigned int i = 0; i != n_dofs; ++i)
117  di.push_back(nodenum++);
118  else
119  nodenum += n_dofs;
120  }
121 }
122 
123 
124 
125 template <unsigned int Dim, FEFamily T>
126 void FE<Dim,T>::dofs_on_edge(const Elem * const elem,
127  const Order o,
128  unsigned int e,
129  std::vector<unsigned int> & di,
130  const bool add_p_level)
131 {
132  libmesh_assert(elem);
133  libmesh_assert_less (e, elem->n_edges());
134 
135  di.clear();
136  unsigned int nodenum = 0;
137  const unsigned int n_nodes = elem->n_nodes();
138  for (unsigned int n = 0; n != n_nodes; ++n)
139  {
140  const unsigned int n_dofs =
141  n_dofs_at_node(*elem, static_cast<Order>(o + add_p_level*elem->p_level()), n);
142  if (elem->is_node_on_edge(n, e))
143  for (unsigned int i = 0; i != n_dofs; ++i)
144  di.push_back(nodenum++);
145  else
146  nodenum += n_dofs;
147  }
148 }
149 
150 
151 
152 template <unsigned int Dim, FEFamily T>
153 void FE<Dim,T>::cache(const Elem * elem)
154 {
155  cached_nodes.resize(elem->n_nodes());
156  for (auto n : elem->node_index_range())
157  cached_nodes[n] = elem->point(n);
158 
159  if (FEInterface::orientation_dependent(T))
160  {
161  cached_edges.resize(elem->n_edges());
162  for (auto n : elem->edge_index_range())
163  cached_edges[n] = elem->positive_edge_orientation(n);
164 
165  cached_faces.resize(elem->n_faces());
166  for (auto n : elem->face_index_range())
167  cached_faces[n] = elem->positive_face_orientation(n);
168  }
169 }
170 
171 
172 
173 template <unsigned int Dim, FEFamily T>
174 bool FE<Dim,T>::matches_cache(const Elem * elem)
175 {
176  bool m = cached_nodes.size() == elem->n_nodes();
177  for (unsigned n = 1; m && n < elem->n_nodes(); n++)
178  m = (elem->point(n) - elem->point(0)).relative_fuzzy_equals(cached_nodes[n] - cached_nodes[0]);
179 
180  if (FEInterface::orientation_dependent(T))
181  {
182  m &= cached_edges.size() == elem->n_edges();
183  for (unsigned n = 0; m && n < elem->n_edges(); n++)
184  m = elem->positive_edge_orientation(n) == cached_edges[n];
185 
186  m &= cached_faces.size() == elem->n_faces();
187  for (unsigned n = 0; m && n < elem->n_faces(); n++)
188  m = elem->positive_face_orientation(n) == cached_faces[n];
189  }
190 
191  return m;
192 }
193 
194 
195 
196 template <unsigned int Dim, FEFamily T>
197 void FE<Dim,T>::reinit(const Elem * elem,
198  const std::vector<Point> * const pts,
199  const std::vector<Real> * const weights)
200 {
201  // We can be called with no element. If we're evaluating SCALAR
202  // dofs we'll still have work to do.
203  // libmesh_assert(elem);
204 
205  // We're calculating now! Time to determine what.
206  this->determine_calculations();
207 
208  // Try to avoid calling init_shape_functions
209  // even when shapes_need_reinit
210  bool cached_elem_still_fits = false;
211 
212  // Most of the hard work happens when we have an actual element
213  if (elem)
214  {
215  // Initialize the shape functions at the user-specified
216  // points
217  if (pts != nullptr)
218  {
219  // Set the type and p level for this element
220  this->_elem = elem;
221  this->_elem_type = elem->type();
222  this->_elem_p_level = elem->p_level();
223  this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
224 
225  // Initialize the shape functions
226  this->_fe_map->template init_reference_to_physical_map<Dim>
227  (*pts, elem);
228  this->init_shape_functions (*pts, elem);
229 
230  // The shape functions do not correspond to the qrule
231  this->shapes_on_quadrature = false;
232  }
233 
234  // If there are no user specified points, we use the
235  // quadrature rule
236 
237  // update the type in accordance to the current cell
238  // and reinit if the cell type has changed or (as in
239  // the case of the hierarchics) the shape functions need
240  // reinit, since they depend on the particular element shape
241  else
242  {
243  libmesh_assert(this->qrule);
244  this->qrule->init(*elem);
245 
246  if (this->qrule->shapes_need_reinit())
247  this->shapes_on_quadrature = false;
248 
249  // We're not going to bother trying to cache nodal
250  // points *and* weights for fancier mapping types.
251  if (this->get_type() != elem->type() ||
252  (elem->runtime_topology() &&
253  this->_elem != elem) ||
254  this->_elem_p_level != elem->p_level() ||
255  !this->shapes_on_quadrature ||
256  elem->mapping_type() != LAGRANGE_MAP)
257  {
258  // Set the type and p level for this element
259  this->_elem = elem;
260  this->_elem_type = elem->type();
261  this->_elem_p_level = elem->p_level();
262  this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
263 
264  // Initialize the shape functions
265  this->_fe_map->template init_reference_to_physical_map<Dim>
266  (this->qrule->get_points(), elem);
267  this->init_shape_functions (this->qrule->get_points(), elem);
268  }
269  else
270  {
271  this->_elem = elem;
272 
273  // Check if cached element's nodes, edge and face orientations still fit
274  cached_elem_still_fits = this->matches_cache(elem);
275 
276  // Initialize the shape functions if needed
277  if (this->shapes_need_reinit() && !cached_elem_still_fits)
278  {
279  this->_fe_map->template init_reference_to_physical_map<Dim>
280  (this->qrule->get_points(), elem);
281  this->init_shape_functions (this->qrule->get_points(), elem);
282  }
283  }
284 
285  // Replace cached nodes, edge and face orientations if no longer fitting
286  if (this->shapes_need_reinit() && !cached_elem_still_fits && *caching)
287  this->cache(elem);
288 
289  // The shape functions correspond to the qrule
290  this->shapes_on_quadrature = true;
291  }
292  }
293  else // With no defined elem, so mapping or caching to
294  // be done, and our "quadrature rule" is one point for nonlocal
295  // (SCALAR) variables and zero points for local variables.
296  {
297  this->_elem = nullptr;
298  this->_elem_type = INVALID_ELEM;
299  this->_elem_p_level = 0;
300  this->_p_level = 0;
301 
302  if (!pts)
303  {
304  if (T == SCALAR)
305  {
306  this->qrule->get_points() =
307  std::vector<Point>(1,Point(0));
308 
309  this->qrule->get_weights() =
310  std::vector<Real>(1,1);
311  }
312  else
313  {
314  this->qrule->get_points().clear();
315  this->qrule->get_weights().clear();
316  }
317 
318  this->init_shape_functions (this->qrule->get_points(), elem);
319  }
320  else
321  this->init_shape_functions (*pts, elem);
322  }
323 
324  // Compute the map for this element.
325  if (pts != nullptr)
326  {
327  if (weights != nullptr)
328  {
329  this->_fe_map->compute_map (this->dim, *weights, elem, this->calculate_d2phi);
330  }
331  else
332  {
333  std::vector<Real> dummy_weights (pts->size(), 1.);
334  this->_fe_map->compute_map (this->dim, dummy_weights, elem, this->calculate_d2phi);
335  }
336  }
337  else
338  {
339  this->_fe_map->compute_map (this->dim, this->qrule->get_weights(), elem, this->calculate_d2phi);
340  }
341 
342  // Compute the shape functions and the derivatives at all of the
343  // quadrature points.
344  if (!cached_elem_still_fits)
345  {
346  if (pts != nullptr)
347  this->compute_shape_functions (elem,*pts);
348  else
349  this->compute_shape_functions(elem,this->qrule->get_points());
350  if (this->calculate_dual)
351  {
352  if (T != LAGRANGE)
353  nonlagrange_dual_warning();
354  // Check if we need to calculate the dual coefficients based on the default QRule
355  // We keep the default dual coeff calculation for the initial stage of the simulation
356  // and in the middel of the simulation when a customized QRule is not provided.
357  // This is used in MOOSE mortar-based contact. Currently, we re-compute dual_coeff
358  // for all the elements on the mortar segment mesh by setting `calculate_default_dual_coeff' = false
359  // in MOOSE (in `Assembly::reinitDual`) and use the customized QRule for calculating the dual shape coefficients
360  // This is to be improved in the future
361  if (elem && this->calculate_default_dual_coeff)
362  this->reinit_default_dual_shape_coeffs(elem);
363  // The dual shape functions relies on the customized shape functions
364  // and the coefficient matrix, \p dual_coeff
365  this->compute_dual_shape_functions();
366  }
367  }
368 }
369 
370 template <unsigned int Dim, FEFamily T>
372  const std::vector<Point> & pts,
373  const std::vector<Real> & JxW)
374 {
375  // Set the type and p level for this element
376  this->_elem = elem;
377  this->_elem_type = elem->type();
378  this->_elem_p_level = elem->p_level();
379  this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
380 
381  const unsigned int n_shapes =
382  this->n_dofs(elem, this->get_order());
383 
384  std::vector<std::vector<OutputShape>> phi_vals;
385  phi_vals.resize(n_shapes);
386  for (const auto i : make_range(phi_vals.size()))
387  phi_vals[i].resize(pts.size());
388 
389  all_shapes(elem, this->get_order(), pts, phi_vals);
390  this->compute_dual_shape_coeffs(JxW, phi_vals);
391 }
392 
393 template <unsigned int Dim, FEFamily T>
395 {
396  libmesh_assert(elem);
397 
398  FEType default_fe_type(this->get_order(), T);
399  QGauss default_qrule(elem->dim(), default_fe_type.default_quadrature_order());
400  default_qrule.init(*elem);
401  // In preparation of computing dual_coeff, we compute the default shape
402  // function values and use these to compute the dual shape coefficients.
403  // The TRUE dual_phi values are computed in compute_dual_shape_functions()
404  this->reinit_dual_shape_coeffs(elem, default_qrule.get_points(), default_qrule.get_weights());
405  // we do not compute default dual coeff many times as this can be expensive
406  this->set_calculate_default_dual_coeff(false);
407 }
408 
409 
410 template <unsigned int Dim, FEFamily T>
411 void FE<Dim,T>::init_dual_shape_functions(const unsigned int n_shapes, const unsigned int n_qp)
412 {
413  if (!this->calculate_dual)
414  return;
415 
416  libmesh_assert_msg(this->calculate_phi,
417  "dual shape function calculation relies on "
418  "primal shape functions being calculated");
419 
420  this->dual_phi.resize(n_shapes);
421  if (this->calculate_dphi)
422  this->dual_dphi.resize(n_shapes);
423 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
424  if (this->calculate_d2phi)
425  this->dual_d2phi.resize(n_shapes);
426 #endif
427 
428  for (auto i : index_range(this->dual_phi))
429  {
430  this->dual_phi[i].resize(n_qp);
431  if (this->calculate_dphi)
432  this->dual_dphi[i].resize(n_qp);
433 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
434  if (this->calculate_d2phi)
435  this->dual_d2phi[i].resize(n_qp);
436 #endif
437  }
438 }
439 
440 template <unsigned int Dim, FEFamily T>
441 void FE<Dim,T>::init_shape_functions(const std::vector<Point> & qp,
442  const Elem * elem)
443 {
444  // Start logging the shape function initialization
445  LOG_SCOPE("init_shape_functions()", "FE");
446 
447  // The number of quadrature points.
448  const unsigned int n_qp = cast_int<unsigned int>(qp.size());
449  this->_n_total_qp = n_qp;
450 
451  // Number of shape functions in the finite element approximation
452  // space.
453  const unsigned int n_approx_shape_functions =
454  this->n_dofs(elem, this->get_order());
455 
456  // Maybe we already have correctly-sized data? Check data sizes,
457  // and get ready to break out of a "loop" if all these resize()
458  // calls are redundant.
459  unsigned int old_n_qp = 0;
460  do
461  {
462  // resize the vectors to hold current data
463  // Phi are the shape functions used for the FE approximation
464  // Phi_map are the shape functions used for the FE mapping
465  if (this->calculate_phi)
466  {
467  if (this->phi.size() == n_approx_shape_functions)
468  {
469  old_n_qp = n_approx_shape_functions ? this->phi[0].size() : 0;
470  break;
471  }
472  this->phi.resize (n_approx_shape_functions);
473  }
474  if (this->calculate_dphi)
475  {
476  if (this->dphi.size() == n_approx_shape_functions)
477  {
478  old_n_qp = n_approx_shape_functions ? this->dphi[0].size() : 0;
479  break;
480  }
481  this->dphi.resize (n_approx_shape_functions);
482  this->dphidx.resize (n_approx_shape_functions);
483  this->dphidy.resize (n_approx_shape_functions);
484  this->dphidz.resize (n_approx_shape_functions);
485  }
486 
487  if (this->calculate_dphiref)
488  {
489  if (Dim > 0)
490  {
491  if (this->dphidxi.size() == n_approx_shape_functions)
492  {
493  old_n_qp = n_approx_shape_functions ? this->dphidxi[0].size() : 0;
494  break;
495  }
496  this->dphidxi.resize (n_approx_shape_functions);
497  }
498 
499  if (Dim > 1)
500  this->dphideta.resize (n_approx_shape_functions);
501 
502  if (Dim > 2)
503  this->dphidzeta.resize (n_approx_shape_functions);
504  }
505 
506  if (this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
507  this->curl_phi.resize(n_approx_shape_functions);
508 
509  if (this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
510  this->div_phi.resize(n_approx_shape_functions);
511 
512 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
513  if (this->calculate_d2phi)
514  {
515  if (this->d2phi.size() == n_approx_shape_functions)
516  {
517  old_n_qp = n_approx_shape_functions ? this->d2phi[0].size() : 0;
518  break;
519  }
520 
521  this->d2phi.resize (n_approx_shape_functions);
522  this->d2phidx2.resize (n_approx_shape_functions);
523  this->d2phidxdy.resize (n_approx_shape_functions);
524  this->d2phidxdz.resize (n_approx_shape_functions);
525  this->d2phidy2.resize (n_approx_shape_functions);
526  this->d2phidydz.resize (n_approx_shape_functions);
527  this->d2phidz2.resize (n_approx_shape_functions);
528 
529  if (Dim > 0)
530  this->d2phidxi2.resize (n_approx_shape_functions);
531 
532  if (Dim > 1)
533  {
534  this->d2phidxideta.resize (n_approx_shape_functions);
535  this->d2phideta2.resize (n_approx_shape_functions);
536  }
537  if (Dim > 2)
538  {
539  this->d2phidxidzeta.resize (n_approx_shape_functions);
540  this->d2phidetadzeta.resize (n_approx_shape_functions);
541  this->d2phidzeta2.resize (n_approx_shape_functions);
542  }
543  }
544 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
545  }
546  while (false);
547 
548  if (old_n_qp != n_qp)
549  for (unsigned int i=0; i<n_approx_shape_functions; i++)
550  {
551  if (this->calculate_phi)
552  this->phi[i].resize (n_qp);
553 
554  if (this->calculate_dphi)
555  {
556  this->dphi[i].resize (n_qp);
557  this->dphidx[i].resize (n_qp);
558  this->dphidy[i].resize (n_qp);
559  this->dphidz[i].resize (n_qp);
560  }
561 
562  if (this->calculate_dphiref)
563  {
564  if (Dim > 0)
565  this->dphidxi[i].resize(n_qp);
566 
567  if (Dim > 1)
568  this->dphideta[i].resize(n_qp);
569 
570  if (Dim > 2)
571  this->dphidzeta[i].resize(n_qp);
572  }
573 
574  if (this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
575  this->curl_phi[i].resize(n_qp);
576 
577  if (this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
578  this->div_phi[i].resize(n_qp);
579 
580 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
581  if (this->calculate_d2phi)
582  {
583  this->d2phi[i].resize (n_qp);
584  this->d2phidx2[i].resize (n_qp);
585  this->d2phidxdy[i].resize (n_qp);
586  this->d2phidxdz[i].resize (n_qp);
587  this->d2phidy2[i].resize (n_qp);
588  this->d2phidydz[i].resize (n_qp);
589  this->d2phidz2[i].resize (n_qp);
590  if (Dim > 0)
591  this->d2phidxi2[i].resize (n_qp);
592  if (Dim > 1)
593  {
594  this->d2phidxideta[i].resize (n_qp);
595  this->d2phideta2[i].resize (n_qp);
596  }
597  if (Dim > 2)
598  {
599  this->d2phidxidzeta[i].resize (n_qp);
600  this->d2phidetadzeta[i].resize (n_qp);
601  this->d2phidzeta2[i].resize (n_qp);
602  }
603  }
604 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
605  }
606 
607 
608 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
609  //------------------------------------------------------------
610  // Initialize the data fields, which should only be used for infinite
611  // elements, to some sensible values, so that using a FE with the
612  // variational formulation of an InfFE, correct element matrices are
613  // returned
614 
615  {
616  if (this->calculate_phi || this->calculate_dphi)
617  {
618  this->weight.resize (n_qp);
619  for (unsigned int p=0; p<n_qp; p++)
620  this->weight[p] = 1.;
621  }
622 
623  if (this->calculate_dphi)
624  {
625  this->dweight.resize (n_qp);
626  this->dphase.resize (n_qp);
627  for (unsigned int p=0; p<n_qp; p++)
628  {
629  this->dweight[p].zero();
630  this->dphase[p].zero();
631  }
632  }
633  }
634 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
635 
636  // Compute the values of the shape function derivatives
637  if (this->calculate_dphiref && Dim > 0)
638  {
639  std::vector<std::vector<OutputShape>> * comps[3]
640  { &this->dphidxi, &this->dphideta, &this->dphidzeta };
641  FE<Dim,T>::all_shape_derivs(elem, this->fe_type.order, qp, comps, this->_add_p_level_in_reinit);
642  }
643 
644  switch (Dim)
645  {
646 
647  //------------------------------------------------------------
648  // 0D
649  case 0:
650  {
651  break;
652  }
653 
654  //------------------------------------------------------------
655  // 1D
656  case 1:
657  {
658 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
659  // Compute the value of shape function i Hessians at quadrature point p
660  if (this->calculate_d2phi)
661  for (unsigned int i=0; i<n_approx_shape_functions; i++)
662  for (unsigned int p=0; p<n_qp; p++)
663  this->d2phidxi2[i][p] = FE<Dim, T>::shape_second_deriv(
664  elem, this->fe_type.order, i, 0, qp[p], this->_add_p_level_in_reinit);
665 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
666 
667  break;
668  }
669 
670 
671 
672  //------------------------------------------------------------
673  // 2D
674  case 2:
675  {
676 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
677  // Compute the value of shape function i Hessians at quadrature point p
678  if (this->calculate_d2phi)
679  for (unsigned int i=0; i<n_approx_shape_functions; i++)
680  for (unsigned int p=0; p<n_qp; p++)
681  {
682  this->d2phidxi2[i][p] = FE<Dim, T>::shape_second_deriv(
683  elem, this->fe_type.order, i, 0, qp[p], this->_add_p_level_in_reinit);
684  this->d2phidxideta[i][p] = FE<Dim, T>::shape_second_deriv(
685  elem, this->fe_type.order, i, 1, qp[p], this->_add_p_level_in_reinit);
686  this->d2phideta2[i][p] = FE<Dim, T>::shape_second_deriv(
687  elem, this->fe_type.order, i, 2, qp[p], this->_add_p_level_in_reinit);
688  }
689 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
690 
691 
692  break;
693  }
694 
695 
696 
697  //------------------------------------------------------------
698  // 3D
699  case 3:
700  {
701 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
702  // Compute the value of shape function i Hessians at quadrature point p
703  if (this->calculate_d2phi)
704  for (unsigned int i=0; i<n_approx_shape_functions; i++)
705  for (unsigned int p=0; p<n_qp; p++)
706  {
707  this->d2phidxi2[i][p] = FE<Dim, T>::shape_second_deriv(
708  elem, this->fe_type.order, i, 0, qp[p], this->_add_p_level_in_reinit);
709  this->d2phidxideta[i][p] = FE<Dim, T>::shape_second_deriv(
710  elem, this->fe_type.order, i, 1, qp[p], this->_add_p_level_in_reinit);
711  this->d2phideta2[i][p] = FE<Dim, T>::shape_second_deriv(
712  elem, this->fe_type.order, i, 2, qp[p], this->_add_p_level_in_reinit);
713  this->d2phidxidzeta[i][p] = FE<Dim, T>::shape_second_deriv(
714  elem, this->fe_type.order, i, 3, qp[p], this->_add_p_level_in_reinit);
715  this->d2phidetadzeta[i][p] = FE<Dim, T>::shape_second_deriv(
716  elem, this->fe_type.order, i, 4, qp[p], this->_add_p_level_in_reinit);
717  this->d2phidzeta2[i][p] = FE<Dim, T>::shape_second_deriv(
718  elem, this->fe_type.order, i, 5, qp[p], this->_add_p_level_in_reinit);
719  }
720 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
721 
722  break;
723  }
724 
725 
726  default:
727  libmesh_error_msg("Invalid dimension Dim = " << Dim);
728  }
729 
730  if (this->calculate_dual)
731  this->init_dual_shape_functions(n_approx_shape_functions, n_qp);
732 }
733 
734 template <unsigned int Dim, FEFamily T>
735 void
737  const Order o,
738  const std::vector<Point> & p,
739  std::vector<std::vector<OutputShape>> * comps[3],
740  const bool add_p_level)
741 {
742  for (unsigned int d=0; d != Dim; ++d)
743  {
744  auto & comps_d = *comps[d];
745  for (auto i : index_range(comps_d))
747  (elem,o,i,d,p,comps_d[i],add_p_level);
748  }
749 }
750 
751 
752 template <unsigned int Dim, FEFamily T>
753 void
755  const unsigned int side,
756  const std::vector<Number> & elem_soln,
757  std::vector<Number> & nodal_soln_on_side,
758  const bool add_p_level,
759  const unsigned vdim)
760 {
761  std::vector<Number> full_nodal_soln;
762  nodal_soln(elem, o, elem_soln, full_nodal_soln, add_p_level, vdim);
763  const std::vector<unsigned int> side_nodes =
764  elem->nodes_on_side(side);
765 
766  std::size_t n_side_nodes = side_nodes.size();
767  nodal_soln_on_side.resize(n_side_nodes);
768  for (auto n : make_range(n_side_nodes))
769  nodal_soln_on_side[n] = full_nodal_soln[side_nodes[n]];
770 }
771 
772 
773 
774 
775 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
776 
777 template <unsigned int Dim, FEFamily T>
778 void FE<Dim,T>::init_base_shape_functions(const std::vector<Point> & qp,
779  const Elem * e)
780 {
781  this->_elem = e;
782  this->_elem_type = e->type();
783  this->_fe_map->template init_reference_to_physical_map<Dim>(qp, e);
784  init_shape_functions(qp, e);
785 }
786 
787 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
788 
789 
790 // Helper for FDM methods
791 namespace {
792 using namespace libMesh;
793 
794 std::tuple<Point, Point, Real>
795 fdm_points(const unsigned int j, const Point & p)
796 {
797  libmesh_assert_less (j, LIBMESH_DIM);
798 
799  // cheat by using finite difference approximations:
800  const Real eps = 1.e-6;
801  Point pp = p, pm = p;
802 
803  switch (j)
804  {
805  // d()/dxi
806  case 0:
807  {
808  pp(0) += eps;
809  pm(0) -= eps;
810  break;
811  }
812 
813  // d()/deta
814  case 1:
815  {
816  pp(1) += eps;
817  pm(1) -= eps;
818  break;
819  }
820 
821  // d()/dzeta
822  case 2:
823  {
824  pp(2) += eps;
825  pm(2) -= eps;
826  break;
827  }
828 
829  default:
830  libmesh_error_msg("Invalid derivative index j = " << j);
831  }
832 
833  return std::make_tuple(pp, pm, eps);
834 }
835 
836 std::tuple<Point, Point, Real, unsigned int>
837 fdm_second_points(const unsigned int j, const Point & p)
838 {
839  // cheat by using finite difference approximations:
840  const Real eps = 1.e-5;
841  Point pp = p, pm = p;
842  unsigned int deriv_j = 0;
843 
844  switch (j)
845  {
846  // d^2() / dxi^2
847  case 0:
848  {
849  pp(0) += eps;
850  pm(0) -= eps;
851  deriv_j = 0;
852  break;
853  }
854 
855  // d^2() / dxi deta
856  case 1:
857  {
858  pp(1) += eps;
859  pm(1) -= eps;
860  deriv_j = 0;
861  break;
862  }
863 
864  // d^2() / deta^2
865  case 2:
866  {
867  pp(1) += eps;
868  pm(1) -= eps;
869  deriv_j = 1;
870  break;
871  }
872 
873  // d^2()/dxidzeta
874  case 3:
875  {
876  pp(2) += eps;
877  pm(2) -= eps;
878  deriv_j = 0;
879  break;
880  } // d^2()/deta^2
881 
882  // d^2()/detadzeta
883  case 4:
884  {
885  pp(2) += eps;
886  pm(2) -= eps;
887  deriv_j = 1;
888  break;
889  }
890 
891  // d^2()/dzeta^2
892  case 5:
893  {
894  pp(2) += eps;
895  pm(2) -= eps;
896  deriv_j = 2;
897  break;
898  }
899 
900  default:
901  libmesh_error_msg("Invalid shape function derivative j = " << j);
902  }
903 
904  return std::make_tuple(pp, pm, eps, deriv_j);
905 }
906 
907 }
908 
909 
910 template <typename OutputShape>
911 OutputShape fe_fdm_deriv(const Elem * elem,
912  const Order order,
913  const unsigned int i,
914  const unsigned int j,
915  const Point & p,
916  const bool add_p_level,
917  OutputShape(*shape_func)
918  (const Elem *, const Order,
919  const unsigned int, const Point &,
920  const bool))
921 {
922  libmesh_assert(elem);
923 
924  auto [pp, pm, eps] = fdm_points(j, p);
925 
926  return (shape_func(elem, order, i, pp, add_p_level) -
927  shape_func(elem, order, i, pm, add_p_level))/2./eps;
928 }
929 
930 
931 template <typename OutputShape>
932 OutputShape fe_fdm_deriv(const ElemType type,
933  const Order order,
934  const unsigned int i,
935  const unsigned int j,
936  const Point & p,
937  OutputShape(*shape_func)
938  (const ElemType, const Order,
939  const unsigned int, const Point &))
940 {
941  auto [pp, pm, eps] = fdm_points(j, p);
942 
943  return (shape_func(type, order, i, pp) -
944  shape_func(type, order, i, pm))/2./eps;
945 }
946 
947 
948 template <typename OutputShape>
949 OutputShape fe_fdm_deriv(const ElemType type,
950  const Order order,
951  const Elem * elem,
952  const unsigned int i,
953  const unsigned int j,
954  const Point & p,
955  OutputShape(*shape_func)
956  (const ElemType, const Order,
957  const Elem *,
958  const unsigned int, const Point &))
959 {
960  auto [pp, pm, eps] = fdm_points(j, p);
961 
962  return (shape_func(type, order, elem, i, pp) -
963  shape_func(type, order, elem, i, pm))/2./eps;
964 }
965 
966 
967 template <typename OutputShape>
968 OutputShape
970  const Order order,
971  const unsigned int i,
972  const unsigned int j,
973  const Point & p,
974  const bool add_p_level,
975  OutputShape(*deriv_func)
976  (const Elem *, const Order,
977  const unsigned int, const unsigned int,
978  const Point &, const bool))
979 {
980  auto [pp, pm, eps, deriv_j] = fdm_second_points(j, p);
981 
982  return (deriv_func(elem, order, i, deriv_j, pp, add_p_level) -
983  deriv_func(elem, order, i, deriv_j, pm, add_p_level))/2./eps;
984 }
985 
986 
987 template <typename OutputShape>
988 OutputShape
990  const Order order,
991  const unsigned int i,
992  const unsigned int j,
993  const Point & p,
994  OutputShape(*deriv_func)
995  (const ElemType, const Order,
996  const unsigned int, const unsigned int,
997  const Point &))
998 {
999  auto [pp, pm, eps, deriv_j] = fdm_second_points(j, p);
1000 
1001  return (deriv_func(type, order, i, deriv_j, pp) -
1002  deriv_func(type, order, i, deriv_j, pm))/2./eps;
1003 }
1004 
1005 
1006 template <typename OutputShape>
1007 OutputShape
1009  const Order order,
1010  const Elem * elem,
1011  const unsigned int i,
1012  const unsigned int j,
1013  const Point & p,
1014  OutputShape(*deriv_func)
1015  (const ElemType, const Order,
1016  const Elem *,
1017  const unsigned int, const unsigned int,
1018  const Point &))
1019 {
1020  auto [pp, pm, eps, deriv_j] = fdm_second_points(j, p);
1021 
1022  return (deriv_func(type, order, elem, i, deriv_j, pp) -
1023  deriv_func(type, order, elem, i, deriv_j, pm))/2./eps;
1024 }
1025 
1026 
1028  const FEType underlying_fe_type,
1029  std::vector<std::vector<Real>> & shapes,
1030  const std::vector<Point> & p,
1031  const bool add_p_level)
1032 {
1033  const int extra_order = add_p_level * elem->p_level();
1034 
1035  const int dim = elem->dim();
1036 
1037  const unsigned int n_sf =
1038  FEInterface::n_shape_functions(underlying_fe_type, extra_order,
1039  elem);
1040 
1041  libmesh_assert_equal_to (n_sf, elem->n_nodes());
1042 
1043  std::vector<Real> node_weights(n_sf);
1044 
1045  const unsigned char datum_index = elem->mapping_data();
1046  for (unsigned int n=0; n<n_sf; n++)
1047  node_weights[n] =
1048  elem->node_ref(n).get_extra_datum<Real>(datum_index);
1049 
1050  const std::size_t n_p = p.size();
1051 
1052  shapes.resize(n_sf);
1053  for (unsigned int i=0; i != n_sf; ++i)
1054  {
1055  auto & shapes_i = shapes[i];
1056  shapes_i.resize(n_p, 0);
1057  FEInterface::shapes(dim, underlying_fe_type, elem, i, p,
1058  shapes_i, add_p_level);
1059  for (auto & s : shapes_i)
1060  s *= node_weights[i];
1061  }
1062 }
1063 
1064 
1066  const FEType fe_type,
1067  std::vector<std::vector<Real>> & shapes,
1068  std::vector<std::vector<std::vector<Real>>> & derivs,
1069  const std::vector<Point> & p,
1070  const bool add_p_level)
1071 {
1072  const int extra_order = add_p_level * elem->p_level();
1073  const unsigned int dim = elem->dim();
1074 
1075  const unsigned int n_sf =
1076  FEInterface::n_shape_functions(fe_type, extra_order, elem);
1077 
1078  libmesh_assert_equal_to (n_sf, elem->n_nodes());
1079 
1080  libmesh_assert_equal_to (dim, derivs.size());
1081  for (unsigned int d = 0; d != dim; ++d)
1082  derivs[d].resize(n_sf);
1083 
1084  std::vector<Real> node_weights(n_sf);
1085 
1086  const unsigned char datum_index = elem->mapping_data();
1087  for (unsigned int n=0; n<n_sf; n++)
1088  node_weights[n] =
1089  elem->node_ref(n).get_extra_datum<Real>(datum_index);
1090 
1091  const std::size_t n_p = p.size();
1092 
1093  shapes.resize(n_sf);
1094  for (unsigned int i=0; i != n_sf; ++i)
1095  shapes[i].resize(n_p, 0);
1096 
1097  FEInterface::all_shapes(dim, fe_type, elem, p, shapes, add_p_level);
1098 
1099  for (unsigned int i=0; i != n_sf; ++i)
1100  {
1101  auto & shapes_i = shapes[i];
1102 
1103  for (auto & s : shapes_i)
1104  s *= node_weights[i];
1105 
1106  for (unsigned int d = 0; d != dim; ++d)
1107  {
1108  auto & derivs_di = derivs[d][i];
1109  derivs_di.resize(n_p);
1110  FEInterface::shape_derivs(fe_type, elem, i, d, p,
1111  derivs_di, add_p_level);
1112  for (auto & dip : derivs_di)
1113  dip *= node_weights[i];
1114  }
1115  }
1116 }
1117 
1118 
1120  const FEType underlying_fe_type,
1121  const unsigned int i,
1122  const Point & p,
1123  const bool add_p_level)
1124 {
1125  int extra_order = add_p_level * elem.p_level();
1126 
1127  const unsigned int n_sf =
1128  FEInterface::n_shape_functions(underlying_fe_type, extra_order, &elem);
1129 
1130  libmesh_assert_equal_to (n_sf, elem.n_nodes());
1131 
1132  std::vector<Real> node_weights(n_sf);
1133 
1134  const unsigned char datum_index = elem.mapping_data();
1135 
1136  Real weighted_shape_i = 0, weighted_sum = 0;
1137 
1138  for (unsigned int sf=0; sf<n_sf; sf++)
1139  {
1140  Real node_weight =
1141  elem.node_ref(sf).get_extra_datum<Real>(datum_index);
1142  Real weighted_shape = node_weight *
1143  FEInterface::shape(underlying_fe_type, extra_order, &elem, sf, p);
1144  weighted_sum += weighted_shape;
1145  if (sf == i)
1146  weighted_shape_i = weighted_shape;
1147  }
1148 
1149  return weighted_shape_i / weighted_sum;
1150 }
1151 
1152 
1154  const FEType underlying_fe_type,
1155  const unsigned int i,
1156  const unsigned int j,
1157  const Point & p,
1158  const bool add_p_level)
1159 {
1160  libmesh_assert_less(j, elem.dim());
1161 
1162  int extra_order = add_p_level * elem.p_level();
1163 
1164  const unsigned int n_sf =
1165  FEInterface::n_shape_functions(underlying_fe_type, extra_order, &elem);
1166 
1167  const unsigned int n_nodes = elem.n_nodes();
1168  libmesh_assert_equal_to (n_sf, n_nodes);
1169 
1170  std::vector<Real> node_weights(n_nodes);
1171 
1172  const unsigned char datum_index = elem.mapping_data();
1173  for (unsigned int n=0; n<n_nodes; n++)
1174  node_weights[n] =
1175  elem.node_ref(n).get_extra_datum<Real>(datum_index);
1176 
1177  Real weighted_shape_i = 0, weighted_sum = 0,
1178  weighted_grad_i = 0, weighted_grad_sum = 0;
1179 
1180  for (unsigned int sf=0; sf<n_sf; sf++)
1181  {
1182  Real weighted_shape = node_weights[sf] *
1183  FEInterface::shape(underlying_fe_type, extra_order, &elem, sf, p);
1184  Real weighted_grad = node_weights[sf] *
1185  FEInterface::shape_deriv(underlying_fe_type, extra_order, &elem, sf, j, p);
1186  weighted_sum += weighted_shape;
1187  weighted_grad_sum += weighted_grad;
1188  if (sf == i)
1189  {
1190  weighted_shape_i = weighted_shape;
1191  weighted_grad_i = weighted_grad;
1192  }
1193  }
1194 
1195  return (weighted_sum * weighted_grad_i - weighted_shape_i * weighted_grad_sum) /
1196  weighted_sum / weighted_sum;
1197 }
1198 
1199 
1200 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1201 
1203  const FEType underlying_fe_type,
1204  const unsigned int i,
1205  const unsigned int j,
1206  const Point & p,
1207  const bool add_p_level)
1208 {
1209  unsigned int j1, j2;
1210  switch (j)
1211  {
1212  case 0:
1213  // j = 0 ==> d^2 phi / dxi^2
1214  j1 = j2 = 0;
1215  break;
1216  case 1:
1217  // j = 1 ==> d^2 phi / dxi deta
1218  j1 = 0;
1219  j2 = 1;
1220  break;
1221  case 2:
1222  // j = 2 ==> d^2 phi / deta^2
1223  j1 = j2 = 1;
1224  break;
1225  case 3:
1226  // j = 3 ==> d^2 phi / dxi dzeta
1227  j1 = 0;
1228  j2 = 2;
1229  break;
1230  case 4:
1231  // j = 4 ==> d^2 phi / deta dzeta
1232  j1 = 1;
1233  j2 = 2;
1234  break;
1235  case 5:
1236  // j = 5 ==> d^2 phi / dzeta^2
1237  j1 = j2 = 2;
1238  break;
1239  default:
1240  libmesh_error();
1241  }
1242 
1243  int extra_order = add_p_level * elem.p_level();
1244 
1245  const unsigned int n_sf =
1246  FEInterface::n_shape_functions(underlying_fe_type, extra_order,
1247  &elem);
1248 
1249  const unsigned int n_nodes = elem.n_nodes();
1250  libmesh_assert_equal_to (n_sf, n_nodes);
1251 
1252  std::vector<Real> node_weights(n_nodes);
1253 
1254  const unsigned char datum_index = elem.mapping_data();
1255  for (unsigned int n=0; n<n_nodes; n++)
1256  node_weights[n] =
1257  elem.node_ref(n).get_extra_datum<Real>(datum_index);
1258 
1259  Real weighted_shape_i = 0, weighted_sum = 0,
1260  weighted_grada_i = 0, weighted_grada_sum = 0,
1261  weighted_gradb_i = 0, weighted_gradb_sum = 0,
1262  weighted_hess_i = 0, weighted_hess_sum = 0;
1263 
1264  for (unsigned int sf=0; sf<n_sf; sf++)
1265  {
1266  Real weighted_shape = node_weights[sf] *
1267  FEInterface::shape(underlying_fe_type, extra_order, &elem, sf,
1268  p);
1269  Real weighted_grada = node_weights[sf] *
1270  FEInterface::shape_deriv(underlying_fe_type, extra_order,
1271  &elem, sf, j1, p);
1272  Real weighted_hess = node_weights[sf] *
1273  FEInterface::shape_second_deriv(underlying_fe_type,
1274  extra_order, &elem, sf, j, p);
1275  weighted_sum += weighted_shape;
1276  weighted_grada_sum += weighted_grada;
1277  Real weighted_gradb = weighted_grada;
1278  if (j1 != j2)
1279  {
1280  weighted_gradb = (j1 == j2) ? weighted_grada :
1281  node_weights[sf] *
1282  FEInterface::shape_deriv(underlying_fe_type, extra_order,
1283  &elem, sf, j2, p);
1284  weighted_grada_sum += weighted_grada;
1285  }
1286  weighted_hess_sum += weighted_hess;
1287  if (sf == i)
1288  {
1289  weighted_shape_i = weighted_shape;
1290  weighted_grada_i = weighted_grada;
1291  weighted_gradb_i = weighted_gradb;
1292  weighted_hess_i = weighted_hess;
1293  }
1294  }
1295 
1296  if (j1 == j2)
1297  weighted_gradb_sum = weighted_grada_sum;
1298 
1299  return (weighted_sum * weighted_hess_i - weighted_grada_i * weighted_gradb_sum -
1300  weighted_shape_i * weighted_hess_sum - weighted_gradb_i * weighted_grada_sum +
1301  2 * weighted_grada_sum * weighted_shape_i * weighted_gradb_sum / weighted_sum) /
1302  weighted_sum / weighted_sum;
1303 }
1304 
1305 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1306 
1307 
1308 void rational_all_shapes (const Elem & elem,
1309  const FEType underlying_fe_type,
1310  const std::vector<Point> & p,
1311  std::vector<std::vector<Real>> & v,
1312  const bool add_p_level)
1313 {
1314  std::vector<std::vector<Real>> shapes;
1315 
1316  rational_fe_weighted_shapes(&elem, underlying_fe_type, shapes, p,
1317  add_p_level);
1318 
1319  std::vector<Real> shape_sums(p.size(), 0);
1320 
1321  for (auto i : index_range(v))
1322  {
1323  libmesh_assert_equal_to ( p.size(), shapes[i].size() );
1324  for (auto j : index_range(p))
1325  shape_sums[j] += shapes[i][j];
1326  }
1327 
1328  for (auto i : index_range(v))
1329  {
1330  libmesh_assert_equal_to ( p.size(), v[i].size() );
1331  for (auto j : index_range(v[i]))
1332  v[i][j] = shapes[i][j] / shape_sums[j];
1333  }
1334 }
1335 
1336 
1337 template <typename OutputShape>
1338 void rational_all_shape_derivs (const Elem & elem,
1339  const FEType underlying_fe_type,
1340  const std::vector<Point> & p,
1341  std::vector<std::vector<OutputShape>> * comps[3],
1342  const bool add_p_level)
1343 {
1344  const int my_dim = elem.dim();
1345 
1346  std::vector<std::vector<Real>> shapes;
1347  std::vector<std::vector<std::vector<Real>>> derivs(my_dim);
1348 
1349  rational_fe_weighted_shapes_derivs(&elem, underlying_fe_type,
1350  shapes, derivs, p, add_p_level);
1351 
1352  std::vector<Real> shape_sums(p.size(), 0);
1353  std::vector<std::vector<Real>> shape_deriv_sums(my_dim);
1354  for (int d=0; d != my_dim; ++d)
1355  shape_deriv_sums[d].resize(p.size());
1356 
1357  for (auto i : index_range(shapes))
1358  {
1359  libmesh_assert_equal_to ( p.size(), shapes[i].size() );
1360  for (auto j : index_range(p))
1361  shape_sums[j] += shapes[i][j];
1362 
1363  for (int d=0; d != my_dim; ++d)
1364  for (auto j : index_range(p))
1365  shape_deriv_sums[d][j] += derivs[d][i][j];
1366  }
1367 
1368  for (int d=0; d != my_dim; ++d)
1369  {
1370  auto & comps_d = *comps[d];
1371  libmesh_assert_equal_to(comps_d.size(), elem.n_nodes());
1372 
1373  for (auto i : index_range(comps_d))
1374  {
1375  auto & comps_di = comps_d[i];
1376  auto & derivs_di = derivs[d][i];
1377 
1378  for (auto j : index_range(comps_di))
1379  comps_di[j] = (shape_sums[j] * derivs_di[j] -
1380  shapes[i][j] * shape_deriv_sums[d][j]) /
1381  shape_sums[j] / shape_sums[j];
1382  }
1383  }
1384 }
1385 
1386 
1387 
1388 template
1389 Real fe_fdm_deriv<Real>(const Elem *, const Order, const unsigned int,
1390  const unsigned int, const Point &, const bool,
1391  Real(*shape_func)
1392  (const Elem *, const Order, const unsigned int,
1393  const Point &, const bool));
1394 
1395 template
1396 Real fe_fdm_deriv<Real>(const ElemType, const Order, const unsigned int,
1397  const unsigned int, const Point &,
1398  Real(*shape_func)
1399  (const ElemType, const Order, const unsigned int,
1400  const Point &));
1401 
1402 template
1403 Real fe_fdm_deriv<Real>(const ElemType, const Order, const Elem *,
1404  const unsigned int, const unsigned int, const Point &,
1405  Real(*shape_func)
1406  (const ElemType, const Order, const Elem *,
1407  const unsigned int, const Point &));
1408 
1409 template
1411 fe_fdm_deriv<RealGradient>(const Elem *, const Order, const unsigned int,
1412  const unsigned int, const Point &, const bool,
1413  RealGradient(*shape_func)
1414  (const Elem *, const Order, const unsigned int,
1415  const Point &, const bool));
1416 
1417 template
1418 Real
1419 fe_fdm_second_deriv<Real>(const ElemType, const Order, const unsigned int,
1420  const unsigned int, const Point &,
1421  Real(*shape_func)
1422  (const ElemType, const Order, const unsigned int,
1423  const unsigned int, const Point &));
1424 
1425 template
1426 Real
1427 fe_fdm_second_deriv<Real>(const Elem *, const Order, const unsigned int,
1428  const unsigned int, const Point &, const bool,
1429  Real(*shape_func)
1430  (const Elem *, const Order, const unsigned int,
1431  const unsigned int, const Point &, const bool));
1432 
1433 template
1434 Real
1435 fe_fdm_second_deriv<Real>(const ElemType, const Order, const Elem *,
1436  const unsigned int, const unsigned int, const Point &,
1437  Real(*shape_func)
1438  (const ElemType, const Order, const Elem *,
1439  const unsigned int, const unsigned int, const Point &));
1440 
1441 template
1443 fe_fdm_second_deriv<RealGradient>(const Elem *, const Order, const unsigned int,
1444  const unsigned int, const Point &, const bool,
1445  RealGradient(*shape_func)
1446  (const Elem *, const Order, const unsigned int,
1447  const unsigned int, const Point &, const bool));
1448 
1449 
1450 
1451 
1452 //--------------------------------------------------------------
1453 // Explicit instantiations using macro from fe_macro.h
1454 
1455 INSTANTIATE_FE(0);
1456 
1457 INSTANTIATE_FE(1);
1458 
1459 INSTANTIATE_FE(2);
1460 
1461 INSTANTIATE_FE(3);
1462 
1464 
1465 template LIBMESH_EXPORT void rational_all_shape_derivs<Real> (const Elem & elem, const FEType underlying_fe_type, const std::vector<Point> & p, std::vector<std::vector<Real>> * comps[3], const bool add_p_level);
1466 } // namespace libMesh
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
unsigned char mapping_data() const
Definition: elem.h:3136
ElemType
Defines an enum for geometric element types.
RealVectorValue RealGradient
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
void rational_fe_weighted_shapes_derivs(const Elem *elem, const FEType fe_type, std::vector< std::vector< Real >> &shapes, std::vector< std::vector< std::vector< Real >>> &derivs, const std::vector< Point > &p, const bool add_p_level)
Definition: fe.C:1065
INSTANTIATE_SUBDIVISION_FE
Definition: fe.C:1463
unsigned int dim
virtual bool runtime_topology() const
Definition: elem.h:259
template LIBMESH_EXPORT void rational_all_shape_derivs< Real >(const Elem &elem, const FEType underlying_fe_type, const std::vector< Point > &p, std::vector< std::vector< Real >> *comps[3], const bool add_p_level)
INSTANTIATE_FE(3)
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
FE(const FEType &fet)
Constructor.
Definition: fe.C:62
Order default_quadrature_order() const
Definition: fe_type.h:371
unsigned int p_level() const
Definition: elem.h:3108
The libMesh namespace provides an interface to certain functionality in the library.
IntRange< unsigned short > edge_index_range() const
Definition: elem.h:2692
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const =0
A specific instantiation of the FEBase class.
Definition: fe.h:127
template RealGradient fe_fdm_deriv< RealGradient >(const Elem *, const Order, const unsigned int, const unsigned int, const Point &, const bool, RealGradient(*shape_func)(const Elem *, const Order, const unsigned int, const Point &, const bool))
const dof_id_type n_nodes
Definition: tecplot_io.C:67
IntRange< unsigned short > face_index_range() const
Definition: elem.h:2701
ElemMappingType mapping_type() const
Definition: elem.h:3120
const Node & node_ref(const unsigned int i) const
Definition: elem.h:2529
virtual unsigned int n_nodes() const =0
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:437
libmesh_assert(ctx)
void rational_all_shape_derivs(const Elem &elem, const FEType underlying_fe_type, const std::vector< Point > &p, std::vector< std::vector< OutputShape >> *comps[3], const bool add_p_level)
Definition: fe.C:1338
virtual unsigned int n_edges() const =0
bool positive_edge_orientation(const unsigned int i) const
Definition: elem.C:3589
OutputShape fe_fdm_second_deriv(const Elem *elem, const Order order, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level, OutputShape(*deriv_func)(const Elem *, const Order, const unsigned int, const unsigned int, const Point &, const bool))
Definition: fe.C:969
Abstract base class for runtime singleton setup.
void setup()
Setup method.
Definition: fe.C:53
virtual unsigned int n_sides() const =0
Real rational_fe_shape(const Elem &elem, const FEType underlying_fe_type, const unsigned int i, const Point &p, const bool add_p_level)
Definition: fe.C:1119
Real rational_fe_shape_second_deriv(const Elem &elem, const FEType underlying_fe_type, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level)
Definition: fe.C:1202
template RealGradient fe_fdm_second_deriv< RealGradient >(const Elem *, const Order, const unsigned int, const unsigned int, const Point &, const bool, RealGradient(*shape_func)(const Elem *, const Order, const unsigned int, const unsigned int, const Point &, const bool))
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const bool * caching
Definition: fe.C:48
virtual unsigned short dim() const =0
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
This class implements specific orders of Gauss quadrature.
virtual void init(const Elem &e, unsigned int p_level=invalid_uint)
Initializes the data structures for a quadrature rule for the element e.
Definition: quadrature.C:65
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2683
bool positive_face_orientation(const unsigned int i) const
Definition: elem.C:3598
bool relative_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within a relative tolerance.
Definition: fuzzy_equals.h:78
virtual unsigned int n_faces() const =0
bool on_command_line(std::string arg)
Definition: libmesh.C:987
T get_extra_datum(const unsigned int index) const
Gets the value on this object of the extra datum associated with index, which should have been obtain...
Definition: dof_object.h:1146
libMesh::CachingSetup caching_setup
void rational_all_shapes(const Elem &elem, const FEType underlying_fe_type, const std::vector< Point > &p, std::vector< std::vector< Real >> &v, const bool add_p_level)
Definition: fe.C:1308
void rational_fe_weighted_shapes(const Elem *elem, const FEType underlying_fe_type, std::vector< std::vector< Real >> &shapes, const std::vector< Point > &p, const bool add_p_level)
Helper functions for rational basis functions.
Definition: fe.C:1027
OutputShape fe_fdm_deriv(const ElemType type, const Order order, const Elem *elem, const unsigned int i, const unsigned int j, const Point &p, OutputShape(*shape_func)(const ElemType, const Order, const Elem *, const unsigned int, const Point &))
Definition: fe.C:949
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Point & point(const unsigned int i) const
Definition: elem.h:2453
template Real fe_fdm_deriv< Real >(const ElemType, const Order, const Elem *, const unsigned int, const unsigned int, const Point &, Real(*shape_func)(const ElemType, const Order, const Elem *, const unsigned int, const Point &))
The QBase class provides the basic functionality from which various quadrature rules can be derived...
Definition: quadrature.h:61
void ErrorVector unsigned int
Definition: adjoints_ex3.C:360
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:117
This class forms the foundation from which generic finite elements may be derived.
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
Most finite element types in libMesh are scalar-valued.
Definition: fe.h:51
Real rational_fe_shape_deriv(const Elem &elem, const FEType underlying_fe_type, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level)
Definition: fe.C:1153
template Real fe_fdm_second_deriv< Real >(const ElemType, const Order, const Elem *, const unsigned int, const unsigned int, const Point &, Real(*shape_func)(const ElemType, const Order, const Elem *, const unsigned int, const unsigned int, const Point &))