libMesh
Loading...
Searching...
No Matches
inf_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/libmesh_config.h"
22
23#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
24
25#include "libmesh/inf_fe.h"
26#include "libmesh/fe.h"
27#include "libmesh/quadrature_gauss.h"
28#include "libmesh/elem.h"
29#include "libmesh/libmesh_logging.h"
30#include "libmesh/int_range.h"
31#include "libmesh/type_tensor.h"
32#include "libmesh/fe_interface.h"
33
34#include <memory>
35
36namespace libMesh
37{
38
39
40
41// Constructor
42template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
44 FEBase (Dim, fet),
45
46 calculate_map_scaled(false),
47 calculate_phi_scaled(false),
48 calculate_dphi_scaled(false),
49 calculate_xyz(false),
50 calculate_jxw(false),
51 _n_total_approx_sf (0),
52
53 // initialize the current_fe_type to all the same
54 // values as \p fet (since the FE families and coordinate
55 // map type should not change), but use an invalid order
56 // for the radial part (since this is the only order
57 // that may change!).
58 // the data structures like \p phi etc are not initialized
59 // through the constructor, but through reinit()
60 current_fe_type (FEType(fet.order,
61 fet.family,
63 fet.radial_family,
64 fet.inf_map))
65
66{
67 // Sanity checks
68 libmesh_assert_equal_to (T_radial, fe_type.radial_family);
69 libmesh_assert_equal_to (T_map, fe_type.inf_map);
70
71 // build the base_fe object
72 if (Dim != 1)
73 base_fe = FEBase::build(Dim-1, fet);
74}
75
76
77
78template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
80{
82 libmesh_assert(base_fe);
83
84 const Order base_int_order = q->get_order();
85 const Order radial_int_order = static_cast<Order>(2 * (static_cast<unsigned int>(fe_type.radial_order.get_order()) + 1) +2);
86 const unsigned int qrule_dim = q->get_dim();
87
88 if (Dim != 1)
89 {
90 // build a Dim-1 quadrature rule of the type that we received
91 base_qrule = QBase::build(q->type(), qrule_dim-1, base_int_order);
92 base_fe->attach_quadrature_rule(base_qrule.get());
93 }
94
95 // in radial direction, always use Gauss quadrature
96 radial_qrule = std::make_unique<QGauss>(1, radial_int_order);
97
98 // Maybe helpful to store the QBase *
99 // with which we initialized our own quadrature rules.
100 // Used e.g. in \p InfFE::reinit(elem,side)
101 qrule = q;
102}
103
104
105
106
107
108template <unsigned int Dim, FEFamily T_radial, InfMapType T_base>
110{
111 base_elem = InfFEBase::build_elem(inf_elem);
112}
113
114
115
116
117
118
119template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
121 const std::vector<Point> * const pts,
122 const std::vector<Real> * const weights)
123{
124 libmesh_assert(base_fe.get());
125 libmesh_assert(inf_elem);
126
127 // checks for consistency of requested calculations,
128 // adds further quantities as needed.
129 this->determine_calculations();
130
131 if (pts == nullptr)
132 {
133 libmesh_assert(base_fe->qrule);
134 libmesh_assert_equal_to (base_fe->qrule, base_qrule.get());
135 libmesh_assert(radial_qrule.get());
136
137 bool init_shape_functions_required = false;
138
139 // init the radial data fields only when the radial order changes
140 if (current_fe_type.radial_order != fe_type.radial_order)
141 {
142 current_fe_type.radial_order = fe_type.radial_order;
143
144 // Watch out: this call to QBase->init() only works for
145 // current_fe_type = const! To allow variable Order,
146 // the init() of QBase has to be modified...
147 radial_qrule->init(EDGE2);
148
149 // initialize the radial shape functions
150 this->init_radial_shape_functions(inf_elem);
151
152 init_shape_functions_required=true;
153 }
154
155
156 bool update_base_elem_required=true;
157
158 // update the type in accordance to the current cell
159 // and reinit if the cell type has changed or (as in
160 // the case of the hierarchics) the shape functions
161 // depend on the particular element and need a reinit
162 if ((Dim != 1) &&
163 ((this->get_type() != inf_elem->type()) ||
164 (base_fe->shapes_need_reinit())))
165 {
166 // store the new element type, update base_elem
167 // here. Through \p update_base_elem_required,
168 // remember whether it has to be updated (see below).
169 this->_elem = inf_elem;
170 this->_elem_type = inf_elem->type();
171 this->update_base_elem(inf_elem);
172 update_base_elem_required=false;
173
174 // initialize the base quadrature rule for the new element
175 base_qrule->init(*base_elem);
176 init_shape_functions_required=true;
177
178 }
179 else
180 this->_elem = inf_elem;
181
182 // computing the reference-to-physical map and coordinates works
183 // only, if we have the current base_elem stored.
184 // This happens when fe_type is const,
185 // the inf_elem->type remains the same. Then we have to
186 // update the base elem _here_.
187 if (update_base_elem_required)
188 this->update_base_elem(inf_elem);
189
190 if (calculate_phi_scaled || calculate_dphi_scaled || calculate_phi || calculate_dphi)
191 // initialize the shape functions in the base
192 base_fe->init_base_shape_functions(base_fe->qrule->get_points(),
193 base_elem.get());
194
195 // compute the shape functions and map functions of base_fe
196 // before using them later in compute_shape_functions.
197 base_fe->_fe_map->compute_map (base_fe->dim, base_fe->qrule->get_weights(),
198 base_elem.get(), base_fe->calculate_d2phi);
199 base_fe->compute_shape_functions(base_elem.get(), base_fe->qrule->get_points());
200
201 // when either the radial or base part change,
202 // we have to init the whole fields
203 if (init_shape_functions_required)
204 this->init_shape_functions (radial_qrule->get_points(),
205 base_fe->qrule->get_points(),
206 inf_elem);
207
208 // Compute the shape functions and the derivatives
209 // at all quadrature points.
210 this->compute_shape_functions (inf_elem,
211 base_fe->qrule->get_points(),
212 radial_qrule->get_points()
213 /* weights are computed inside the function*/
214 );
215 }
216
217 else // if pts != nullptr
218 {
219 // update the elem
220 this->_elem = inf_elem;
221 this->_elem_type = inf_elem->type();
222
223 // We'll assume that pts is a tensor product mesh of points.
224 // pts[i] = pts[ angular_index + n_angular_pts * radial_index]
225 // That will handle the pts.size()==1 case that we care about
226 // right now, and it will generalize a bit, and it won't break
227 // the assumptions elsewhere in InfFE.
228 std::vector<Point> radial_pts;
229 if (pts->size() > 0)
230 {
231 Real radius = (*pts)[0](Dim-1);
232 radial_pts.push_back(radius);
233 unsigned int n_radial_pts=1;
234 unsigned int n_angular_pts=1;
235 for (auto p : IntRange<std::size_t>(1, pts->size()))
236 {
237 radius = (*pts)[p](Dim-1);
238 // check for changes of radius: The max. allowed distance is somewhat arbitrary
239 // but the given value should not produce false positives...
240 if (std::abs(radial_pts[n_radial_pts-1](0) - radius) > 1e-4)
241 {
242 // it may change only every n_angular_pts:
243 if (p == (n_radial_pts)*n_angular_pts)
244 {
245 radial_pts.push_back(radius);
246 ++n_radial_pts;
247 }
248 else
249 {
250 libmesh_error_msg("We assumed that the "<<pts->size()
251 <<" points are of tensor-product type with "
252 <<n_radial_pts<<" radial points and "
253 <<n_angular_pts<< " angular points."<<std::endl
254 <<"But apparently point "<<p+1
255 <<" does not fit that scheme: Its radius is "
256 <<radius <<"but should have "
257 <<radial_pts[n_radial_pts*n_angular_pts-p]<<".");
258 //<<radial_pts[p-n_radial_pts*n_angular_pts]<<".");
259 }
260 }
261 // if we are still at the first radial segment,
262 // we consider another angular point
263 else if (n_radial_pts == 1)
264 {
265 ++n_angular_pts;
266 }
267 // if there was repetition but this does not, the assumed
268 // format does not work:
269 }
270 }
271 else
272 {
273 // I don't see any reason to call this function with no points.
274 libmesh_error_msg("Calling reinit() with an empty point list is prohibited.\n");
275 }
276
277 const std::size_t radial_pts_size = radial_pts.size();
278 const std::size_t base_pts_size = pts->size() / radial_pts_size;
279 // If we're a tensor product we should have no remainder
280 libmesh_assert_equal_to
281 (base_pts_size * radial_pts_size, pts->size());
282
283
284 std::vector<Point> base_pts;
285 base_pts.reserve(base_pts_size);
286 for (std::size_t p=0; p != base_pts_size; ++p)
287 {
288 Point pt = (*pts)[p];
289 pt(Dim-1) = 0;
290 base_pts.push_back(pt);
291 }
292
293 // init radial shapes
294 this->init_radial_shape_functions(inf_elem, &radial_pts);
295
296 // update the base
297 this->update_base_elem(inf_elem);
298
299 // the finite element on the ifem base
300 base_fe = FEBase::build(Dim-1, this->fe_type);
301
302 // having a new base_fe, we need to redetermine the tasks...
303 this->determine_calculations();
304
305 base_fe->reinit( base_elem.get(), &base_pts);
306
307 this->init_shape_functions (radial_pts, base_pts, inf_elem);
308
309 // finally compute the ifem shapes
310 if (weights != nullptr)
311 {
312 this->compute_shape_functions (inf_elem,base_pts,radial_pts);
313 }
314 else
315 {
316 this->compute_shape_functions (inf_elem, base_pts, radial_pts);
317 }
318
319 }
320
321 if (this->calculate_dual)
322 libmesh_not_implemented_msg("Dual shape support for infinite elements is "
323 "not currently implemented");
324}
325
326
327
328template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
330{
331 this->calculations_started = true;
332
333 // If the user did not explicitly pre-request something (or nothing)
334 // to be computed, then we throw an error here.
335 bool requested_ok =
336 this->calculate_nothing || this->calculate_phi ||
337 this->calculate_dphi || this->calculate_dphiref ||
338 this->calculate_phi_scaled || this->calculate_dphi_scaled ||
339 this->calculate_xyz || this->calculate_jxw ||
340 this->calculate_map_scaled || this->calculate_map ||
341 this->calculate_curl_phi || this->calculate_div_phi;
342
343#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
344 requested_ok = requested_ok || this->calculate_d2phi;
345#endif
346
347 libmesh_error_msg_if(
348 !requested_ok,
349 "You must call one or more of the FE accessors "
350 "(e.g. get_phi(), get_dphi(), get_nothing()) "
351 "_before_ calling reinit()!");
352
353 // set further terms necessary to do the requested task
354 if (calculate_jxw)
355 this->calculate_map = true;
356 if (this->calculate_dphi)
357 this->calculate_map = true;
358 if (this->calculate_dphi_scaled)
359 this->calculate_map_scaled = true;
360 // if Cartesian positions were requested but the calculation of map
361 // was not triggered, we'll opt for the 'scaled' variant.
362 if (calculate_xyz && !calculate_map)
363 this->calculate_map_scaled = true;
364 base_fe->calculate_phi = this->calculate_phi || this->calculate_phi_scaled
365 || this->calculate_dphi || this->calculate_dphi_scaled;
366 base_fe->calculate_dphi = this->calculate_dphi || this->calculate_dphi_scaled;
367 if (this->calculate_map || this->calculate_map_scaled
368 || this->calculate_dphiref)
369 {
370 base_fe->calculate_dphiref = true;
371 base_fe->get_xyz(); // trigger base_fe->fe_map to 'calculate_xyz'
372 base_fe->get_JxW(); // trigger base_fe->fe_map to 'calculate_dxyz'
373 }
374 base_fe->determine_calculations();
375
376#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
377 if (this->calculate_d2phi)
378 libmesh_not_implemented();
379#endif //LIBMESH_ENABLE_SECOND_DERIVATIVES
380}
381
382
383
384template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
385void
387init_radial_shape_functions(const Elem * libmesh_dbg_var(inf_elem),
388 const std::vector<Point> * radial_pts)
389{
390 libmesh_assert(radial_qrule.get() || radial_pts);
391 libmesh_assert(inf_elem);
392
393 // Start logging the radial shape function initialization
394 LOG_SCOPE("init_radial_shape_functions()", "InfFE");
395
396 // initialize most of the things related to physical approximation
397 const Order radial_approx_order = fe_type.radial_order;
398 const unsigned int n_radial_approx_shape_functions =
399 InfFERadial::n_dofs(radial_approx_order);
400
401 const std::size_t n_radial_qp =
402 radial_pts ? radial_pts->size() : radial_qrule->n_points();
403 const std::vector<Point> & radial_qp =
404 radial_pts ? *radial_pts : radial_qrule->get_points();
405
406 // the radial polynomials (eval)
407 if (calculate_phi || calculate_dphi || calculate_phi_scaled || calculate_dphi_scaled)
408 {
409 mode.resize (n_radial_approx_shape_functions);
410 for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
411 mode[i].resize (n_radial_qp);
412
413 // evaluate the mode shapes in radial direction at radial quadrature points
414 for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
415 for (std::size_t p=0; p<n_radial_qp; ++p)
416 mode[i][p] = InfFE<Dim,T_radial,T_map>::eval (radial_qp[p](0), radial_approx_order, i);
417 }
418
419 if (calculate_dphi || calculate_dphi_scaled)
420 {
421 dmodedv.resize (n_radial_approx_shape_functions);
422 for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
423 dmodedv[i].resize (n_radial_qp);
424
425 // evaluate the mode shapes in radial direction at radial quadrature points
426 for (unsigned int i=0; i<n_radial_approx_shape_functions; ++i)
427 for (std::size_t p=0; p<n_radial_qp; ++p)
428 dmodedv[i][p] = InfFE<Dim,T_radial,T_map>::eval_deriv (radial_qp[p](0), radial_approx_order, i);
429 }
430
431 // the (1-v)/2 weight.
432 if (calculate_phi || calculate_phi_scaled || calculate_dphi || calculate_dphi_scaled)
433 {
434 som.resize (n_radial_qp);
435 // compute scalar values at radial quadrature points
436 for (std::size_t p=0; p<n_radial_qp; ++p)
437 som[p] = InfFERadial::decay (Dim, radial_qp[p](0));
438 }
439 if (calculate_dphi || calculate_dphi_scaled)
440 {
441 dsomdv.resize (n_radial_qp);
442 // compute scalar values at radial quadrature points
443 for (std::size_t p=0; p<n_radial_qp; ++p)
444 dsomdv[p] = InfFERadial::decay_deriv (Dim, radial_qp[p](0));
445 }
446}
447
448
449
450template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
451void InfFE<Dim,T_radial,T_map>::init_shape_functions(const std::vector<Point> & radial_qp,
452 const std::vector<Point> & base_qp,
453 const Elem * inf_elem)
454{
455 libmesh_assert(inf_elem);
456
457 // Start logging the radial shape function initialization
458 LOG_SCOPE("init_shape_functions()", "InfFE");
459
460 // fast access to some const ints for the radial data
461 const unsigned int n_radial_approx_sf = InfFERadial::n_dofs(fe_type.radial_order);
462 const std::size_t n_radial_qp = radial_qp.size();
463#ifdef DEBUG
464 if (calculate_phi || calculate_dphi || calculate_phi_scaled || calculate_dphi_scaled)
465 libmesh_assert_equal_to(n_radial_approx_sf, mode.size());
466 if (calculate_phi || calculate_dphi || calculate_dphi_scaled)
467 libmesh_assert_equal_to(som.size(), n_radial_qp);
468#endif
469
470
471 // initialize most of the quantities related to mapping
472
473 // The element type and order to use in the base map
474 //const Order base_mapping_order = base_elem->default_order();
475
476 // the number of base shape functions used to construct the map
477 // (Lagrange shape functions are used for mapping in the base)
478 //unsigned int n_base_mapping_shape_functions =
479 // InfFEBase::n_base_mapping_sf(*base_elem,
480 // base_mapping_order);
481
482 // initialize most of the things related to physical approximation
483 unsigned int n_base_approx_shape_functions;
484 if (Dim > 1)
485 n_base_approx_shape_functions =
486 FEInterface::n_dofs(base_fe->get_fe_type(), base_elem.get());
487 else
488 n_base_approx_shape_functions = 1;
489
490
491 // update class member field
492 _n_total_approx_sf =
493 n_radial_approx_sf * n_base_approx_shape_functions;
494
495
496 // The number of the base quadrature points.
497 const unsigned int n_base_qp = cast_int<unsigned int>(base_qp.size());
498
499 // The total number of quadrature points.
500 _n_total_qp = n_radial_qp * n_base_qp;
501
502
503 // initialize the node and shape numbering maps
504 {
505 // similar for the shapes: the i-th entry stores
506 // the associated base/radial shape number
507 _radial_shape_index.resize(_n_total_approx_sf);
508 _base_shape_index.resize(_n_total_approx_sf);
509
510 // fill the shape index map
511 for (unsigned int n=0; n<_n_total_approx_sf; ++n)
512 {
513 compute_shape_indices (this->fe_type,
514 inf_elem,
515 n,
516 _base_shape_index[n],
517 _radial_shape_index[n]);
518 libmesh_assert_less (_base_shape_index[n], n_base_approx_shape_functions);
519 libmesh_assert_less (_radial_shape_index[n], n_radial_approx_sf);
520 }
521 }
522
523 // resize the base data fields
524 //dist.resize(n_base_mapping_shape_functions);
525
526 // resize the total data fields
527
528 // the phase term varies with xi, eta and zeta(v): store it for _all_ qp
529 //
530 // when computing the phase, we need the base approximations
531 // therefore, initialize the phase here, but evaluate it
532 // in compute_shape_functions().
533 //
534 // the weight, though, is only needed at the radial quadrature points, n_radial_qp.
535 // but for a uniform interface to the protected data fields
536 // the weight data field (which are accessible from the outside) are expanded to _n_total_qp.
537 if (calculate_phi || calculate_dphi)
538 weight.resize (_n_total_qp);
539 if (calculate_phi_scaled || calculate_dphi_scaled)
540 weightxr_sq.resize (_n_total_qp);
541 if (calculate_dphi || calculate_dphi_scaled)
542 dweightdv.resize (n_radial_qp);
543 if (calculate_dphi)
544 dweight.resize (_n_total_qp);
545 if (calculate_dphi_scaled)
546 dweightxr_sq.resize(_n_total_qp);
547
548 if (calculate_dphi || calculate_dphi_scaled)
549 dphase.resize (_n_total_qp);
550
551 // this vector contains the integration weights for the combined quadrature rule
552 // if no quadrature rules are given, use only ones.
553 _total_qrule_weights.resize(_n_total_qp,1);
554
555 // InfFE's data fields phi, dphi, dphidx, phi_map etc hold the _total_
556 // shape and mapping functions, respectively
557 {
558 if (calculate_map_scaled)
559 JxWxdecay.resize(_n_total_qp);
560 if (calculate_jxw)
561 JxW.resize(_n_total_qp);
562 if (calculate_map_scaled || calculate_map)
563 {
564 xyz.resize(_n_total_qp);
565 dxidx_map_scaled.resize(_n_total_qp);
566 dxidy_map_scaled.resize(_n_total_qp);
567 dxidz_map_scaled.resize(_n_total_qp);
568 detadx_map_scaled.resize(_n_total_qp);
569 detady_map_scaled.resize(_n_total_qp);
570 detadz_map_scaled.resize(_n_total_qp);
571 dzetadx_map_scaled.resize(_n_total_qp);
572 dzetady_map_scaled.resize(_n_total_qp);
573 dzetadz_map_scaled.resize(_n_total_qp);
574 }
575 if (calculate_map)
576 {
577 dxidx_map.resize(_n_total_qp);
578 dxidy_map.resize(_n_total_qp);
579 dxidz_map.resize(_n_total_qp);
580 detadx_map.resize(_n_total_qp);
581 detady_map.resize(_n_total_qp);
582 detadz_map.resize(_n_total_qp);
583 dzetadx_map.resize(_n_total_qp);
584 dzetady_map.resize(_n_total_qp);
585 dzetadz_map.resize(_n_total_qp);
586 }
587 if (calculate_phi)
588 phi.resize (_n_total_approx_sf);
589 if (calculate_phi_scaled)
590 phixr.resize (_n_total_approx_sf);
591 if (calculate_dphi)
592 {
593 dphi.resize (_n_total_approx_sf);
594 dphidx.resize (_n_total_approx_sf);
595 dphidy.resize (_n_total_approx_sf);
596 dphidz.resize (_n_total_approx_sf);
597 }
598
599 if (calculate_dphi_scaled)
600 {
601 dphixr.resize (_n_total_approx_sf);
602 dphixr_sq.resize(_n_total_approx_sf);
603 }
604#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
605
606 if (calculate_d2phi)
607 {
608 libmesh_not_implemented();
609 d2phi.resize (_n_total_approx_sf);
610 d2phidx2.resize (_n_total_approx_sf);
611 d2phidxdy.resize (_n_total_approx_sf);
612 d2phidxdz.resize (_n_total_approx_sf);
613 d2phidy2.resize (_n_total_approx_sf);
614 d2phidydz.resize (_n_total_approx_sf);
615 d2phidz2.resize (_n_total_approx_sf);
616 d2phidxi2.resize (_n_total_approx_sf);
617
618 if (Dim > 1)
619 {
620 d2phidxideta.resize(_n_total_approx_sf);
621 d2phideta2.resize(_n_total_approx_sf);
622 }
623
624 if (Dim > 2)
625 {
626 d2phidetadzeta.resize(_n_total_approx_sf);
627 d2phidxidzeta.resize(_n_total_approx_sf);
628 d2phidzeta2.resize(_n_total_approx_sf);
629 }
630 }
631#endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
632
633 if (calculate_dphi || calculate_dphi_scaled)
634 {
635 dphidxi.resize (_n_total_approx_sf);
636
637 if (Dim > 1)
638 dphideta.resize(_n_total_approx_sf);
639
640 if (Dim == 3)
641 dphidzeta.resize(_n_total_approx_sf);
642 }
643
644 }
645
646 // collect all the for loops, where inner vectors are
647 // resized to the appropriate number of quadrature points
648 {
649 if (calculate_phi)
650 for (unsigned int i=0; i<_n_total_approx_sf; ++i)
651 phi[i].resize (_n_total_qp);
652
653 if (calculate_dphi)
654 for (unsigned int i=0; i<_n_total_approx_sf; ++i)
655 {
656 dphi[i].resize (_n_total_qp);
657 dphidx[i].resize (_n_total_qp);
658 dphidy[i].resize (_n_total_qp);
659 dphidz[i].resize (_n_total_qp);
660 }
661
662 if (calculate_phi_scaled)
663 for (unsigned int i=0; i<_n_total_approx_sf; ++i)
664 {
665 phixr[i].resize (_n_total_qp);
666 }
667 if (calculate_dphi_scaled)
668 for (unsigned int i=0; i<_n_total_approx_sf; ++i)
669 {
670 dphixr[i].resize(_n_total_qp);
671 dphixr_sq[i].resize(_n_total_qp);
672 }
673#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
674 if (calculate_d2phi)
675 for (unsigned int i=0; i<_n_total_approx_sf; ++i)
676 {
677 d2phi[i].resize (_n_total_qp);
678 d2phidx2[i].resize (_n_total_qp);
679 d2phidxdy[i].resize (_n_total_qp);
680 d2phidxdz[i].resize (_n_total_qp);
681 d2phidy2[i].resize (_n_total_qp);
682 d2phidydz[i].resize (_n_total_qp);
683 d2phidy2[i].resize (_n_total_qp);
684 d2phidxi2[i].resize (_n_total_qp);
685
686 if (Dim > 1)
687 {
688 d2phidxideta[i].resize (_n_total_qp);
689 d2phideta2[i].resize (_n_total_qp);
690 }
691 if (Dim > 2)
692 {
693 d2phidxidzeta[i].resize (_n_total_qp);
694 d2phidetadzeta[i].resize (_n_total_qp);
695 d2phidzeta2[i].resize (_n_total_qp);
696 }
697 }
698#endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
699
700 if (calculate_dphi || calculate_dphi_scaled)
701 for (unsigned int i=0; i<_n_total_approx_sf; ++i)
702 {
703 dphidxi[i].resize (_n_total_qp);
704
705 if (Dim > 1)
706 dphideta[i].resize (_n_total_qp);
707
708 if (Dim == 3)
709 dphidzeta[i].resize (_n_total_qp);
710
711 }
712
713 }
714 {
715 // (a) compute scalar values at _all_ quadrature points -- for uniform
716 // access from the outside to these fields
717 // (b) form a std::vector<Real> which contains the appropriate weights
718 // of the combined quadrature rule!
719 libmesh_assert_equal_to (radial_qp.size(), n_radial_qp);
720
721 if (radial_qrule && base_qrule)
722 {
723 const std::vector<Real> & radial_qw = radial_qrule->get_weights();
724 const std::vector<Real> & base_qw = base_qrule->get_weights();
725 libmesh_assert_equal_to (radial_qw.size(), n_radial_qp);
726 libmesh_assert_equal_to (base_qw.size(), n_base_qp);
727
728 for (unsigned int rp=0; rp<n_radial_qp; ++rp)
729 for (unsigned int bp=0; bp<n_base_qp; ++bp)
730 _total_qrule_weights[bp + rp*n_base_qp] = radial_qw[rp] * base_qw[bp];
731 }
732
733
734 for (unsigned int rp=0; rp<n_radial_qp; ++rp)
735 {
736 if (calculate_phi || calculate_dphi)
737 for (unsigned int bp=0; bp<n_base_qp; ++bp)
738 weight[bp + rp*n_base_qp] = InfFERadial::D(radial_qp[rp](0));
739
740 if ( calculate_phi_scaled)
741 for (unsigned int bp=0; bp<n_base_qp; ++bp)
742 weightxr_sq[bp + rp*n_base_qp] = InfFERadial::Dxr_sq(radial_qp[rp](0));
743
744 if ( calculate_dphi || calculate_dphi_scaled)
745 dweightdv[rp] = InfFERadial::D_deriv(radial_qp[rp](0));
746 }
747 }
748}
749
750
751
752template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
754 const std::vector<Point> & base_qp,
755 const std::vector<Point> & radial_qp
756 )
757{
758 libmesh_assert(inf_elem);
759 // at least check whether the base element type is correct.
760 // otherwise this version of computing dist would give problems
761 libmesh_assert_equal_to (base_elem->type(),
762 InfFEBase::get_elem_type(inf_elem->type()));
763
764 // Start logging the overall computation of shape functions
765 LOG_SCOPE("compute_shape_functions()", "InfFE");
766
767 //const unsigned int n_radial_qp = cast_int<unsigned int>(som.size());
768 //const unsigned int n_base_qp = cast_int<unsigned int>(S_map[0].size());
769 const std::size_t n_radial_qp = radial_qp.size();
770 const unsigned int n_base_qp = base_qp.size();
771
772 libmesh_assert_equal_to (_n_total_qp, n_radial_qp*n_base_qp);
773 libmesh_assert_equal_to (_n_total_qp, _total_qrule_weights.size());
774#ifdef DEBUG
775 if (som.size() > 0)
776 libmesh_assert_equal_to(n_radial_qp, som.size());
777
778 if (this->calculate_map || this->calculate_map_scaled)
779 {
780 // these vectors are needed later; initialize here already to have access to
781 // n_base_qp etc.
782 const std::vector<std::vector<Real>> & S_map = (base_fe->get_fe_map()).get_phi_map();
783 if (S_map[0].size() > 0)
784 libmesh_assert_equal_to(n_base_qp, S_map[0].size());
785 }
786 if (radial_qrule)
787 libmesh_assert_equal_to(n_radial_qp, radial_qrule->n_points());
788 if (base_qrule)
789 libmesh_assert_equal_to(n_base_qp, base_qrule->n_points());
790 libmesh_assert_equal_to(_n_total_qp % n_radial_qp, 0); // "Error in the structure of quadrature points!");
791#endif
792
793
794 _n_total_approx_sf = InfFERadial::n_dofs(fe_type.radial_order) *
795 FEInterface::n_dofs(base_fe->get_fe_type(), base_elem.get());
796
797
798
799 const Point origin = inf_elem->origin();
800
801 // Compute the shape function values (and derivatives)
802 // at the Quadrature points. Note that the actual values
803 // have already been computed via init_shape_functions
804
805 unsigned int elem_dim = inf_elem->dim();
806 // Compute the value of the derivative shape function i at quadrature point p
807 switch (elem_dim)
808 {
809 case 1:
810 case 2:
811 {
812 libmesh_not_implemented();
813 break;
814 }
815 case 3:
816 {
817 std::vector<std::vector<Real>> S (0);
818 std::vector<std::vector<Real>> Ss(0);
819 std::vector<std::vector<Real>> St(0);
820
821 std::vector<Real> base_dxidx (0);
822 std::vector<Real> base_dxidy (0);
823 std::vector<Real> base_dxidz (0);
824 std::vector<Real> base_detadx(0);
825 std::vector<Real> base_detady(0);
826 std::vector<Real> base_detadz(0);
827
828 std::vector<Point> base_xyz (0);
829
830 if (calculate_phi || calculate_phi_scaled ||
831 calculate_dphi || calculate_dphi_scaled)
832 S=base_fe->phi;
833
834 // fast access to the approximation and mapping shapes of base_fe
835 if (calculate_map || calculate_map_scaled)
836 {
837 Ss = base_fe->dphidxi;
838 St = base_fe->dphideta;
839
840 base_dxidx = base_fe->get_dxidx();
841 base_dxidy = base_fe->get_dxidy();
842 base_dxidz = base_fe->get_dxidz();
843 base_detadx = base_fe->get_detadx();
844 base_detady = base_fe->get_detady();
845 base_detadz = base_fe->get_detadz();
846
847 base_xyz = base_fe->get_xyz();
848 }
849
850 ElemType base_type= base_elem->type();
851
852#ifdef DEBUG
853 if (calculate_phi)
854 libmesh_assert_equal_to (phi.size(), _n_total_approx_sf);
855 if (calculate_dphi)
856 {
857 libmesh_assert_equal_to (dphidxi.size(), _n_total_approx_sf);
858 libmesh_assert_equal_to (dphideta.size(), _n_total_approx_sf);
859 libmesh_assert_equal_to (dphidzeta.size(), _n_total_approx_sf);
860 }
861#endif
862
863 unsigned int tp=0; // total qp
864 for (unsigned int rp=0; rp<n_radial_qp; ++rp) // over radial qps
865 for (unsigned int bp=0; bp<n_base_qp; ++bp) // over base qps
866
867 { // First compute the map from base element quantities to physical space:
868
869 // initialize them with invalid value to not use them
870 // without setting them to the correct value before.
871 Point unit_r(NAN);
872 RealGradient grad_a_scaled(NAN);
873 Real a(NAN);
874 Real r_norm(NAN);
875 if (calculate_map || calculate_map_scaled)
876 {
877 xyz[tp] = InfFEMap::map(elem_dim, inf_elem, Point(base_qp[bp](0),base_qp[bp](1),radial_qp[rp](0)));
878
879 const Point r(xyz[tp]-origin);
880 a=(base_xyz[bp]-origin).norm();
881 r_norm = r.norm();
882
883 // check that 'som' == a/r.
884#ifndef NDEVEL
885 if (som.size())
886 libmesh_assert_less(std::abs(som[rp] -a/r_norm) , 1e-7);
887#endif
888 unit_r=(r/r_norm);
889
890 // They are used for computing the normal and do not correspond to the direction of eta and xi in this element:
891 // Due to the stretch of these axes in radial direction, they are deformed.
892 Point e_xi(base_dxidx[bp],
893 base_dxidy[bp],
894 base_dxidz[bp]);
895 Point e_eta(base_detadx[bp],
896 base_detady[bp],
897 base_detadz[bp]);
898
899 const RealGradient normal=e_eta.cross(e_xi).unit();
900
901 // grad a = a/r.norm() * grad_a_scaled
902 grad_a_scaled=unit_r - normal/(normal*unit_r);
903
904 const Real dxi_er=base_dxidx[bp]* unit_r(0) + base_dxidy[bp] *unit_r(1) + base_dxidz[bp] *unit_r(2);
905 const Real deta_er=base_detadx[bp]*unit_r(0) + base_detady[bp]*unit_r(1) + base_detadz[bp]*unit_r(2);
906
907 // in case of non-affine map, further terms need to be taken into account,
908 // involving \p e_eta and \p e_xi and thus recursive computation is needed
909 if (!base_elem->has_affine_map())
910 {
919 const unsigned int n_sf = base_elem->n_nodes();
920 RealGradient tmp(0.,0.,0.);
921 for (unsigned int i=0; i< n_sf; ++i)
922 {
923 RealGradient dL_da_i = (FE<2,LAGRANGE>::shape_deriv(base_type,
924 base_elem->default_order(),
925 i, 0, base_qp[bp]) * e_xi
927 base_elem->default_order(),
928 i, 1, base_qp[bp]) * e_eta);
929
930 tmp += (base_elem->node_ref(i) -origin).norm()* dL_da_i;
931
932 }
933 libmesh_assert(tmp*unit_r < .95 ); // in a proper setup, tmp should have only a small radial component.
934 grad_a_scaled = ( tmp - (tmp*unit_r)*unit_r ) / ( 1. - tmp*unit_r);
935
936 }
937
938 // 'scale' = r/a
939 dxidx_map_scaled[tp] = (grad_a_scaled(0) - unit_r(0))*dxi_er +base_dxidx[bp];
940 dxidy_map_scaled[tp] = (grad_a_scaled(1) - unit_r(1))*dxi_er +base_dxidy[bp];
941 dxidz_map_scaled[tp] = (grad_a_scaled(2) - unit_r(2))*dxi_er +base_dxidz[bp];
942
943 // 'scale' = r/a
944 detadx_map_scaled[tp] = (grad_a_scaled(0) - unit_r(0))*deta_er + base_detadx[bp];
945 detady_map_scaled[tp] = (grad_a_scaled(1) - unit_r(1))*deta_er + base_detady[bp];
946 detadz_map_scaled[tp] = (grad_a_scaled(2) - unit_r(2))*deta_er + base_detadz[bp];
947
948 // 'scale' = (r/a)**2
949 dzetadx_map_scaled[tp] =-2./a*(grad_a_scaled(0) - unit_r(0));
950 dzetady_map_scaled[tp] =-2./a*(grad_a_scaled(1) - unit_r(1));
951 dzetadz_map_scaled[tp] =-2./a*(grad_a_scaled(2) - unit_r(2));
952
953 }
954
955 if (calculate_map)
956 {
957 dxidx_map[tp] = a/r_norm * dxidx_map_scaled[tp];
958 dxidy_map[tp] = a/r_norm * dxidy_map_scaled[tp];
959 dxidz_map[tp] = a/r_norm * dxidz_map_scaled[tp];
960
961 detadx_map[tp] = a/r_norm * detadx_map_scaled[tp];
962 detady_map[tp] = a/r_norm * detady_map_scaled[tp];
963 detadz_map[tp] = a/r_norm * detadz_map_scaled[tp];
964
965 // dzetadx = dzetadr*dr/dx - 2/r * grad_a
966 // = dzetadr*dr/dx - 2*a/r^2 * grad_a_scaled
967 dzetadx_map[tp] =-2.*a/(r_norm*r_norm)*(grad_a_scaled(0) - unit_r(0));
968 dzetady_map[tp] =-2.*a/(r_norm*r_norm)*(grad_a_scaled(1) - unit_r(1));
969 dzetadz_map[tp] =-2.*a/(r_norm*r_norm)*(grad_a_scaled(2) - unit_r(2));
970
971 if (calculate_jxw)
972 {
973 Real inv_jac = (dxidx_map[tp]*( detady_map[tp]*dzetadz_map[tp]- dzetady_map[tp]*detadz_map[tp]) +
974 detadx_map[tp]*(dzetady_map[tp]* dxidz_map[tp]- dxidy_map[tp]*dzetadz_map[tp]) +
975 dzetadx_map[tp]*( dxidy_map[tp]*detadz_map[tp]- detady_map[tp]* dxidz_map[tp]));
976
977 if (inv_jac <= 1e-10)
978 {
979 libmesh_error_msg("ERROR: negative inverse Jacobian " \
980 << inv_jac \
981 << " at point " \
982 << xyz[tp] \
983 << " in element " \
984 << inf_elem->id());
985 }
986
987
988 JxW[tp] = _total_qrule_weights[tp]/inv_jac;
989 }
990
991 }
992 if (calculate_map_scaled)
993 {
994 Real inv_jacxR_pow4 = (dxidx_map_scaled[tp] *( detady_map_scaled[tp]*dzetadz_map_scaled[tp]
995 - dzetady_map_scaled[tp]* detadz_map_scaled[tp]) +
996 detadx_map_scaled[tp] *( dzetady_map_scaled[tp]* dxidz_map_scaled[tp]
997 - dxidy_map_scaled[tp]*dzetadz_map_scaled[tp]) +
998 dzetadx_map_scaled[tp]*( dxidy_map_scaled[tp]* detadz_map_scaled[tp]
999 -detady_map_scaled[tp]* dxidz_map_scaled[tp]));
1000 if (inv_jacxR_pow4 <= 1e-7)
1001 {
1002 libmesh_error_msg("ERROR: negative weighted inverse Jacobian " \
1003 << inv_jacxR_pow4 \
1004 << " at point " \
1005 << xyz[tp] \
1006 << " in element " \
1007 << inf_elem->id());
1008 }
1009
1010 JxWxdecay[tp] = _total_qrule_weights[tp]/inv_jacxR_pow4;
1011 }
1012
1013 // phase term mu(r)=i*k*(r-a).
1014 // skip i*k: it is added separately during matrix assembly.
1015
1016 if (calculate_dphi || calculate_dphi_scaled)
1017 dphase[tp] = unit_r - grad_a_scaled*a/r_norm;
1018
1019 if (calculate_dphi)
1020 {
1021 dweight[tp](0) = dweightdv[rp] * dzetadx_map[tp];
1022 dweight[tp](1) = dweightdv[rp] * dzetady_map[tp];
1023 dweight[tp](2) = dweightdv[rp] * dzetadz_map[tp];
1024 }
1025 if (calculate_dphi_scaled)
1026 {
1027 dweightxr_sq[tp](0) = dweightdv[rp] * dzetadx_map_scaled[tp];
1028 dweightxr_sq[tp](1) = dweightdv[rp] * dzetady_map_scaled[tp];
1029 dweightxr_sq[tp](2) = dweightdv[rp] * dzetadz_map_scaled[tp];
1030 }
1031
1032 if (calculate_phi || calculate_phi_scaled || calculate_dphi || calculate_dphi_scaled)
1033 // compute the shape-functions and derivative quantities:
1034 for (unsigned int i=0; i <_n_total_approx_sf ; ++i)
1035 {
1036 // let the index vectors take care of selecting the appropriate base/radial shape
1037 unsigned int bi = _base_shape_index [i];
1038 unsigned int ri = _radial_shape_index[i];
1039 if (calculate_phi)
1040 phi [i][tp] = S [bi][bp] * mode[ri][rp] * som[rp];
1041
1042 if (calculate_phi_scaled)
1043 phixr [i][tp] = S [bi][bp] * mode[ri][rp];
1044
1045 if (calculate_dphi || calculate_dphi_scaled)
1046 {
1047 dphidxi [i][tp] = Ss[bi][bp] * mode[ri][rp] * som[rp];
1048 dphideta [i][tp] = St[bi][bp] * mode[ri][rp] * som[rp];
1049 dphidzeta[i][tp] = S [bi][bp]
1050 * (dmodedv[ri][rp] * som[rp] + mode[ri][rp] * dsomdv[rp]);
1051 }
1052
1053 if (calculate_dphi)
1054 {
1055
1056 // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx);
1057 dphi[i][tp](0) =
1058 dphidx[i][tp] = (dphidxi[i][tp]*dxidx_map[tp] +
1059 dphideta[i][tp]*detadx_map[tp] +
1060 dphidzeta[i][tp]*dzetadx_map[tp]);
1061
1062 // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy);
1063 dphi[i][tp](1) =
1064 dphidy[i][tp] = (dphidxi[i][tp]*dxidy_map[tp] +
1065 dphideta[i][tp]*detady_map[tp] +
1066 dphidzeta[i][tp]*dzetady_map[tp]);
1067
1068 // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz);
1069 dphi[i][tp](2) =
1070 dphidz[i][tp] = (dphidxi[i][tp]*dxidz_map[tp] +
1071 dphideta[i][tp]*detadz_map[tp] +
1072 dphidzeta[i][tp]*dzetadz_map[tp]);
1073
1074 }
1075 if (calculate_dphi_scaled)
1076 { // we don't distinguish between the different levels of scaling here...
1077
1078 dphixr[i][tp](0)= (dphidxi[i][tp]*dxidx_map_scaled[tp] +
1079 dphideta[i][tp]*detadx_map_scaled[tp] +
1080 dphidzeta[i][tp]*dzetadx_map_scaled[tp]*som[rp]);
1081
1082 dphixr[i][tp](1) = (dphidxi[i][tp]*dxidy_map_scaled[tp] +
1083 dphideta[i][tp]*detady_map_scaled[tp] +
1084 dphidzeta[i][tp]*dzetady_map_scaled[tp]*som[rp]);
1085
1086 dphixr[i][tp](2) = (dphidxi[i][tp]*dxidz_map_scaled[tp] +
1087 dphideta[i][tp]*detadz_map_scaled[tp] +
1088 dphidzeta[i][tp]*dzetadz_map_scaled[tp]*som[rp]);
1089
1090 const Real dphidxixr = Ss[bi][bp] * mode[ri][rp];
1091 const Real dphidetaxr= St[bi][bp] * mode[ri][rp];
1092
1093 dphixr_sq[i][tp](0)= (dphidxixr*dxidx_map_scaled[tp] +
1094 dphidetaxr*detadx_map_scaled[tp] +
1095 dphidzeta[i][tp]*dzetadx_map_scaled[tp]);
1096
1097 dphixr_sq[i][tp](1) = (dphidxixr*dxidy_map_scaled[tp] +
1098 dphidetaxr*detady_map_scaled[tp] +
1099 dphidzeta[i][tp]*dzetady_map_scaled[tp]);
1100
1101 dphixr_sq[i][tp](2) = (dphidxixr*dxidz_map_scaled[tp] +
1102 dphidetaxr*detadz_map_scaled[tp] +
1103 dphidzeta[i][tp]*dzetadz_map_scaled[tp]);
1104 }
1105
1106 }
1107 tp++;
1108 }
1109
1110 break;
1111 }
1112
1113 default:
1114 libmesh_error_msg("Unsupported dim = " << dim);
1115 }
1116}
1117
1118
1119
1120template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
1122{
1123 // We never call this.
1124 libmesh_not_implemented();
1125 return false;
1126}
1127
1128} // namespace libMesh
1129
1130
1131// Explicit instantiations
1132#include "libmesh/inf_fe_instantiate_1D.h"
1133#include "libmesh/inf_fe_instantiate_2D.h"
1134#include "libmesh/inf_fe_instantiate_3D.h"
1135
1136
1137
1138#endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
unsigned int dim
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual Point origin() const
Definition elem.h:1923
virtual unsigned short dim() const =0
virtual ElemType type() const =0
FEType fe_type
The finite element type for this object.
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
static unsigned int n_dofs(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
InfMapType inf_map
The coordinate mapping type of the infinite element.
Definition fe_type.h:284
FEFamily radial_family
The type of approximation in radial direction.
Definition fe_type.h:276
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
static ElemType get_elem_type(const ElemType type)
static std::unique_ptr< const Elem > build_elem(const Elem *inf_elem)
Build the base element of an infinite element.
static Point map(const unsigned int dim, const Elem *inf_elem, const Point &reference_point)
Definition inf_fe_map.C:40
static Real D(const Real v)
Definition inf_fe.h:82
static Real D_deriv(const Real v)
Definition inf_fe.h:90
static Real decay_deriv(const unsigned int dim, const Real)
Definition inf_fe.h:1292
static Real Dxr_sq(const Real)
Definition inf_fe.h:84
static unsigned int n_dofs(const Order o_radial)
Definition inf_fe.h:113
static Real decay(const unsigned int dim, const Real v)
Definition inf_fe.h:1266
A specific instantiation of the FEBase class.
Definition inf_fe.h:225
void init_radial_shape_functions(const Elem *inf_elem, const std::vector< Point > *radial_pts=nullptr)
Some of the member data only depend on the radial part of the infinite element.
Definition inf_fe.C:387
virtual bool shapes_need_reinit() const override
Definition inf_fe.C:1121
virtual void determine_calculations() override
Determine which values are to be calculated, for both the FE itself and for the FEMap.
Definition inf_fe.C:329
void compute_shape_functions(const Elem *inf_elem, const std::vector< Point > &base_qp, const std::vector< Point > &radial_qp)
After having updated the jacobian and the transformation from local to global coordinates in FEAbstra...
Definition inf_fe.C:753
virtual void attach_quadrature_rule(QBase *q) override
The use of quadrature rules with the InfFE class is somewhat different from the approach of the FE cl...
Definition inf_fe.C:79
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 inf_fe.C:120
void update_base_elem(const Elem *inf_elem)
Updates the protected member base_elem to the appropriate base element for the given inf_elem.
Definition inf_fe.C:109
std::unique_ptr< FEBase > base_fe
Have a FE<Dim-1,T_base> handy for base approximation.
Definition inf_fe.h:1206
friend class InfFE
Make all InfFE<Dim,T_radial,T_map> classes friends of each other, so that the protected eval() may be...
Definition inf_fe.h:1253
void init_shape_functions(const std::vector< Point > &radial_qp, const std::vector< Point > &base_qp, const Elem *inf_elem)
Initialize all the data fields like weight, mode, phi, dphidxi, dphideta, dphidzeta,...
Definition inf_fe.C:451
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition int_range.h:54
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
Order get_order() const
Definition quadrature.h:249
virtual QuadratureType type() const =0
unsigned int get_dim() const
Definition quadrature.h:150
static std::unique_ptr< QBase > build(std::string_view name, const unsigned int dim, const Order order=INVALID_ORDER)
Builds a specific quadrature rule based on the name string.
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
auto norm() const
The libMesh namespace provides an interface to certain functionality in the library.
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
@ INVALID_ORDER
Definition enum_order.h:88
const Real radius