inf_fe.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 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 #include "libmesh/inf_fe.h"
26 #include "libmesh/elem.h"
28 #include "libmesh/int_range.h"
29 
30 namespace libMesh
31 {
32 
33 
34 
35 // Constructor
36 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
38  FEBase (Dim, fet),
39 
40  _n_total_approx_sf (0),
41  _n_total_qp (0),
42 
43  // initialize the current_fe_type to all the same
44  // values as \p fet (since the FE families and coordinate
45  // map type should not change), but use an invalid order
46  // for the radial part (since this is the only order
47  // that may change!).
48  // the data structures like \p phi etc are not initialized
49  // through the constructor, but through reinit()
50  current_fe_type (FEType(fet.order,
51  fet.family,
53  fet.radial_family,
54  fet.inf_map))
55 
56 {
57  // Sanity checks
58  libmesh_assert_equal_to (T_radial, fe_type.radial_family);
59  libmesh_assert_equal_to (T_map, fe_type.inf_map);
60 
61  // build the base_fe object
62  if (Dim != 1)
63  base_fe = FEBase::build(Dim-1, fet);
64 }
65 
66 
67 
68 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
70 {
71  libmesh_assert(q);
72  libmesh_assert(base_fe);
73 
74  const Order base_int_order = q->get_order();
75  const Order radial_int_order = static_cast<Order>(2 * (static_cast<unsigned int>(fe_type.radial_order.get_order()) + 1) +2);
76  const unsigned int qrule_dim = q->get_dim();
77 
78  if (Dim != 1)
79  {
80  // build a Dim-1 quadrature rule of the type that we received
81  base_qrule = QBase::build(q->type(), qrule_dim-1, base_int_order);
82  base_fe->attach_quadrature_rule(base_qrule.get());
83  }
84 
85  // in radial direction, always use Gauss quadrature
86  radial_qrule.reset(new QGauss(1, radial_int_order));
87 
88  // currently not used. But maybe helpful to store the QBase *
89  // with which we initialized our own quadrature rules
90  qrule = q;
91 }
92 
93 
94 
95 
96 
97 template <unsigned int Dim, FEFamily T_radial, InfMapType T_base>
99 {
100  base_elem.reset(Base::build_elem(inf_elem));
101 }
102 
103 
104 
105 
106 
107 
108 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
110  const std::vector<Point> * const pts,
111  const std::vector<Real> * const weights)
112 {
113  libmesh_assert(base_fe.get());
114  libmesh_assert(inf_elem);
115 
116  // I don't understand infinite elements well enough to risk
117  // calculating too little. :-( RHS
118  this->calculate_phi = this->calculate_dphi = this->calculate_dphiref = true;
119  this->get_xyz();
120  this->determine_calculations();
121  base_fe->calculate_phi = base_fe->calculate_dphi = base_fe->calculate_dphiref = true;
122  base_fe->get_xyz();
123  base_fe->determine_calculations();
124 
125  if (pts == nullptr)
126  {
127  libmesh_assert(base_fe->qrule);
128  libmesh_assert_equal_to (base_fe->qrule, base_qrule.get());
129  libmesh_assert(radial_qrule.get());
130 
131  bool init_shape_functions_required = false;
132 
133  // init the radial data fields only when the radial order changes
134  if (current_fe_type.radial_order != fe_type.radial_order)
135  {
136  current_fe_type.radial_order = fe_type.radial_order;
137 
138  // Watch out: this call to QBase->init() only works for
139  // current_fe_type = const! To allow variable Order,
140  // the init() of QBase has to be modified...
141  radial_qrule->init(EDGE2);
142 
143  // initialize the radial shape functions
144  this->init_radial_shape_functions(inf_elem);
145 
146  init_shape_functions_required=true;
147  }
148 
149 
150  bool update_base_elem_required=true;
151 
152  // update the type in accordance to the current cell
153  // and reinit if the cell type has changed or (as in
154  // the case of the hierarchics) the shape functions
155  // depend on the particular element and need a reinit
156  if ((Dim != 1) &&
157  ((this->get_type() != inf_elem->type()) ||
158  (base_fe->shapes_need_reinit())))
159  {
160  // store the new element type, update base_elem
161  // here. Through \p update_base_elem_required,
162  // remember whether it has to be updated (see below).
163  elem_type = inf_elem->type();
164  this->update_base_elem(inf_elem);
165  update_base_elem_required=false;
166 
167  // initialize the base quadrature rule for the new element
168  base_qrule->init(base_elem->type());
169 
170  // initialize the shape functions in the base
171  base_fe->init_base_shape_functions(base_fe->qrule->get_points(),
172  base_elem.get());
173 
174  // compute the shape functions and map functions of base_fe
175  // before using them later in combine_base_radial.
176  base_fe->_fe_map->compute_map (base_fe->dim, base_fe->qrule->get_weights(),
177  base_elem.get(), base_fe->calculate_d2phi);
178  base_fe->compute_shape_functions(base_elem.get(), base_fe->qrule->get_points());
179 
180  init_shape_functions_required=true;
181  }
182 
183 
184  // when either the radial or base part change,
185  // we have to init the whole fields
186  if (init_shape_functions_required)
187  this->init_shape_functions (radial_qrule->get_points(),
188  base_fe->qrule->get_points(),
189  inf_elem);
190 
191  // computing the distance only works when we have the current
192  // base_elem stored. This happens when fe_type is const,
193  // the inf_elem->type remains the same. Then we have to
194  // update the base elem _here_.
195  if (update_base_elem_required)
196  this->update_base_elem(inf_elem);
197 
198  // compute dist (depends on geometry, therefore has to be updated for
199  // each and every new element), throw radial and base part together
200  this->combine_base_radial (inf_elem);
201 
202  this->_fe_map->compute_map (this->dim, _total_qrule_weights, inf_elem, this->calculate_d2phi);
203 
204  // Compute the shape functions and the derivatives
205  // at all quadrature points.
206  this->compute_shape_functions (inf_elem,base_fe->qrule->get_points());
207  }
208 
209  else // if pts != nullptr
210  {
211  // update the elem_type
212  elem_type = inf_elem->type();
213 
214  // We'll assume that pts is a tensor product mesh of points.
215  // That will handle the pts.size()==1 case that we care about
216  // right now, and it will generalize a bit, and it won't break
217  // the assumptions elsewhere in InfFE.
218  std::vector<Point> radial_pts;
219  for (auto p : index_range(*pts))
220  {
221  Real radius = (*pts)[p](Dim-1);
222  //IMHO this is a dangerous check:
223  // 1) it is not guaranteed that two points have numerically equal radii
224  // 2) if there several radii but not sorted/regular, this breaks
225  if (radial_pts.size() && radial_pts[0](0) == radius)
226  break;
227  radial_pts.push_back(Point(radius));
228  }
229  const std::size_t radial_pts_size = radial_pts.size();
230  const std::size_t base_pts_size = pts->size() / radial_pts_size;
231  // If we're a tensor product we should have no remainder
232  libmesh_assert_equal_to
233  (base_pts_size * radial_pts_size, pts->size());
234 
235  if (pts->size() > 1)
236  {
237  // lets inform the user about our assumptions.
238  // If this warning appears very often, this should be taken as a reason
239  // for rewriting this.
240  libmesh_experimental();
241  libmesh_warning("We assume that the "<<pts->size()
242  <<" points are of tensor-product type with "
243  <<radial_pts_size<<" radial points and "
244  <<base_pts_size<< " angular points.");
245  }
246 
247 
248  std::vector<Point> base_pts;
249  base_pts.reserve(base_pts_size);
250  for (std::size_t p=0; p != pts->size(); p += radial_pts_size)
251  {
252  Point pt = (*pts)[p];
253  pt(Dim-1) = 0;
254  base_pts.push_back(pt);
255  }
256 
257  // init radial shapes
258  this->init_radial_shape_functions(inf_elem, &radial_pts);
259 
260  // update the base
261  this->update_base_elem(inf_elem);
262 
263  // the finite element on the ifem base
264  base_fe = FEBase::build(Dim-1, this->fe_type);
265 
266  base_fe->calculate_phi = base_fe->calculate_dphi = base_fe->calculate_dphiref = true;
267  base_fe->get_xyz();
268  base_fe->determine_calculations();
269 
270  // init base shapes
271  base_fe->init_base_shape_functions(base_pts,
272  base_elem.get());
273 
274  // compute the shape functions and map functions of base_fe
275  // before using them later in combine_base_radial.
276 
277  if (weights)
278  {
279  base_fe->_fe_map->compute_map (base_fe->dim, *weights,
280  base_elem.get(), base_fe->calculate_d2phi);
281  }
282  else
283  {
284  std::vector<Real> dummy_weights (pts->size(), 1.);
285  base_fe->_fe_map->compute_map (base_fe->dim, dummy_weights,
286  base_elem.get(), base_fe->calculate_d2phi);
287  }
288 
289  base_fe->compute_shape_functions(base_elem.get(), *pts);
290 
291  this->init_shape_functions (radial_pts, base_pts, inf_elem);
292 
293  // combine the base and radial shapes
294  this->combine_base_radial (inf_elem);
295 
296  // weights
297  if (weights != nullptr)
298  {
299  this->_fe_map->compute_map (this->dim, *weights, inf_elem, this->calculate_d2phi);
300  }
301  else
302  {
303  std::vector<Real> dummy_weights (pts->size(), 1.);
304  this->_fe_map->compute_map (this->dim, dummy_weights, inf_elem, this->calculate_d2phi);
305  }
306 
307  // finally compute the ifem shapes
308  this->compute_shape_functions (inf_elem,*pts);
309  }
310 
311 }
312 
313 
314 
315 
316 
317 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
318 void
320 init_radial_shape_functions(const Elem * libmesh_dbg_var(inf_elem),
321  const std::vector<Point> * radial_pts)
322 {
323  libmesh_assert(radial_qrule.get() || radial_pts);
324  libmesh_assert(inf_elem);
325 
326  // Start logging the radial shape function initialization
327  LOG_SCOPE("init_radial_shape_functions()", "InfFE");
328 
329  // initialize most of the things related to mapping
330 
331  // The order to use in the radial map (currently independent of the element type)
332  const Order radial_mapping_order = Radial::mapping_order();
333  const unsigned int n_radial_mapping_shape_functions = Radial::n_dofs(radial_mapping_order);
334 
335  // initialize most of the things related to physical approximation
336  const Order radial_approx_order = fe_type.radial_order;
337  const unsigned int n_radial_approx_shape_functions = Radial::n_dofs(radial_approx_order);
338 
339  const std::size_t n_radial_qp =
340  radial_pts ? radial_pts->size() : radial_qrule->n_points();
341  const std::vector<Point> & radial_qp =
342  radial_pts ? *radial_pts : radial_qrule->get_points();
343 
344  // resize the radial data fields
345 
346  // the radial polynomials (eval)
347  mode.resize (n_radial_approx_shape_functions);
348  dmodedv.resize (n_radial_approx_shape_functions);
349 
350  // the (1-v)/2 weight
351  som.resize (n_radial_qp);
352  dsomdv.resize (n_radial_qp);
353 
354  // the radial map
355  radial_map.resize (n_radial_mapping_shape_functions);
356  dradialdv_map.resize (n_radial_mapping_shape_functions);
357 
358 
359  for (unsigned int i=0; i<n_radial_mapping_shape_functions; i++)
360  {
361  radial_map[i].resize (n_radial_qp);
362  dradialdv_map[i].resize (n_radial_qp);
363  }
364 
365 
366  for (unsigned int i=0; i<n_radial_approx_shape_functions; i++)
367  {
368  mode[i].resize (n_radial_qp);
369  dmodedv[i].resize (n_radial_qp);
370  }
371 
372 
373  // compute scalar values at radial quadrature points
374  for (std::size_t p=0; p<n_radial_qp; p++)
375  {
376  som[p] = Radial::decay (radial_qp[p](0));
377  dsomdv[p] = Radial::decay_deriv (radial_qp[p](0));
378  }
379 
380 
381  // evaluate the mode shapes in radial direction at radial quadrature points
382  for (unsigned int i=0; i<n_radial_approx_shape_functions; i++)
383  for (std::size_t p=0; p<n_radial_qp; p++)
384  {
385  mode[i][p] = InfFE<Dim,T_radial,T_map>::eval (radial_qp[p](0), radial_approx_order, i);
386  dmodedv[i][p] = InfFE<Dim,T_radial,T_map>::eval_deriv (radial_qp[p](0), radial_approx_order, i);
387  }
388 
389 
390  // evaluate the mapping functions in radial direction at radial quadrature points
391  for (unsigned int i=0; i<n_radial_mapping_shape_functions; i++)
392  for (std::size_t p=0; p<n_radial_qp; p++)
393  {
394  radial_map[i][p] = InfFE<Dim,INFINITE_MAP,T_map>::eval (radial_qp[p](0), radial_mapping_order, i);
395  dradialdv_map[i][p] = InfFE<Dim,INFINITE_MAP,T_map>::eval_deriv (radial_qp[p](0), radial_mapping_order, i);
396  }
397 }
398 
399 
400 
401 
402 
403 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
404 void InfFE<Dim,T_radial,T_map>::init_shape_functions(const std::vector<Point> & radial_qp,
405  const std::vector<Point> & base_qp,
406  const Elem * inf_elem)
407 {
408  libmesh_assert(inf_elem);
409 
410  // Start logging the radial shape function initialization
411  LOG_SCOPE("init_shape_functions()", "InfFE");
412 
413  // fast access to some const ints for the radial data
414  const unsigned int n_radial_mapping_sf = cast_int<unsigned int>(radial_map.size());
415  const unsigned int n_radial_approx_sf = cast_int<unsigned int>(mode.size());
416  const unsigned int n_radial_qp = cast_int<unsigned int>(som.size());
417 
418 
419  // initialize most of the things related to mapping
420 
421  // The element type and order to use in the base map
422  const Order base_mapping_order = base_elem->default_order();
423  const ElemType base_mapping_elem_type = base_elem->type();
424 
425  // the number of base shape functions used to construct the map
426  // (Lagrange shape functions are used for mapping in the base)
427  unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type,
428  base_mapping_order);
429 
430  const unsigned int n_total_mapping_shape_functions =
431  n_radial_mapping_sf * n_base_mapping_shape_functions;
432 
433  // initialize most of the things related to physical approximation
434  unsigned int n_base_approx_shape_functions;
435  if (Dim > 1)
436  n_base_approx_shape_functions = base_fe->n_shape_functions();
437  else
438  n_base_approx_shape_functions = 1;
439 
440 
441  const unsigned int n_total_approx_shape_functions =
442  n_radial_approx_sf * n_base_approx_shape_functions;
443 
444  // update class member field
445  _n_total_approx_sf = n_total_approx_shape_functions;
446 
447 
448  // The number of the base quadrature points.
449  const unsigned int n_base_qp = cast_int<unsigned int>(base_qp.size());
450 
451  // The total number of quadrature points.
452  const unsigned int n_total_qp = n_radial_qp * n_base_qp;
453 
454 
455  // update class member field
456  _n_total_qp = n_total_qp;
457 
458 
459 
460  // initialize the node and shape numbering maps
461  {
462  // these vectors work as follows: the i-th entry stores
463  // the associated base/radial node number
464  _radial_node_index.resize(n_total_mapping_shape_functions);
465  _base_node_index.resize(n_total_mapping_shape_functions);
466 
467  // similar for the shapes: the i-th entry stores
468  // the associated base/radial shape number
469  _radial_shape_index.resize(n_total_approx_shape_functions);
470  _base_shape_index.resize(n_total_approx_shape_functions);
471 
472  const ElemType inf_elem_type = inf_elem->type();
473 
474  // fill the node index map
475  for (unsigned int n=0; n<n_total_mapping_shape_functions; n++)
476  {
477  compute_node_indices (inf_elem_type,
478  n,
479  _base_node_index[n],
480  _radial_node_index[n]);
481  libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions);
482  libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf);
483  }
484 
485  // fill the shape index map
486  for (unsigned int n=0; n<n_total_approx_shape_functions; n++)
487  {
488  compute_shape_indices (this->fe_type,
489  inf_elem_type,
490  n,
491  _base_shape_index[n],
492  _radial_shape_index[n]);
493  libmesh_assert_less (_base_shape_index[n], n_base_approx_shape_functions);
494  libmesh_assert_less (_radial_shape_index[n], n_radial_approx_sf);
495  }
496  }
497 
498  // resize the base data fields
499  dist.resize(n_base_mapping_shape_functions);
500 
501  // resize the total data fields
502 
503  // the phase term varies with xi, eta and zeta(v): store it for _all_ qp
504  //
505  // when computing the phase, we need the base approximations
506  // therefore, initialize the phase here, but evaluate it
507  // in combine_base_radial().
508  //
509  // the weight, though, is only needed at the radial quadrature points, n_radial_qp.
510  // but for a uniform interface to the protected data fields
511  // the weight data field (which are accessible from the outside) are expanded to n_total_qp.
512  weight.resize (n_total_qp);
513  dweightdv.resize (n_total_qp);
514  dweight.resize (n_total_qp);
515 
516  dphase.resize (n_total_qp);
517  dphasedxi.resize (n_total_qp);
518  dphasedeta.resize (n_total_qp);
519  dphasedzeta.resize (n_total_qp);
520 
521  // this vector contains the integration weights for the combined quadrature rule
522  _total_qrule_weights.resize(n_total_qp);
523 
524  // InfFE's data fields phi, dphi, dphidx, phi_map etc hold the _total_
525  // shape and mapping functions, respectively
526  {
527  phi.resize (n_total_approx_shape_functions);
528  dphi.resize (n_total_approx_shape_functions);
529  dphidx.resize (n_total_approx_shape_functions);
530  dphidy.resize (n_total_approx_shape_functions);
531  dphidz.resize (n_total_approx_shape_functions);
532  dphidxi.resize (n_total_approx_shape_functions);
533 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
534  libmesh_warning("Warning: Second derivatives for Infinite elements"
535  << " are not yet implemented!"
536  << std::endl);
537 
538  d2phi.resize (n_total_approx_shape_functions);
539  d2phidx2.resize (n_total_approx_shape_functions);
540  d2phidxdy.resize (n_total_approx_shape_functions);
541  d2phidxdz.resize (n_total_approx_shape_functions);
542  d2phidy2.resize (n_total_approx_shape_functions);
543  d2phidydz.resize (n_total_approx_shape_functions);
544  d2phidz2.resize (n_total_approx_shape_functions);
545  d2phidxi2.resize (n_total_approx_shape_functions);
546 
547  if (Dim > 1)
548  {
549  d2phidxideta.resize(n_total_approx_shape_functions);
550  d2phideta2.resize(n_total_approx_shape_functions);
551  }
552 
553  if (Dim > 2)
554  {
555  d2phidetadzeta.resize(n_total_approx_shape_functions);
556  d2phidxidzeta.resize(n_total_approx_shape_functions);
557  d2phidzeta2.resize(n_total_approx_shape_functions);
558  }
559 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
560 
561  if (Dim > 1)
562  dphideta.resize(n_total_approx_shape_functions);
563 
564  if (Dim == 3)
565  dphidzeta.resize(n_total_approx_shape_functions);
566 
567  std::vector<std::vector<Real>> & phi_map = this->_fe_map->get_phi_map();
568  std::vector<std::vector<Real>> & dphidxi_map = this->_fe_map->get_dphidxi_map();
569 
570  phi_map.resize(n_total_mapping_shape_functions);
571  dphidxi_map.resize(n_total_mapping_shape_functions);
572 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
573  std::vector<std::vector<Real>> & d2phidxi2_map = this->_fe_map->get_d2phidxi2_map();
574  d2phidxi2_map.resize(n_total_mapping_shape_functions);
575 
576  if (Dim > 1)
577  {
578  std::vector<std::vector<Real>> & d2phidxideta_map = this->_fe_map->get_d2phidxideta_map();
579  std::vector<std::vector<Real>> & d2phideta2_map = this->_fe_map->get_d2phideta2_map();
580  d2phidxideta_map.resize(n_total_mapping_shape_functions);
581  d2phideta2_map.resize(n_total_mapping_shape_functions);
582  }
583 
584  if (Dim == 3)
585  {
586  std::vector<std::vector<Real>> & d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map();
587  std::vector<std::vector<Real>> & d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map();
588  std::vector<std::vector<Real>> & d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map();
589  d2phidxidzeta_map.resize(n_total_mapping_shape_functions);
590  d2phidetadzeta_map.resize(n_total_mapping_shape_functions);
591  d2phidzeta2_map.resize(n_total_mapping_shape_functions);
592  }
593 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
594 
595  if (Dim > 1)
596  {
597  std::vector<std::vector<Real>> & dphideta_map = this->_fe_map->get_dphideta_map();
598  dphideta_map.resize(n_total_mapping_shape_functions);
599  }
600 
601  if (Dim == 3)
602  {
603  std::vector<std::vector<Real>> & dphidzeta_map = this->_fe_map->get_dphidzeta_map();
604  dphidzeta_map.resize(n_total_mapping_shape_functions);
605  }
606  }
607 
608  // collect all the for loops, where inner vectors are
609  // resized to the appropriate number of quadrature points
610  {
611  for (unsigned int i=0; i<n_total_approx_shape_functions; i++)
612  {
613  phi[i].resize (n_total_qp);
614  dphi[i].resize (n_total_qp);
615  dphidx[i].resize (n_total_qp);
616  dphidy[i].resize (n_total_qp);
617  dphidz[i].resize (n_total_qp);
618  dphidxi[i].resize (n_total_qp);
619 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
620  d2phi[i].resize (n_total_qp);
621  d2phidx2[i].resize (n_total_qp);
622  d2phidxdy[i].resize (n_total_qp);
623  d2phidxdz[i].resize (n_total_qp);
624  d2phidy2[i].resize (n_total_qp);
625  d2phidydz[i].resize (n_total_qp);
626  d2phidy2[i].resize (n_total_qp);
627  d2phidxi2[i].resize (n_total_qp);
628 
629  if (Dim > 1)
630  {
631  d2phidxideta[i].resize (n_total_qp);
632  d2phideta2[i].resize (n_total_qp);
633  }
634  if (Dim > 2)
635  {
636  d2phidxidzeta[i].resize (n_total_qp);
637  d2phidetadzeta[i].resize (n_total_qp);
638  d2phidzeta2[i].resize (n_total_qp);
639  }
640 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
641 
642  if (Dim > 1)
643  dphideta[i].resize (n_total_qp);
644 
645  if (Dim == 3)
646  dphidzeta[i].resize (n_total_qp);
647 
648  }
649 
650  for (unsigned int i=0; i<n_total_mapping_shape_functions; i++)
651  {
652  std::vector<std::vector<Real>> & phi_map = this->_fe_map->get_phi_map();
653  std::vector<std::vector<Real>> & dphidxi_map = this->_fe_map->get_dphidxi_map();
654  phi_map[i].resize (n_total_qp);
655  dphidxi_map[i].resize (n_total_qp);
656 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
657  std::vector<std::vector<Real>> & d2phidxi2_map = this->_fe_map->get_d2phidxi2_map();
658  d2phidxi2_map[i].resize (n_total_qp);
659  if (Dim > 1)
660  {
661  std::vector<std::vector<Real>> & d2phidxideta_map = this->_fe_map->get_d2phidxideta_map();
662  std::vector<std::vector<Real>> & d2phideta2_map = this->_fe_map->get_d2phideta2_map();
663  d2phidxideta_map[i].resize (n_total_qp);
664  d2phideta2_map[i].resize (n_total_qp);
665  }
666 
667  if (Dim > 2)
668  {
669  std::vector<std::vector<Real>> & d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map();
670  std::vector<std::vector<Real>> & d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map();
671  std::vector<std::vector<Real>> & d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map();
672  d2phidxidzeta_map[i].resize (n_total_qp);
673  d2phidetadzeta_map[i].resize (n_total_qp);
674  d2phidzeta2_map[i].resize (n_total_qp);
675  }
676 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
677 
678  if (Dim > 1)
679  {
680  std::vector<std::vector<Real>> & dphideta_map = this->_fe_map->get_dphideta_map();
681  dphideta_map[i].resize (n_total_qp);
682  }
683 
684  if (Dim == 3)
685  {
686  std::vector<std::vector<Real>> & dphidzeta_map = this->_fe_map->get_dphidzeta_map();
687  dphidzeta_map[i].resize (n_total_qp);
688  }
689  }
690  }
691 
692 
693 
694  {
695  // (a) compute scalar values at _all_ quadrature points -- for uniform
696  // access from the outside to these fields
697  // (b) form a std::vector<Real> which contains the appropriate weights
698  // of the combined quadrature rule!
699  libmesh_assert_equal_to (radial_qp.size(), n_radial_qp);
700 
701  if (radial_qrule && base_qrule)
702  {
703  const std::vector<Real> & radial_qw = radial_qrule->get_weights();
704  const std::vector<Real> & base_qw = base_qrule->get_weights();
705  libmesh_assert_equal_to (radial_qw.size(), n_radial_qp);
706  libmesh_assert_equal_to (base_qw.size(), n_base_qp);
707 
708  for (unsigned int rp=0; rp<n_radial_qp; rp++)
709  for (unsigned int bp=0; bp<n_base_qp; bp++)
710  {
711  weight[bp + rp*n_base_qp] = Radial::D(radial_qp[rp](0));
712  dweightdv[bp + rp*n_base_qp] = Radial::D_deriv(radial_qp[rp](0));
713  _total_qrule_weights[bp + rp*n_base_qp] = radial_qw[rp] * base_qw[bp];
714  }
715  }
716  else
717  {
718  for (unsigned int rp=0; rp<n_radial_qp; rp++)
719  for (unsigned int bp=0; bp<n_base_qp; bp++)
720  {
721  weight[bp + rp*n_base_qp] = Radial::D(radial_qp[rp](0));
722  dweightdv[bp + rp*n_base_qp] = Radial::D_deriv(radial_qp[rp](0));
723  }
724  }
725  }
726 }
727 
728 
729 
730 
731 
732 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
734 {
735  libmesh_assert(inf_elem);
736  // at least check whether the base element type is correct.
737  // otherwise this version of computing dist would give problems
738  libmesh_assert_equal_to (base_elem->type(), Base::get_elem_type(inf_elem->type()));
739 
740  // Start logging the combination of radial and base parts
741  LOG_SCOPE("combine_base_radial()", "InfFE");
742 
743  // zero the phase, since it is to be summed up
744  std::fill (dphasedxi.begin(), dphasedxi.end(), 0.);
745  std::fill (dphasedeta.begin(), dphasedeta.end(), 0.);
746  std::fill (dphasedzeta.begin(), dphasedzeta.end(), 0.);
747 
748 
749  const unsigned int n_base_mapping_sf = cast_int<unsigned int>(dist.size());
750  const Point origin = inf_elem->origin();
751 
752  // for each new infinite element, compute the radial distances
753  for (unsigned int n=0; n<n_base_mapping_sf; n++)
754  dist[n] = Point(base_elem->point(n) - origin).norm();
755 
756 
757  switch (Dim)
758  {
759  // 1D
760  case 1:
761  {
762  libmesh_not_implemented();
763  break;
764  }
765 
766  // 2D
767  case 2:
768  {
769  libmesh_not_implemented();
770  break;
771  }
772 
773  // 3D
774  case 3:
775  {
776  // fast access to the approximation and mapping shapes of base_fe
777  const std::vector<std::vector<Real>> & S = base_fe->phi;
778  const std::vector<std::vector<Real>> & Ss = base_fe->dphidxi;
779  const std::vector<std::vector<Real>> & St = base_fe->dphideta;
780  const std::vector<std::vector<Real>> & S_map = (base_fe->get_fe_map()).get_phi_map();
781  const std::vector<std::vector<Real>> & Ss_map = (base_fe->get_fe_map()).get_dphidxi_map();
782  const std::vector<std::vector<Real>> & St_map = (base_fe->get_fe_map()).get_dphideta_map();
783 
784  const unsigned int n_radial_qp = cast_int<unsigned int>(som.size());
785  if (radial_qrule)
786  libmesh_assert_equal_to(n_radial_qp, radial_qrule->n_points());
787  const unsigned int n_base_qp = cast_int<unsigned int>(S_map[0].size());
788  if (base_qrule)
789  libmesh_assert_equal_to(n_base_qp, base_qrule->n_points());
790 
791  const unsigned int n_total_mapping_sf =
792  cast_int<unsigned int>(radial_map.size()) * n_base_mapping_sf;
793 
794  const unsigned int n_total_approx_sf = Radial::n_dofs(fe_type.radial_order) * base_fe->n_shape_functions();
795 
796 
797  // compute the phase term derivatives
798  {
799  unsigned int tp=0;
800  for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qps
801  for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qps
802  {
803  // sum over all base shapes, to get the average distance
804  for (unsigned int i=0; i<n_base_mapping_sf; i++)
805  {
806  dphasedxi[tp] += Ss_map[i][bp] * dist[i] * radial_map [1][rp];
807  dphasedeta[tp] += St_map[i][bp] * dist[i] * radial_map [1][rp];
808  dphasedzeta[tp] += S_map [i][bp] * dist[i] * dradialdv_map[1][rp];
809  }
810 
811  tp++;
812 
813  } // loop radial and base qps
814  }
815 
816  libmesh_assert_equal_to (phi.size(), n_total_approx_sf);
817  libmesh_assert_equal_to (dphidxi.size(), n_total_approx_sf);
818  libmesh_assert_equal_to (dphideta.size(), n_total_approx_sf);
819  libmesh_assert_equal_to (dphidzeta.size(), n_total_approx_sf);
820 
821  // compute the overall approximation shape functions,
822  // pick the appropriate radial and base shapes through using
823  // _base_shape_index and _radial_shape_index
824  for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qps
825  for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qps
826  for (unsigned int ti=0; ti<n_total_approx_sf; ti++) // over _all_ approx_sf
827  {
828  // let the index vectors take care of selecting the appropriate base/radial shape
829  const unsigned int bi = _base_shape_index [ti];
830  const unsigned int ri = _radial_shape_index[ti];
831  phi [ti][bp+rp*n_base_qp] = S [bi][bp] * mode[ri][rp] * som[rp];
832  dphidxi [ti][bp+rp*n_base_qp] = Ss[bi][bp] * mode[ri][rp] * som[rp];
833  dphideta [ti][bp+rp*n_base_qp] = St[bi][bp] * mode[ri][rp] * som[rp];
834  dphidzeta[ti][bp+rp*n_base_qp] = S [bi][bp]
835  * (dmodedv[ri][rp] * som[rp] + mode[ri][rp] * dsomdv[rp]);
836  }
837 
838  std::vector<std::vector<Real>> & phi_map = this->_fe_map->get_phi_map();
839  std::vector<std::vector<Real>> & dphidxi_map = this->_fe_map->get_dphidxi_map();
840  std::vector<std::vector<Real>> & dphideta_map = this->_fe_map->get_dphideta_map();
841  std::vector<std::vector<Real>> & dphidzeta_map = this->_fe_map->get_dphidzeta_map();
842 
843  libmesh_assert_equal_to (phi_map.size(), n_total_mapping_sf);
844  libmesh_assert_equal_to (dphidxi_map.size(), n_total_mapping_sf);
845  libmesh_assert_equal_to (dphideta_map.size(), n_total_mapping_sf);
846  libmesh_assert_equal_to (dphidzeta_map.size(), n_total_mapping_sf);
847 
848  // compute the overall mapping functions,
849  // pick the appropriate radial and base entries through using
850  // _base_node_index and _radial_node_index
851  for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qps
852  for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qps
853  for (unsigned int ti=0; ti<n_total_mapping_sf; ti++) // over all mapping shapes
854  {
855  // let the index vectors take care of selecting the appropriate base/radial mapping shape
856  const unsigned int bi = _base_node_index [ti];
857  const unsigned int ri = _radial_node_index[ti];
858  phi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp];
859  dphidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp];
860  dphideta_map [ti][bp+rp*n_base_qp] = St_map[bi][bp] * radial_map [ri][rp];
861  dphidzeta_map[ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp];
862  }
863 
864  break;
865  }
866 
867  default:
868  libmesh_error_msg("Unsupported Dim = " << Dim);
869  }
870 }
871 
872 
873 
874 
875 
876 
877 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
879  const std::vector<Point> &)
880 {
881  // Start logging the overall computation of shape functions
882  LOG_SCOPE("compute_shape_functions()", "InfFE");
883 
884  const unsigned int n_total_qp = _n_total_qp;
885 
886  // Compute the shape function values (and derivatives)
887  // at the Quadrature points. Note that the actual values
888  // have already been computed via init_shape_functions
889 
890  // Compute the value of the derivative shape function i at quadrature point p
891  switch (dim)
892  {
893 
894  case 1:
895  {
896  libmesh_not_implemented();
897  break;
898  }
899 
900  case 2:
901  {
902  libmesh_not_implemented();
903  break;
904  }
905 
906  case 3:
907  {
908  const std::vector<Real> & dxidx_map = this->_fe_map->get_dxidx();
909  const std::vector<Real> & dxidy_map = this->_fe_map->get_dxidy();
910  const std::vector<Real> & dxidz_map = this->_fe_map->get_dxidz();
911 
912  const std::vector<Real> & detadx_map = this->_fe_map->get_detadx();
913  const std::vector<Real> & detady_map = this->_fe_map->get_detady();
914  const std::vector<Real> & detadz_map = this->_fe_map->get_detadz();
915 
916  const std::vector<Real> & dzetadx_map = this->_fe_map->get_dzetadx();
917  const std::vector<Real> & dzetady_map = this->_fe_map->get_dzetady();
918  const std::vector<Real> & dzetadz_map = this->_fe_map->get_dzetadz();
919 
920  // These are _all_ shape functions of this infinite element
921  for (auto i : index_range(phi))
922  for (unsigned int p=0; p<n_total_qp; p++)
923  {
924  // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx);
925  dphi[i][p](0) =
926  dphidx[i][p] = (dphidxi[i][p]*dxidx_map[p] +
927  dphideta[i][p]*detadx_map[p] +
928  dphidzeta[i][p]*dzetadx_map[p]);
929 
930  // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy);
931  dphi[i][p](1) =
932  dphidy[i][p] = (dphidxi[i][p]*dxidy_map[p] +
933  dphideta[i][p]*detady_map[p] +
934  dphidzeta[i][p]*dzetady_map[p]);
935 
936  // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz);
937  dphi[i][p](2) =
938  dphidz[i][p] = (dphidxi[i][p]*dxidz_map[p] +
939  dphideta[i][p]*detadz_map[p] +
940  dphidzeta[i][p]*dzetadz_map[p]);
941  }
942 
943 
944  // This is the derivative of the phase term of this infinite element
945  for (unsigned int p=0; p<n_total_qp; p++)
946  {
947  // the derivative of the phase term
948  dphase[p](0) = (dphasedxi[p] * dxidx_map[p] +
949  dphasedeta[p] * detadx_map[p] +
950  dphasedzeta[p] * dzetadx_map[p]);
951 
952  dphase[p](1) = (dphasedxi[p] * dxidy_map[p] +
953  dphasedeta[p] * detady_map[p] +
954  dphasedzeta[p] * dzetady_map[p]);
955 
956  dphase[p](2) = (dphasedxi[p] * dxidz_map[p] +
957  dphasedeta[p] * detadz_map[p] +
958  dphasedzeta[p] * dzetadz_map[p]);
959 
960  // the derivative of the radial weight - varies only in radial direction,
961  // therefore dweightdxi = dweightdeta = 0.
962  dweight[p](0) = dweightdv[p] * dzetadx_map[p];
963 
964  dweight[p](1) = dweightdv[p] * dzetady_map[p];
965 
966  dweight[p](2) = dweightdv[p] * dzetadz_map[p];
967  }
968 
969  break;
970  }
971 
972  default:
973  libmesh_error_msg("Unsupported dim = " << dim);
974  }
975 }
976 
977 
978 
979 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map>
981 {
982  return false;
983 }
984 
985 } // namespace libMesh
986 
987 
988 // Explicit instantiations
992 
993 
994 
995 #endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
Manages the family, order, etc. parameters for a given FE.
Definition: fe_type.h:179
virtual Point origin() const
Definition: elem.h:1553
void combine_base_radial(const Elem *inf_elem)
Definition: inf_fe.C:733
static Real eval_deriv(Real v, Order o_radial, unsigned int i)
void init_shape_functions(const std::vector< Point > &radial_qp, const std::vector< Point > &base_qp, const Elem *inf_elem)
Definition: inf_fe.C:404
The base class for all geometric element types.
Definition: elem.h:100
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Definition: int_range.h:104
virtual QuadratureType type() const =0
virtual void compute_shape_functions(const Elem *, const std::vector< Point > &) override
Definition: inf_fe.C:878
friend class InfFE
Definition: inf_fe.h:818
std::unique_ptr< FEBase > base_fe
Definition: inf_fe.h:772
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:233
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Order get_order() const
Definition: quadrature.h:203
static Real eval(Real v, Order o_radial, unsigned int i)
unsigned int get_dim() const
Definition: quadrature.h:136
InfMapType inf_map
Definition: fe_type.h:258
virtual bool shapes_need_reinit() const override
Definition: inf_fe.C:980
void init_radial_shape_functions(const Elem *inf_elem, const std::vector< Point > *radial_pts=nullptr)
Definition: inf_fe.C:320
static std::unique_ptr< QBase > build(const std::string &name, const unsigned int dim, const Order order=INVALID_ORDER)
FEFamily radial_family
Definition: fe_type.h:250
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Implements 1, 2, and 3D "Gaussian" quadrature rules.
virtual void reinit(const Elem *elem, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr) override
Definition: inf_fe.C:109
virtual void attach_quadrature_rule(QBase *q) override
Definition: inf_fe.C:69
virtual ElemType type() const =0
A geometric point in (x,y,z) space.
Definition: point.h:38
Base class for all quadrature families and orders.
Definition: quadrature.h:62
void update_base_elem(const Elem *inf_elem)
Definition: inf_fe.C:98