Line data Source code
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 372 : void nonlagrange_dual_warning () {
37 : libmesh_warning("dual calculations have only been verified for the LAGRANGE family");
38 372 : }
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 :
50 : class CachingSetup: public Singleton::Setup
51 : {
52 : private:
53 16843 : void setup() { caching = new bool(!on_command_line("--disable-caching")); }
54 : public:
55 16389 : ~CachingSetup() { delete caching; caching = nullptr; }
56 : } caching_setup;
57 :
58 :
59 : // ------------------------------------------------------------
60 : // FE class members
61 : template <unsigned int Dim, FEFamily T>
62 15325910 : FE<Dim,T>::FE (const FEType & fet) :
63 : FEGenericBase<typename FEOutputType<T>::type> (Dim,fet),
64 13587597 : last_side(INVALID_ELEM),
65 15325910 : 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 869451 : libmesh_assert_equal_to (T, this->get_family());
71 15325910 : }
72 :
73 :
74 : template <unsigned int Dim, FEFamily T>
75 0 : unsigned int FE<Dim,T>::n_shape_functions () const
76 : {
77 0 : if (this->_elem)
78 0 : return this->n_dofs (this->_elem,
79 0 : this->fe_type.order + this->_p_level);
80 :
81 0 : return this->n_dofs (this->get_type(),
82 0 : this->fe_type.order + this->_p_level);
83 : }
84 :
85 :
86 : template <unsigned int Dim, FEFamily T>
87 12884294 : void FE<Dim,T>::attach_quadrature_rule (QBase * q)
88 : {
89 589951 : libmesh_assert(q);
90 12884294 : this->qrule = q;
91 : // make sure we don't cache results from a previous quadrature rule
92 12884294 : this->_elem = nullptr;
93 12884294 : this->_elem_type = INVALID_ELEM;
94 12884294 : return;
95 : }
96 :
97 :
98 : template <unsigned int Dim, FEFamily T>
99 476885 : 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 40563 : libmesh_assert(elem);
106 40563 : libmesh_assert_less (s, elem->n_sides());
107 :
108 40563 : di.clear();
109 40563 : unsigned int nodenum = 0;
110 476885 : const unsigned int n_nodes = elem->n_nodes();
111 6848420 : for (unsigned int n = 0; n != n_nodes; ++n)
112 : {
113 : const unsigned int n_dofs =
114 7392037 : n_dofs_at_node(*elem, static_cast<Order>(o + add_p_level*elem->p_level()), n);
115 6371535 : if (elem->is_node_on_side(n, s))
116 6171404 : for (unsigned int i = 0; i != n_dofs; ++i)
117 3456875 : di.push_back(nodenum++);
118 : else
119 3657006 : nodenum += n_dofs;
120 : }
121 476885 : }
122 :
123 :
124 :
125 : template <unsigned int Dim, FEFamily T>
126 119562 : 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 8709 : libmesh_assert(elem);
133 8709 : libmesh_assert_less (e, elem->n_edges());
134 :
135 8709 : di.clear();
136 8709 : unsigned int nodenum = 0;
137 119562 : const unsigned int n_nodes = elem->n_nodes();
138 2505660 : for (unsigned int n = 0; n != n_nodes; ++n)
139 : {
140 : const unsigned int n_dofs =
141 2737362 : n_dofs_at_node(*elem, static_cast<Order>(o + add_p_level*elem->p_level()), n);
142 2386098 : if (elem->is_node_on_edge(n, e))
143 818043 : for (unsigned int i = 0; i != n_dofs; ++i)
144 466305 : di.push_back(nodenum++);
145 : else
146 2034360 : nodenum += n_dofs;
147 : }
148 119562 : }
149 :
150 :
151 :
152 : template <unsigned int Dim, FEFamily T>
153 4774234 : void FE<Dim,T>::cache(const Elem * elem)
154 : {
155 4774234 : cached_nodes.resize(elem->n_nodes());
156 57296552 : for (auto n : elem->node_index_range())
157 61212954 : cached_nodes[n] = elem->point(n);
158 :
159 4774234 : if (FEInterface::orientation_dependent(T))
160 : {
161 3655740 : cached_edges.resize(elem->n_edges());
162 22631232 : for (auto n : elem->edge_index_range())
163 18975492 : cached_edges[n] = elem->positive_edge_orientation(n);
164 :
165 3655740 : cached_faces.resize(elem->n_faces());
166 12026854 : for (auto n : elem->face_index_range())
167 8371114 : cached_faces[n] = elem->positive_face_orientation(n);
168 : }
169 4774234 : }
170 :
171 :
172 :
173 : template <unsigned int Dim, FEFamily T>
174 117481366 : bool FE<Dim,T>::matches_cache(const Elem * elem)
175 : {
176 126897259 : bool m = cached_nodes.size() == elem->n_nodes();
177 166719434 : for (unsigned n = 1; m && n < elem->n_nodes(); n++)
178 52459826 : m = (elem->point(n) - elem->point(0)).relative_fuzzy_equals(cached_nodes[n] - cached_nodes[0]);
179 :
180 117481366 : if (FEInterface::orientation_dependent(T))
181 : {
182 3332063 : m &= cached_edges.size() == elem->n_edges();
183 4551583 : for (unsigned n = 0; m && n < elem->n_edges(); n++)
184 1219520 : m = elem->positive_edge_orientation(n) == cached_edges[n];
185 :
186 3332063 : m &= cached_faces.size() == elem->n_faces();
187 3687811 : for (unsigned n = 0; m && n < elem->n_faces(); n++)
188 355748 : m = elem->positive_face_orientation(n) == cached_faces[n];
189 : }
190 :
191 117481366 : return m;
192 : }
193 :
194 :
195 :
196 : template <unsigned int Dim, FEFamily T>
197 160343635 : 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 160343635 : this->determine_calculations();
207 :
208 : // Try to avoid calling init_shape_functions
209 : // even when shapes_need_reinit
210 13490119 : bool cached_elem_still_fits = false;
211 :
212 : // Most of the hard work happens when we have an actual element
213 160343635 : if (elem)
214 : {
215 : // Initialize the shape functions at the user-specified
216 : // points
217 160343635 : if (pts != nullptr)
218 : {
219 : // Set the type and p level for this element
220 41226766 : this->_elem = elem;
221 41226766 : this->_elem_type = elem->type();
222 41226766 : this->_elem_p_level = elem->p_level();
223 44925168 : this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
224 :
225 : // Initialize the shape functions
226 7396774 : this->_fe_map->template init_reference_to_physical_map<Dim>
227 33829992 : (*pts, elem);
228 41226766 : this->init_shape_functions (*pts, elem);
229 :
230 : // The shape functions do not correspond to the qrule
231 41226766 : 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 9791747 : libmesh_assert(this->qrule);
244 119116869 : this->qrule->init(*elem);
245 :
246 119116869 : if (this->qrule->shapes_need_reinit())
247 0 : 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 227262888 : if (this->get_type() != elem->type() ||
252 117864976 : (elem->runtime_topology() &&
253 108146019 : this->_elem != elem) ||
254 117864976 : this->_elem_p_level != elem->p_level() ||
255 246696927 : !this->shapes_on_quadrature ||
256 19168045 : elem->mapping_type() != LAGRANGE_MAP)
257 : {
258 : // Set the type and p level for this element
259 1635503 : this->_elem = elem;
260 1635503 : this->_elem_type = elem->type();
261 1635503 : this->_elem_p_level = elem->p_level();
262 1744647 : this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
263 :
264 : // Initialize the shape functions
265 328590 : this->_fe_map->template init_reference_to_physical_map<Dim>
266 1635503 : (this->qrule->get_points(), elem);
267 1744647 : this->init_shape_functions (this->qrule->get_points(), elem);
268 : }
269 : else
270 : {
271 117481366 : this->_elem = elem;
272 :
273 : // Check if cached element's nodes, edge and face orientations still fit
274 117481366 : cached_elem_still_fits = this->matches_cache(elem);
275 :
276 : // Initialize the shape functions if needed
277 117481366 : if (this->shapes_need_reinit() && !cached_elem_still_fits)
278 : {
279 978427 : this->_fe_map->template init_reference_to_physical_map<Dim>
280 3898713 : (this->qrule->get_points(), elem);
281 4224864 : 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 119116869 : if (this->shapes_need_reinit() && !cached_elem_still_fits && *caching)
287 4774234 : this->cache(elem);
288 :
289 : // The shape functions correspond to the qrule
290 119116869 : 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 0 : this->_elem = nullptr;
298 0 : this->_elem_type = INVALID_ELEM;
299 0 : this->_elem_p_level = 0;
300 0 : this->_p_level = 0;
301 :
302 0 : if (!pts)
303 : {
304 : if (T == SCALAR)
305 : {
306 0 : this->qrule->get_points() =
307 0 : std::vector<Point>(1,Point(0));
308 :
309 0 : this->qrule->get_weights() =
310 0 : std::vector<Real>(1,1);
311 : }
312 : else
313 : {
314 0 : this->qrule->get_points().clear();
315 0 : this->qrule->get_weights().clear();
316 : }
317 :
318 0 : this->init_shape_functions (this->qrule->get_points(), elem);
319 : }
320 : else
321 0 : this->init_shape_functions (*pts, elem);
322 : }
323 :
324 : // Compute the map for this element.
325 160343635 : if (pts != nullptr)
326 : {
327 41226766 : if (weights != nullptr)
328 : {
329 52000 : this->_fe_map->compute_map (this->dim, *weights, elem, this->calculate_d2phi);
330 : }
331 : else
332 : {
333 48531300 : std::vector<Real> dummy_weights (pts->size(), 1.);
334 41174766 : this->_fe_map->compute_map (this->dim, dummy_weights, elem, this->calculate_d2phi);
335 : }
336 : }
337 : else
338 : {
339 128641906 : 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 160343635 : if (!cached_elem_still_fits)
345 : {
346 117792099 : if (pts != nullptr)
347 41226766 : this->compute_shape_functions (elem,*pts);
348 : else
349 83440609 : this->compute_shape_functions(elem,this->qrule->get_points());
350 117792099 : if (this->calculate_dual)
351 : {
352 : if (T != LAGRANGE)
353 372 : 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 6348 : if (elem && this->calculate_default_dual_coeff)
362 6348 : 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 6348 : this->compute_dual_shape_functions();
366 : }
367 : }
368 160343635 : }
369 :
370 : template <unsigned int Dim, FEFamily T>
371 6348 : void FE<Dim,T>::reinit_dual_shape_coeffs(const Elem * elem,
372 : const std::vector<Point> & pts,
373 : const std::vector<Real> & JxW)
374 : {
375 : // Set the type and p level for this element
376 6348 : this->_elem = elem;
377 6348 : this->_elem_type = elem->type();
378 6348 : this->_elem_p_level = elem->p_level();
379 6773 : this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
380 :
381 850 : const unsigned int n_shapes =
382 5498 : this->n_dofs(elem, this->get_order());
383 :
384 1275 : std::vector<std::vector<OutputShape>> phi_vals;
385 6348 : phi_vals.resize(n_shapes);
386 108062 : for (const auto i : make_range(phi_vals.size()))
387 115594 : phi_vals[i].resize(pts.size());
388 :
389 6348 : all_shapes(elem, this->get_order(), pts, phi_vals);
390 6348 : this->compute_dual_shape_coeffs(JxW, phi_vals);
391 6348 : }
392 :
393 : template <unsigned int Dim, FEFamily T>
394 6348 : void FE<Dim,T>::reinit_default_dual_shape_coeffs (const Elem * elem)
395 : {
396 425 : libmesh_assert(elem);
397 :
398 425 : FEType default_fe_type(this->get_order(), T);
399 6773 : QGauss default_qrule(elem->dim(), default_fe_type.default_quadrature_order());
400 6348 : 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 6348 : 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 425 : this->set_calculate_default_dual_coeff(false);
407 6348 : }
408 :
409 :
410 : template <unsigned int Dim, FEFamily T>
411 6348 : void FE<Dim,T>::init_dual_shape_functions(const unsigned int n_shapes, const unsigned int n_qp)
412 : {
413 6348 : if (!this->calculate_dual)
414 0 : return;
415 :
416 425 : libmesh_assert_msg(this->calculate_phi,
417 : "dual shape function calculation relies on "
418 : "primal shape functions being calculated");
419 :
420 6348 : this->dual_phi.resize(n_shapes);
421 6348 : if (this->calculate_dphi)
422 6336 : this->dual_dphi.resize(n_shapes);
423 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
424 6348 : if (this->calculate_d2phi)
425 6086 : this->dual_d2phi.resize(n_shapes);
426 : #endif
427 :
428 108062 : for (auto i : index_range(this->dual_phi))
429 : {
430 108654 : this->dual_phi[i].resize(n_qp);
431 101714 : if (this->calculate_dphi)
432 108628 : this->dual_dphi[i].resize(n_qp);
433 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
434 101714 : if (this->calculate_d2phi)
435 106184 : this->dual_d2phi[i].resize(n_qp);
436 : #endif
437 : }
438 : }
439 :
440 : template <unsigned int Dim, FEFamily T>
441 45401603 : 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 8043712 : LOG_SCOPE("init_shape_functions()", "FE");
446 :
447 : // The number of quadrature points.
448 8043176 : const unsigned int n_qp = cast_int<unsigned int>(qp.size());
449 45401603 : this->_n_total_qp = n_qp;
450 :
451 : // Number of shape functions in the finite element approximation
452 : // space.
453 8043176 : const unsigned int n_approx_shape_functions =
454 37358427 : 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 4021856 : 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 45401603 : if (this->calculate_phi)
466 : {
467 42846257 : if (this->phi.size() == n_approx_shape_functions)
468 : {
469 37254985 : old_n_qp = n_approx_shape_functions ? this->phi[0].size() : 0;
470 3301750 : break;
471 : }
472 2142374 : this->phi.resize (n_approx_shape_functions);
473 : }
474 8146618 : if (this->calculate_dphi)
475 : {
476 4432748 : if (this->dphi.size() == n_approx_shape_functions)
477 : {
478 1852770 : old_n_qp = n_approx_shape_functions ? this->dphi[0].size() : 0;
479 213164 : break;
480 : }
481 2209487 : this->dphi.resize (n_approx_shape_functions);
482 2209487 : this->dphidx.resize (n_approx_shape_functions);
483 2209487 : this->dphidy.resize (n_approx_shape_functions);
484 2209487 : this->dphidz.resize (n_approx_shape_functions);
485 : }
486 :
487 6287471 : if (this->calculate_dphiref)
488 : {
489 : if (Dim > 0)
490 : {
491 3638141 : if (this->dphidxi.size() == n_approx_shape_functions)
492 : {
493 34935 : old_n_qp = n_approx_shape_functions ? this->dphidxi[0].size() : 0;
494 2985 : break;
495 : }
496 3348533 : this->dphidxi.resize (n_approx_shape_functions);
497 : }
498 :
499 : if (Dim > 1)
500 3052920 : this->dphideta.resize (n_approx_shape_functions);
501 :
502 : if (Dim > 2)
503 2384054 : this->dphidzeta.resize (n_approx_shape_functions);
504 : }
505 :
506 6258913 : if (this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
507 7023 : this->curl_phi.resize(n_approx_shape_functions);
508 :
509 6258913 : if (this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
510 11185 : this->div_phi.resize(n_approx_shape_functions);
511 :
512 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
513 6258913 : if (this->calculate_d2phi)
514 : {
515 1586721 : if (this->d2phi.size() == n_approx_shape_functions)
516 : {
517 0 : old_n_qp = n_approx_shape_functions ? this->d2phi[0].size() : 0;
518 0 : break;
519 : }
520 :
521 1483387 : this->d2phi.resize (n_approx_shape_functions);
522 1483387 : this->d2phidx2.resize (n_approx_shape_functions);
523 1483387 : this->d2phidxdy.resize (n_approx_shape_functions);
524 1483387 : this->d2phidxdz.resize (n_approx_shape_functions);
525 1483387 : this->d2phidy2.resize (n_approx_shape_functions);
526 1483387 : this->d2phidydz.resize (n_approx_shape_functions);
527 1483387 : this->d2phidz2.resize (n_approx_shape_functions);
528 :
529 : if (Dim > 0)
530 1483387 : this->d2phidxi2.resize (n_approx_shape_functions);
531 :
532 : if (Dim > 1)
533 : {
534 1197829 : this->d2phidxideta.resize (n_approx_shape_functions);
535 1197829 : this->d2phideta2.resize (n_approx_shape_functions);
536 : }
537 : if (Dim > 2)
538 : {
539 1164163 : this->d2phidxidzeta.resize (n_approx_shape_functions);
540 1164163 : this->d2phidetadzeta.resize (n_approx_shape_functions);
541 1164163 : this->d2phidzeta2.resize (n_approx_shape_functions);
542 : }
543 : }
544 : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
545 : }
546 : while (false);
547 :
548 45401603 : if (old_n_qp != n_qp)
549 55582335 : for (unsigned int i=0; i<n_approx_shape_functions; i++)
550 : {
551 49246488 : if (this->calculate_phi)
552 20012351 : this->phi[i].resize (n_qp);
553 :
554 49246488 : if (this->calculate_dphi)
555 : {
556 18327160 : this->dphi[i].resize (n_qp);
557 18327160 : this->dphidx[i].resize (n_qp);
558 18327160 : this->dphidy[i].resize (n_qp);
559 18327160 : this->dphidz[i].resize (n_qp);
560 : }
561 :
562 49240111 : if (this->calculate_dphiref)
563 : {
564 : if (Dim > 0)
565 28423488 : this->dphidxi[i].resize(n_qp);
566 :
567 : if (Dim > 1)
568 27208577 : this->dphideta[i].resize(n_qp);
569 :
570 : if (Dim > 2)
571 22650448 : this->dphidzeta[i].resize(n_qp);
572 : }
573 :
574 49246488 : if (this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
575 58194 : this->curl_phi[i].resize(n_qp);
576 :
577 49246488 : if (this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR))
578 92816 : this->div_phi[i].resize(n_qp);
579 :
580 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
581 49246488 : if (this->calculate_d2phi)
582 : {
583 13134965 : this->d2phi[i].resize (n_qp);
584 13134965 : this->d2phidx2[i].resize (n_qp);
585 13134965 : this->d2phidxdy[i].resize (n_qp);
586 13134965 : this->d2phidxdz[i].resize (n_qp);
587 13134965 : this->d2phidy2[i].resize (n_qp);
588 13134965 : this->d2phidydz[i].resize (n_qp);
589 13134965 : this->d2phidz2[i].resize (n_qp);
590 : if (Dim > 0)
591 13134965 : this->d2phidxi2[i].resize (n_qp);
592 : if (Dim > 1)
593 : {
594 11966378 : this->d2phidxideta[i].resize (n_qp);
595 11966378 : this->d2phideta2[i].resize (n_qp);
596 : }
597 : if (Dim > 2)
598 : {
599 11606097 : this->d2phidxidzeta[i].resize (n_qp);
600 11606097 : this->d2phidetadzeta[i].resize (n_qp);
601 11606097 : 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 11590807 : if (this->calculate_phi || this->calculate_dphi)
617 : {
618 10846151 : this->weight.resize (n_qp);
619 46769968 : for (unsigned int p=0; p<n_qp; p++)
620 48562168 : this->weight[p] = 1.;
621 : }
622 :
623 11590807 : if (this->calculate_dphi)
624 : {
625 4257362 : this->dweight.resize (n_qp);
626 4257362 : this->dphase.resize (n_qp);
627 15841385 : for (unsigned int p=0; p<n_qp; p++)
628 : {
629 11584023 : this->dweight[p].zero();
630 8524301 : 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 45202823 : if (this->calculate_dphiref && Dim > 0)
638 : {
639 23502630 : std::vector<std::vector<OutputShape>> * comps[3]
640 23502630 : { &this->dphidxi, &this->dphideta, &this->dphidzeta };
641 17004056 : 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 19049 : break;
652 : }
653 :
654 : //------------------------------------------------------------
655 : // 1D
656 2509323 : case 1:
657 : {
658 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
659 : // Compute the value of shape function i Hessians at quadrature point p
660 2736774 : if (this->calculate_d2phi)
661 1504803 : for (unsigned int i=0; i<n_approx_shape_functions; i++)
662 5891882 : for (unsigned int p=0; p<n_qp; p++)
663 4689280 : this->d2phidxi2[i][p] = FE<Dim, T>::shape_second_deriv(
664 4689280 : elem, this->fe_type.order, i, 0, qp[p], this->_add_p_level_in_reinit);
665 : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
666 :
667 227451 : break;
668 : }
669 :
670 :
671 :
672 : //------------------------------------------------------------
673 : // 2D
674 17483924 : case 2:
675 : {
676 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
677 : // Compute the value of shape function i Hessians at quadrature point p
678 19327293 : if (this->calculate_d2phi)
679 9246335 : for (unsigned int i=0; i<n_approx_shape_functions; i++)
680 55429666 : for (unsigned int p=0; p<n_qp; p++)
681 : {
682 47034584 : this->d2phidxi2[i][p] = FE<Dim, T>::shape_second_deriv(
683 47034584 : elem, this->fe_type.order, i, 0, qp[p], this->_add_p_level_in_reinit);
684 87013326 : this->d2phidxideta[i][p] = FE<Dim, T>::shape_second_deriv(
685 47034584 : elem, this->fe_type.order, i, 1, qp[p], this->_add_p_level_in_reinit);
686 47034584 : this->d2phideta2[i][p] = FE<Dim, T>::shape_second_deriv(
687 47034584 : 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 1843369 : break;
693 : }
694 :
695 :
696 :
697 : //------------------------------------------------------------
698 : // 3D
699 21206769 : case 3:
700 : {
701 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
702 : // Compute the value of shape function i Hessians at quadrature point p
703 23138756 : if (this->calculate_d2phi)
704 123459180 : for (unsigned int i=0; i<n_approx_shape_functions; i++)
705 391609763 : for (unsigned int p=0; p<n_qp; p++)
706 : {
707 273029274 : this->d2phidxi2[i][p] = FE<Dim, T>::shape_second_deriv(
708 273029274 : elem, this->fe_type.order, i, 0, qp[p], this->_add_p_level_in_reinit);
709 501090664 : this->d2phidxideta[i][p] = FE<Dim, T>::shape_second_deriv(
710 273029274 : elem, this->fe_type.order, i, 1, qp[p], this->_add_p_level_in_reinit);
711 501090664 : this->d2phideta2[i][p] = FE<Dim, T>::shape_second_deriv(
712 273029274 : elem, this->fe_type.order, i, 2, qp[p], this->_add_p_level_in_reinit);
713 501090664 : this->d2phidxidzeta[i][p] = FE<Dim, T>::shape_second_deriv(
714 273029274 : elem, this->fe_type.order, i, 3, qp[p], this->_add_p_level_in_reinit);
715 501090664 : this->d2phidetadzeta[i][p] = FE<Dim, T>::shape_second_deriv(
716 273029274 : elem, this->fe_type.order, i, 4, qp[p], this->_add_p_level_in_reinit);
717 273029274 : this->d2phidzeta2[i][p] = FE<Dim, T>::shape_second_deriv(
718 273029274 : 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 1931987 : break;
723 : }
724 :
725 :
726 : default:
727 : libmesh_error_msg("Invalid dimension Dim = " << Dim);
728 : }
729 :
730 45401603 : if (this->calculate_dual)
731 5394 : this->init_dual_shape_functions(n_approx_shape_functions, n_qp);
732 45401603 : }
733 :
734 : template <unsigned int Dim, FEFamily T>
735 : void
736 43677192 : FE<Dim,T>::default_all_shape_derivs (const Elem * elem,
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 152552174 : for (unsigned int d=0; d != Dim; ++d)
743 : {
744 108874982 : auto & comps_d = *comps[d];
745 1425361080 : for (auto i : index_range(comps_d))
746 : FE<Dim,T>::shape_derivs
747 1430485086 : (elem,o,i,d,p,comps_d[i],add_p_level);
748 : }
749 43677192 : }
750 :
751 :
752 : template <unsigned int Dim, FEFamily T>
753 : void
754 3216 : FE<Dim,T>::default_side_nodal_soln(const Elem * elem, const Order o,
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 536 : std::vector<Number> full_nodal_soln;
762 3216 : nodal_soln(elem, o, elem_soln, full_nodal_soln, add_p_level, vdim);
763 3216 : const std::vector<unsigned int> side_nodes =
764 3216 : elem->nodes_on_side(side);
765 :
766 536 : std::size_t n_side_nodes = side_nodes.size();
767 3216 : nodal_soln_on_side.resize(n_side_nodes);
768 22944 : for (auto n : make_range(n_side_nodes))
769 24660 : nodal_soln_on_side[n] = full_nodal_soln[side_nodes[n]];
770 3216 : }
771 :
772 :
773 :
774 :
775 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
776 :
777 : template <unsigned int Dim, FEFamily T>
778 2662 : void FE<Dim,T>::init_base_shape_functions(const std::vector<Point> & qp,
779 : const Elem * e)
780 : {
781 2662 : this->_elem = e;
782 2662 : this->_elem_type = e->type();
783 2662 : this->_fe_map->template init_reference_to_physical_map<Dim>(qp, e);
784 2662 : init_shape_functions(qp, e);
785 2662 : }
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 3483800262 : fdm_points(const unsigned int j, const Point & p)
796 : {
797 281635446 : libmesh_assert_less (j, LIBMESH_DIM);
798 :
799 : // cheat by using finite difference approximations:
800 281635446 : const Real eps = 1.e-6;
801 3483800262 : Point pp = p, pm = p;
802 :
803 3483800262 : switch (j)
804 : {
805 : // d()/dxi
806 131199192 : case 0:
807 : {
808 1612007960 : pp(0) += eps;
809 1612007960 : pm(0) -= eps;
810 1612007960 : break;
811 : }
812 :
813 : // d()/deta
814 94808674 : case 1:
815 : {
816 1172365656 : pp(1) += eps;
817 1172365656 : pm(1) -= eps;
818 1172365656 : break;
819 : }
820 :
821 : // d()/dzeta
822 55627580 : case 2:
823 : {
824 699426646 : pp(2) += eps;
825 699426646 : pm(2) -= eps;
826 699426646 : break;
827 : }
828 :
829 0 : default:
830 0 : libmesh_error_msg("Invalid derivative index j = " << j);
831 : }
832 :
833 3765435708 : return std::make_tuple(pp, pm, eps);
834 : }
835 :
836 : std::tuple<Point, Point, Real, unsigned int>
837 1585743489 : fdm_second_points(const unsigned int j, const Point & p)
838 : {
839 : // cheat by using finite difference approximations:
840 131324391 : const Real eps = 1.e-5;
841 1585743489 : Point pp = p, pm = p;
842 131324391 : unsigned int deriv_j = 0;
843 :
844 1585743489 : switch (j)
845 : {
846 : // d^2() / dxi^2
847 22461599 : case 0:
848 : {
849 271227443 : pp(0) += eps;
850 271227443 : pm(0) -= eps;
851 22461599 : deriv_j = 0;
852 271227443 : break;
853 : }
854 :
855 : // d^2() / dxi deta
856 22461599 : case 1:
857 : {
858 271227443 : pp(1) += eps;
859 271227443 : pm(1) -= eps;
860 22461599 : deriv_j = 0;
861 271227443 : break;
862 : }
863 :
864 : // d^2() / deta^2
865 22461599 : case 2:
866 : {
867 271227443 : pp(1) += eps;
868 271227443 : pm(1) -= eps;
869 22461599 : deriv_j = 1;
870 271227443 : break;
871 : }
872 :
873 : // d^2()/dxidzeta
874 21313198 : case 3:
875 : {
876 257353720 : pp(2) += eps;
877 257353720 : pm(2) -= eps;
878 21313198 : deriv_j = 0;
879 257353720 : break;
880 : } // d^2()/deta^2
881 :
882 : // d^2()/detadzeta
883 21313198 : case 4:
884 : {
885 257353720 : pp(2) += eps;
886 257353720 : pm(2) -= eps;
887 21313198 : deriv_j = 1;
888 257353720 : break;
889 : }
890 :
891 : // d^2()/dzeta^2
892 21313198 : case 5:
893 : {
894 257353720 : pp(2) += eps;
895 257353720 : pm(2) -= eps;
896 21313198 : deriv_j = 2;
897 257353720 : break;
898 : }
899 :
900 0 : default:
901 0 : libmesh_error_msg("Invalid shape function derivative j = " << j);
902 : }
903 :
904 1717067880 : return std::make_tuple(pp, pm, eps, deriv_j);
905 : }
906 :
907 : }
908 :
909 :
910 : template <typename OutputShape>
911 3335220990 : 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 276680352 : libmesh_assert(elem);
923 :
924 3335220990 : auto [pp, pm, eps] = fdm_points(j, p);
925 :
926 3335220990 : return (shape_func(elem, order, i, pp, add_p_level) -
927 3335220990 : shape_func(elem, order, i, pm, add_p_level))/2./eps;
928 : }
929 :
930 :
931 : template <typename OutputShape>
932 0 : 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 0 : auto [pp, pm, eps] = fdm_points(j, p);
942 :
943 0 : return (shape_func(type, order, i, pp) -
944 0 : shape_func(type, order, i, pm))/2./eps;
945 : }
946 :
947 :
948 : template <typename OutputShape>
949 148579272 : 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 148579272 : auto [pp, pm, eps] = fdm_points(j, p);
961 :
962 148579272 : return (shape_func(type, order, elem, i, pp) -
963 148579272 : shape_func(type, order, elem, i, pm))/2./eps;
964 : }
965 :
966 :
967 : template <typename OutputShape>
968 : OutputShape
969 1578358017 : fe_fdm_second_deriv(const Elem * elem,
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 1578358017 : auto [pp, pm, eps, deriv_j] = fdm_second_points(j, p);
981 :
982 1578358017 : return (deriv_func(elem, order, i, deriv_j, pp, add_p_level) -
983 1578358017 : deriv_func(elem, order, i, deriv_j, pm, add_p_level))/2./eps;
984 : }
985 :
986 :
987 : template <typename OutputShape>
988 : OutputShape
989 0 : fe_fdm_second_deriv(const ElemType type,
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 0 : auto [pp, pm, eps, deriv_j] = fdm_second_points(j, p);
1000 :
1001 0 : return (deriv_func(type, order, i, deriv_j, pp) -
1002 0 : deriv_func(type, order, i, deriv_j, pm))/2./eps;
1003 : }
1004 :
1005 :
1006 : template <typename OutputShape>
1007 : OutputShape
1008 7385472 : fe_fdm_second_deriv(const ElemType type,
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 7385472 : auto [pp, pm, eps, deriv_j] = fdm_second_points(j, p);
1021 :
1022 7385472 : return (deriv_func(type, order, elem, i, deriv_j, pp) -
1023 7385472 : deriv_func(type, order, elem, i, deriv_j, pm))/2./eps;
1024 : }
1025 :
1026 :
1027 447222 : void rational_fe_weighted_shapes(const Elem * elem,
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 447222 : const int extra_order = add_p_level * elem->p_level();
1034 :
1035 447222 : const int dim = elem->dim();
1036 :
1037 : const unsigned int n_sf =
1038 447222 : FEInterface::n_shape_functions(underlying_fe_type, extra_order,
1039 38757 : elem);
1040 :
1041 38757 : libmesh_assert_equal_to (n_sf, elem->n_nodes());
1042 :
1043 485979 : std::vector<Real> node_weights(n_sf);
1044 :
1045 77514 : const unsigned char datum_index = elem->mapping_data();
1046 5615830 : for (unsigned int n=0; n<n_sf; n++)
1047 5615965 : node_weights[n] =
1048 5168608 : elem->node_ref(n).get_extra_datum<Real>(datum_index);
1049 :
1050 77514 : const std::size_t n_p = p.size();
1051 :
1052 447222 : shapes.resize(n_sf);
1053 5615830 : for (unsigned int i=0; i != n_sf; ++i)
1054 : {
1055 5168608 : auto & shapes_i = shapes[i];
1056 5168608 : shapes_i.resize(n_p, 0);
1057 5168608 : FEInterface::shapes(dim, underlying_fe_type, elem, i, p,
1058 : shapes_i, add_p_level);
1059 27693992 : for (auto & s : shapes_i)
1060 24557857 : s *= node_weights[i];
1061 : }
1062 447222 : }
1063 :
1064 :
1065 561870 : void rational_fe_weighted_shapes_derivs(const Elem * elem,
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 561870 : const int extra_order = add_p_level * elem->p_level();
1073 561870 : const unsigned int dim = elem->dim();
1074 :
1075 : const unsigned int n_sf =
1076 561870 : FEInterface::n_shape_functions(fe_type, extra_order, elem);
1077 :
1078 49896 : libmesh_assert_equal_to (n_sf, elem->n_nodes());
1079 :
1080 49896 : libmesh_assert_equal_to (dim, derivs.size());
1081 1846502 : for (unsigned int d = 0; d != dim; ++d)
1082 1396520 : derivs[d].resize(n_sf);
1083 :
1084 611766 : std::vector<Real> node_weights(n_sf);
1085 :
1086 99792 : const unsigned char datum_index = elem->mapping_data();
1087 6745720 : for (unsigned int n=0; n<n_sf; n++)
1088 6731265 : node_weights[n] =
1089 6183850 : elem->node_ref(n).get_extra_datum<Real>(datum_index);
1090 :
1091 99792 : const std::size_t n_p = p.size();
1092 :
1093 561870 : shapes.resize(n_sf);
1094 6745720 : for (unsigned int i=0; i != n_sf; ++i)
1095 6731265 : shapes[i].resize(n_p, 0);
1096 :
1097 561870 : FEInterface::all_shapes(dim, fe_type, elem, p, shapes, add_p_level);
1098 :
1099 6745720 : for (unsigned int i=0; i != n_sf; ++i)
1100 : {
1101 6183850 : auto & shapes_i = shapes[i];
1102 :
1103 42928406 : for (auto & s : shapes_i)
1104 40114047 : s *= node_weights[i];
1105 :
1106 21210010 : for (unsigned int d = 0; d != dim; ++d)
1107 : {
1108 16335434 : auto & derivs_di = derivs[d][i];
1109 15026160 : derivs_di.resize(n_p);
1110 15026160 : FEInterface::shape_derivs(fe_type, elem, i, d, p,
1111 : derivs_di, add_p_level);
1112 96961110 : for (auto & dip : derivs_di)
1113 89357066 : dip *= node_weights[i];
1114 : }
1115 : }
1116 561870 : }
1117 :
1118 :
1119 23320440 : Real rational_fe_shape(const Elem & elem,
1120 : const FEType underlying_fe_type,
1121 : const unsigned int i,
1122 : const Point & p,
1123 : const bool add_p_level)
1124 : {
1125 23320440 : int extra_order = add_p_level * elem.p_level();
1126 :
1127 : const unsigned int n_sf =
1128 23320440 : FEInterface::n_shape_functions(underlying_fe_type, extra_order, &elem);
1129 :
1130 2116962 : libmesh_assert_equal_to (n_sf, elem.n_nodes());
1131 :
1132 23320440 : std::vector<Real> node_weights(n_sf);
1133 :
1134 4107474 : const unsigned char datum_index = elem.mapping_data();
1135 :
1136 2116962 : Real weighted_shape_i = 0, weighted_sum = 0;
1137 :
1138 318152052 : for (unsigned int sf=0; sf<n_sf; sf++)
1139 : {
1140 : Real node_weight =
1141 294831612 : elem.node_ref(sf).get_extra_datum<Real>(datum_index);
1142 : Real weighted_shape = node_weight *
1143 294831612 : FEInterface::shape(underlying_fe_type, extra_order, &elem, sf, p);
1144 294831612 : weighted_sum += weighted_shape;
1145 294831612 : if (sf == i)
1146 2116962 : weighted_shape_i = weighted_shape;
1147 : }
1148 :
1149 27427914 : return weighted_shape_i / weighted_sum;
1150 : }
1151 :
1152 :
1153 49542084 : Real rational_fe_shape_deriv(const Elem & elem,
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 4181172 : libmesh_assert_less(j, elem.dim());
1161 :
1162 49542084 : int extra_order = add_p_level * elem.p_level();
1163 :
1164 : const unsigned int n_sf =
1165 49542084 : FEInterface::n_shape_functions(underlying_fe_type, extra_order, &elem);
1166 :
1167 49542084 : const unsigned int n_nodes = elem.n_nodes();
1168 4181172 : libmesh_assert_equal_to (n_sf, n_nodes);
1169 :
1170 49542084 : std::vector<Real> node_weights(n_nodes);
1171 :
1172 8362344 : const unsigned char datum_index = elem.mapping_data();
1173 754581492 : for (unsigned int n=0; n<n_nodes; n++)
1174 761551656 : node_weights[n] =
1175 705039408 : elem.node_ref(n).get_extra_datum<Real>(datum_index);
1176 :
1177 4181172 : Real weighted_shape_i = 0, weighted_sum = 0,
1178 4181172 : weighted_grad_i = 0, weighted_grad_sum = 0;
1179 :
1180 754581492 : for (unsigned int sf=0; sf<n_sf; sf++)
1181 : {
1182 705039408 : Real weighted_shape = node_weights[sf] *
1183 705039408 : FEInterface::shape(underlying_fe_type, extra_order, &elem, sf, p);
1184 705039408 : Real weighted_grad = node_weights[sf] *
1185 705039408 : FEInterface::shape_deriv(underlying_fe_type, extra_order, &elem, sf, j, p);
1186 705039408 : weighted_sum += weighted_shape;
1187 705039408 : weighted_grad_sum += weighted_grad;
1188 705039408 : if (sf == i)
1189 : {
1190 4181172 : weighted_shape_i = weighted_shape;
1191 4181172 : weighted_grad_i = weighted_grad;
1192 : }
1193 : }
1194 :
1195 49542084 : return (weighted_sum * weighted_grad_i - weighted_shape_i * weighted_grad_sum) /
1196 57904428 : weighted_sum / weighted_sum;
1197 : }
1198 :
1199 :
1200 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1201 :
1202 13696218 : Real rational_fe_shape_second_deriv(const Elem & elem,
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 1111222 : switch (j)
1211 : {
1212 189701 : case 0:
1213 : // j = 0 ==> d^2 phi / dxi^2
1214 189701 : j1 = j2 = 0;
1215 189701 : break;
1216 189412 : case 1:
1217 : // j = 1 ==> d^2 phi / dxi deta
1218 189412 : j1 = 0;
1219 189412 : j2 = 1;
1220 189412 : break;
1221 189412 : case 2:
1222 : // j = 2 ==> d^2 phi / deta^2
1223 189412 : j1 = j2 = 1;
1224 189412 : break;
1225 180899 : case 3:
1226 : // j = 3 ==> d^2 phi / dxi dzeta
1227 180899 : j1 = 0;
1228 180899 : j2 = 2;
1229 180899 : break;
1230 180899 : case 4:
1231 : // j = 4 ==> d^2 phi / deta dzeta
1232 180899 : j1 = 1;
1233 180899 : j2 = 2;
1234 180899 : break;
1235 180899 : case 5:
1236 : // j = 5 ==> d^2 phi / dzeta^2
1237 180899 : j1 = j2 = 2;
1238 180899 : break;
1239 0 : default:
1240 0 : libmesh_error();
1241 : }
1242 :
1243 13696218 : int extra_order = add_p_level * elem.p_level();
1244 :
1245 : const unsigned int n_sf =
1246 13696218 : FEInterface::n_shape_functions(underlying_fe_type, extra_order,
1247 1111222 : &elem);
1248 :
1249 13696218 : const unsigned int n_nodes = elem.n_nodes();
1250 1111222 : libmesh_assert_equal_to (n_sf, n_nodes);
1251 :
1252 13696218 : std::vector<Real> node_weights(n_nodes);
1253 :
1254 2222444 : const unsigned char datum_index = elem.mapping_data();
1255 308030160 : for (unsigned int n=0; n<n_nodes; n++)
1256 318740822 : node_weights[n] =
1257 294333942 : elem.node_ref(n).get_extra_datum<Real>(datum_index);
1258 :
1259 1111222 : Real weighted_shape_i = 0, weighted_sum = 0,
1260 1111222 : weighted_grada_i = 0, weighted_grada_sum = 0,
1261 1111222 : weighted_gradb_i = 0, weighted_gradb_sum = 0,
1262 1111222 : weighted_hess_i = 0, weighted_hess_sum = 0;
1263 :
1264 308030160 : for (unsigned int sf=0; sf<n_sf; sf++)
1265 : {
1266 294333942 : Real weighted_shape = node_weights[sf] *
1267 294333942 : FEInterface::shape(underlying_fe_type, extra_order, &elem, sf,
1268 294333942 : p);
1269 294333942 : Real weighted_grada = node_weights[sf] *
1270 294333942 : FEInterface::shape_deriv(underlying_fe_type, extra_order,
1271 294333942 : &elem, sf, j1, p);
1272 294333942 : Real weighted_hess = node_weights[sf] *
1273 294333942 : FEInterface::shape_second_deriv(underlying_fe_type,
1274 294333942 : extra_order, &elem, sf, j, p);
1275 294333942 : weighted_sum += weighted_shape;
1276 294333942 : weighted_grada_sum += weighted_grada;
1277 24406880 : Real weighted_gradb = weighted_grada;
1278 294333942 : if (j1 != j2)
1279 : {
1280 146828754 : weighted_gradb = (j1 == j2) ? weighted_grada :
1281 146828754 : node_weights[sf] *
1282 146828754 : FEInterface::shape_deriv(underlying_fe_type, extra_order,
1283 : &elem, sf, j2, p);
1284 146828754 : weighted_grada_sum += weighted_grada;
1285 : }
1286 294333942 : weighted_hess_sum += weighted_hess;
1287 294333942 : if (sf == i)
1288 : {
1289 1111222 : weighted_shape_i = weighted_shape;
1290 1111222 : weighted_grada_i = weighted_grada;
1291 1111222 : weighted_gradb_i = weighted_gradb;
1292 1111222 : weighted_hess_i = weighted_hess;
1293 : }
1294 : }
1295 :
1296 13696218 : if (j1 == j2)
1297 560012 : weighted_gradb_sum = weighted_grada_sum;
1298 :
1299 15918662 : return (weighted_sum * weighted_hess_i - weighted_grada_i * weighted_gradb_sum -
1300 18141106 : weighted_shape_i * weighted_hess_sum - weighted_gradb_i * weighted_grada_sum +
1301 15918662 : 2 * weighted_grada_sum * weighted_shape_i * weighted_gradb_sum / weighted_sum) /
1302 15918662 : weighted_sum / weighted_sum;
1303 : }
1304 :
1305 : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1306 :
1307 :
1308 447222 : 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 116271 : std::vector<std::vector<Real>> shapes;
1315 :
1316 447222 : rational_fe_weighted_shapes(&elem, underlying_fe_type, shapes, p,
1317 : add_p_level);
1318 :
1319 524736 : std::vector<Real> shape_sums(p.size(), 0);
1320 :
1321 5615830 : for (auto i : index_range(v))
1322 : {
1323 447357 : libmesh_assert_equal_to ( p.size(), shapes[i].size() );
1324 27693992 : for (auto j : index_range(p))
1325 28622803 : shape_sums[j] += shapes[i][j];
1326 : }
1327 :
1328 5615830 : for (auto i : index_range(v))
1329 : {
1330 447357 : libmesh_assert_equal_to ( p.size(), v[i].size() );
1331 27693992 : for (auto j : index_range(v[i]))
1332 30655276 : v[i][j] = shapes[i][j] / shape_sums[j];
1333 : }
1334 447222 : }
1335 :
1336 :
1337 : template <typename OutputShape>
1338 561870 : 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 561870 : const int my_dim = elem.dim();
1345 :
1346 149688 : std::vector<std::vector<Real>> shapes;
1347 661662 : std::vector<std::vector<std::vector<Real>>> derivs(my_dim);
1348 :
1349 561870 : rational_fe_weighted_shapes_derivs(&elem, underlying_fe_type,
1350 : shapes, derivs, p, add_p_level);
1351 :
1352 661662 : std::vector<Real> shape_sums(p.size(), 0);
1353 661662 : std::vector<std::vector<Real>> shape_deriv_sums(my_dim);
1354 1846502 : for (int d=0; d != my_dim; ++d)
1355 1508408 : shape_deriv_sums[d].resize(p.size());
1356 :
1357 6745720 : for (auto i : index_range(shapes))
1358 : {
1359 547415 : libmesh_assert_equal_to ( p.size(), shapes[i].size() );
1360 42928406 : for (auto j : index_range(p))
1361 43483538 : shape_sums[j] += shapes[i][j];
1362 :
1363 21210010 : for (int d=0; d != my_dim; ++d)
1364 96961110 : for (auto j : index_range(p))
1365 119045530 : shape_deriv_sums[d][j] += derivs[d][i][j];
1366 : }
1367 :
1368 1846502 : for (int d=0; d != my_dim; ++d)
1369 : {
1370 1284632 : auto & comps_d = *comps[d];
1371 111888 : libmesh_assert_equal_to(comps_d.size(), elem.n_nodes());
1372 :
1373 16310792 : for (auto i : index_range(comps_d))
1374 : {
1375 1309274 : auto & comps_di = comps_d[i];
1376 3927822 : auto & derivs_di = derivs[d][i];
1377 :
1378 96961110 : for (auto j : index_range(comps_di))
1379 111623414 : comps_di[j] = (shape_sums[j] * derivs_di[j] -
1380 96779182 : shapes[i][j] * shape_deriv_sums[d][j]) /
1381 81934950 : shape_sums[j] / shape_sums[j];
1382 : }
1383 : }
1384 1023948 : }
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
1410 : RealGradient
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
1442 : RealGradient
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 :
1463 : INSTANTIATE_SUBDIVISION_FE;
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
|