libMesh
Loading...
Searching...
No Matches
fe.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
32namespace {
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
42namespace 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
48static 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
61template <unsigned int Dim, FEFamily T>
62FE<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
74template <unsigned int Dim, FEFamily T>
75unsigned 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
86template <unsigned int Dim, FEFamily T>
88{
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
98template <unsigned int Dim, FEFamily T>
99void 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
125template <unsigned int Dim, FEFamily T>
126void 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
152template <unsigned int Dim, FEFamily T>
153void 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
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
173template <unsigned int Dim, FEFamily T>
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
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
196template <unsigned int Dim, FEFamily T>
197void 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
370template <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
393template <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
410template <unsigned int Dim, FEFamily T>
411void FE<Dim,T>::init_dual_shape_functions(const unsigned int n_shapes, const unsigned int n_qp)
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
440template <unsigned int Dim, FEFamily T>
441void 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);
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);
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++)
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
734template <unsigned int Dim, FEFamily T>
735void
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
752template <unsigned int Dim, FEFamily T>
753void
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
777template <unsigned int Dim, FEFamily T>
778void 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);
786
787#endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
788
789
790// Helper for FDM methods
791namespace {
792using namespace libMesh;
793
794std::tuple<Point, Point, Real>
795fdm_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
836std::tuple<Point, Point, Real, unsigned int>
837fdm_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
910template <typename OutputShape>
911OutputShape 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
931template <typename OutputShape>
932OutputShape 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
948template <typename OutputShape>
949OutputShape 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
967template <typename OutputShape>
968OutputShape
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
987template <typename OutputShape>
988OutputShape
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
1006template <typename OutputShape>
1007OutputShape
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
1308void 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
1337template <typename OutputShape>
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
1388template
1389Real 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
1395template
1396Real 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
1402template
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
1409template
1411fe_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
1417template
1419fe_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
1425template
1427fe_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
1433template
1435fe_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
1441template
1443fe_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
1456
1458
1460
1462
1464
1465template 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
unsigned int dim
void setup()
Setup method.
Definition fe.C:53
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...
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
unsigned char mapping_data() const
Definition elem.h:3153
const Point & point(const unsigned int i) const
Definition elem.h:2462
const Node & node_ref(const unsigned int i) const
Definition elem.h:2538
virtual unsigned int n_nodes() const =0
bool positive_edge_orientation(const unsigned int i) const
Definition elem.C:3634
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
bool positive_face_orientation(const unsigned int i) const
Definition elem.C:3643
virtual unsigned short dim() const =0
ElemMappingType mapping_type() const
Definition elem.h:3137
virtual bool runtime_topology() const
Definition elem.h:254
virtual unsigned int n_faces() const =0
IntRange< unsigned short > edge_index_range() const
Definition elem.h:2709
virtual ElemType type() const =0
IntRange< unsigned short > node_index_range() const
Definition elem.h:2700
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const =0
virtual unsigned int n_edges() const =0
virtual unsigned int n_sides() const =0
unsigned int p_level() const
Definition elem.h:3125
IntRange< unsigned short > face_index_range() const
Definition elem.h:2718
FEFamily get_family() const
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
static Real shape(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const Point &p)
static Real shape_second_deriv(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const unsigned int j, const Point &p)
static Real shape_deriv(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const unsigned int j, const Point &p)
static FEFieldType field_type(const FEType &fe_type)
static void shape_derivs(const FEType &fe_t, const Elem *elem, const unsigned int i, const unsigned int j, const std::vector< Point > &p, std::vector< OutputType > &dphi, const bool add_p_level=true)
Fills dphi with the derivatives of the shape function at point p in direction j.
static void all_shapes(const unsigned int dim, const FEType &fe_t, const Elem *elem, const std::vector< Point > &p, std::vector< std::vector< OutputType > > &phi, const bool add_p_level=true)
static void shapes(const unsigned int dim, const FEType &fe_t, const Elem *elem, const unsigned int i, const std::vector< Point > &p, std::vector< OutputType > &phi, const bool add_p_level=true)
Fills phi with the values of the shape function at point p.
static bool orientation_dependent(const FEFamily &fe_family)
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
Order default_quadrature_order() const
Definition fe_type.h:415
A specific instantiation of the FEBase class.
Definition fe.h:128
virtual unsigned int n_shape_functions() const override
Definition fe.C:75
virtual void init_shape_functions(const std::vector< Point > &qp, const Elem *e)
Update the various member data fields phi, dphidxi, dphideta, dphidzeta, etc.
Definition fe.C:441
virtual void reinit(const Elem *elem, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr) override
This is at the core of this class.
Definition fe.C:197
FE(const FEType &fet)
Constructor.
Definition fe.C:62
void init_dual_shape_functions(unsigned int n_shapes, unsigned int n_qp)
Init dual_phi and potentially dual_dphi, dual_d2phi.
Definition fe.C:411
bool matches_cache(const Elem *elem)
Check if the node locations, edge and face orientations held in the element cache match those of elem...
Definition fe.C:174
static void dofs_on_edge(const Elem *const elem, const Order o, unsigned int e, std::vector< unsigned int > &di, bool add_p_level=true)
Fills the vector di with the local degree of freedom indices associated with edge e of element elem.
Definition fe.C:126
virtual void attach_quadrature_rule(QBase *q) override
Provides the class with the quadrature rule, which provides the locations (on a reference element) wh...
Definition fe.C:87
void cache(const Elem *elem)
Repopulate the element cache with the node locations, edge and face orientations of the element elem.
Definition fe.C:153
static void default_side_nodal_soln(const Elem *elem, const Order o, const unsigned int side, const std::vector< Number > &elem_soln, std::vector< Number > &nodal_soln_on_side, bool add_p_level=true, const unsigned vdim=1)
A default implementation for side_nodal_soln.
Definition fe.C:754
virtual void reinit_default_dual_shape_coeffs(const Elem *elem) override
This computes the default dual shape function coefficients.
Definition fe.C:394
static void all_shape_derivs(const Elem *elem, const Order o, const std::vector< Point > &p, std::vector< std::vector< OutputShape > > *comps[3], const bool add_p_level=true)
Fills comps with dphidxi (and in higher dimensions, eta/zeta) derivative component values for all sha...
static OutputShape shape_second_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
virtual void init_base_shape_functions(const std::vector< Point > &qp, const Elem *e) override
Initialize the data fields for the base of an an infinite element.
Definition fe.C:778
virtual void reinit_dual_shape_coeffs(const Elem *elem, const std::vector< Point > &pts, const std::vector< Real > &JxW) override
This re-computes the dual shape function coefficients.
Definition fe.C:371
static void default_all_shape_derivs(const Elem *elem, const Order o, const std::vector< Point > &p, std::vector< std::vector< OutputShape > > *comps[3], const bool add_p_level=true)
A default implementation for all_shape_derivs.
Definition fe.C:736
static void dofs_on_side(const Elem *const elem, const Order o, unsigned int s, std::vector< unsigned int > &di, bool add_p_level=true)
Fills the vector di with the local degree of freedom indices associated with side s of element elem.
Definition fe.C:99
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
The QBase class provides the basic functionality from which various quadrature rules can be derived.
Definition quadrature.h:62
const std::vector< Point > & get_points() const
Definition quadrature.h:156
const std::vector< Real > & get_weights() const
Definition quadrature.h:168
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
This class implements specific orders of Gauss quadrature.
Abstract base class for runtime singleton setup.
The libMesh namespace provides an interface to certain functionality in the library.
INSTANTIATE_FE(0)
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:153
OutputShape fe_fdm_deriv(const Elem *elem, const Order order, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level, OutputShape(*shape_func)(const Elem *, const Order, const unsigned int, const Point &, const bool))
Helper functions for finite differenced derivatives in cases where analytical calculations haven't be...
Definition fe.C:911
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
ElemType
Defines an enum for geometric element types.
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
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
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)
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
libmesh_assert(ctx)
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
libMesh::CachingSetup caching_setup
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
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
INSTANTIATE_SUBDIVISION_FE
Definition fe.C:1463
static const bool * caching
Definition fe.C:48
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))
template Real fe_fdm_second_deriv< Real >(const ElemType, const Order, const unsigned int, const unsigned int, const Point &, Real(*shape_func)(const ElemType, const Order, const unsigned int, const unsigned int, const Point &))
template Real fe_fdm_deriv< Real >(const Elem *, const Order, const unsigned int, const unsigned int, const Point &, const bool, Real(*shape_func)(const Elem *, const Order, const unsigned int, const Point &, const bool))
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
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))
RealVectorValue RealGradient
bool on_command_line(std::string arg)
Definition libmesh.C:934
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:176
Most finite element types in libMesh are scalar-valued.
Definition fe.h:52
const dof_id_type n_nodes
Definition tecplot_io.C:67