libMesh
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 
36 namespace libMesh
37 {
38 
39 
40 
41 // Constructor
42 template <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 
78 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
80 {
81  libmesh_assert(q);
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 
108 template <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 
119 template <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 
328 template <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 
384 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
385 void
387 init_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 
450 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
451 void 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 
752 template <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
926  +FE<2,LAGRANGE>::shape_deriv(base_type,
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 
1120 template <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
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
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
ElemType
Defines an enum for geometric element types.
static ElemType get_elem_type(const ElemType type)
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
A specific instantiation of the FEBase class.
Definition: fe.h:42
static unsigned int n_dofs(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:353
static unsigned int n_dofs(const Order o_radial)
Definition: inf_fe.h:113
const Real radius
auto norm() const
Definition: type_vector.h:908
virtual Point origin() const
Definition: elem.h:1920
static Point map(const unsigned int dim, const Elem *inf_elem, const Point &reference_point)
Definition: inf_fe_map.C:40
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition: int_range.h:53
static Real decay_deriv(const unsigned int dim, const Real)
Definition: inf_fe.h:1292
unsigned int dim
static Real Dxr_sq(const Real)
Definition: inf_fe.h:84
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, etc.
Definition: inf_fe.C:451
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
static OutputShape shape_deriv(const ElemType t, const Order o, const unsigned int i, const unsigned int j, const Point &p)
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
The libMesh namespace provides an interface to certain functionality in the library.
static std::unique_ptr< const Elem > build_elem(const Elem *inf_elem)
Build the base element of an infinite element.
virtual QuadratureType type() const =0
static Real D(const Real v)
Definition: inf_fe.h:82
A specific instantiation of the FEBase class.
Definition: fe.h:127
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
dof_id_type id() const
Definition: dof_object.h:819
std::unique_ptr< FEBase > base_fe
Have a FE<Dim-1,T_base> handy for base approximation.
Definition: inf_fe.h:1206
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:444
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libmesh_assert(ctx)
Order get_order() const
Definition: quadrature.h:249
static Real decay(const unsigned int dim, const Real v)
Definition: inf_fe.h:1266
unsigned int get_dim() const
Definition: quadrature.h:150
InfMapType inf_map
The coordinate mapping type of the infinite element.
Definition: fe_type.h:284
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
Definition: type_vector.h:885
virtual bool shapes_need_reinit() const override
Definition: inf_fe.C:1121
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
FEFamily radial_family
The type of approximation in radial direction.
Definition: fe_type.h:276
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
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
auto norm(const T &a)
Definition: tensor_tools.h:74
virtual unsigned short dim() const =0
static Real D_deriv(const Real v)
Definition: inf_fe.h:90
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.
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
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
FEType fe_type
The finite element type for this object.
Definition: fe_abstract.h:730
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
The QBase class provides the basic functionality from which various quadrature rules can be derived...
Definition: quadrature.h:61
This class forms the foundation from which generic finite elements may be derived.
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