libMesh::InfElemBuilder Class Reference

#include <inf_elem_builder.h>

Public Types

typedef std::pair< bool, double > InfElemOriginValue
 

Public Member Functions

 InfElemBuilder (MeshBase &mesh)
 
const Point build_inf_elem (const bool be_verbose=false)
 
const Point build_inf_elem (const InfElemOriginValue &origin_x, const InfElemOriginValue &origin_y, const InfElemOriginValue &origin_z, const bool x_sym=false, const bool y_sym=false, const bool z_sym=false, const bool be_verbose=false, std::vector< const Node *> *inner_boundary_nodes=nullptr)
 

Private Member Functions

void build_inf_elem (const Point &origin, const bool x_sym=false, const bool y_sym=false, const bool z_sym=false, const bool be_verbose=false, std::set< std::pair< dof_id_type, unsigned int >> *inner_faces=nullptr)
 

Private Attributes

MeshBase_mesh
 

Detailed Description

This class is used to build infinite elements on top of an existing mesh. It only makes sense to use this if LIBMESH_ENABLE_INFINITE_ELEMENTS is true.

Author
Daniel Dreyer
John W. Peterson
Date
2004

Definition at line 53 of file inf_elem_builder.h.

Member Typedef Documentation

◆ InfElemOriginValue

typedef std::pair<bool, double> libMesh::InfElemBuilder::InfElemOriginValue

Useful typedef

Definition at line 65 of file inf_elem_builder.h.

Constructor & Destructor Documentation

◆ InfElemBuilder()

libMesh::InfElemBuilder::InfElemBuilder ( MeshBase mesh)
inlineexplicit

Constructor.

Definition at line 60 of file inf_elem_builder.h.

60 : _mesh(mesh) {}
MeshBase & mesh

Member Function Documentation

◆ build_inf_elem() [1/3]

const Point libMesh::InfElemBuilder::build_inf_elem ( const bool  be_verbose = false)

Build infinite elements atop a volume-based mesh, determine origin automatically.

Returns
The origin as a const Point to make it more obvious that the origin should not change after the infinite elements have been built.

When symmetry planes are present, use the version with optional symmetry switches. The flag be_verbose enables some diagnostic output.

Definition at line 41 of file inf_elem_builder.C.

References _mesh, libMesh::MeshTools::create_bounding_box(), libMesh::out, libMesh::MeshBase::prepare_for_use(), libMesh::ParallelObject::processor_id(), and libMesh::TypeVector< T >::write_unformatted().

Referenced by build_inf_elem().

42 {
43  // determine origin automatically,
44  // works only if the mesh has no symmetry planes.
45  const BoundingBox b_box = MeshTools::create_bounding_box(_mesh);
46  Point origin = (b_box.first + b_box.second) / 2;
47 
48  if (be_verbose && _mesh.processor_id() == 0)
49  {
50 #ifdef DEBUG
51  libMesh::out << " Determined origin for Infinite Elements:"
52  << std::endl
53  << " ";
54  origin.write_unformatted(libMesh::out);
55  libMesh::out << std::endl;
56 #endif
57  }
58 
59  // Call the protected implementation function with the
60  // automatically determined origin.
61  this->build_inf_elem(origin, false, false, false, be_verbose);
62 
63  // when finished with building the Ifems,
64  // it remains to prepare the mesh for use:
65  // find neighbors (again), partition (if needed)...
66  this->_mesh.prepare_for_use (/*skip_renumber =*/ false);
67 
68  return origin;
69 }
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:386
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Definition: mesh_base.C:152
const Point build_inf_elem(const bool be_verbose=false)
processor_id_type processor_id() const
OStreamProxy out(std::cout)

◆ build_inf_elem() [2/3]

const Point libMesh::InfElemBuilder::build_inf_elem ( const InfElemOriginValue origin_x,
const InfElemOriginValue origin_y,
const InfElemOriginValue origin_z,
const bool  x_sym = false,
const bool  y_sym = false,
const bool  z_sym = false,
const bool  be_verbose = false,
std::vector< const Node *> *  inner_boundary_nodes = nullptr 
)
Returns
The origin of the infinite elements. Builds infinite elements atop a volume-based mesh. Finds all faces on the outer boundary and build infinite elements on them. Using the InfElemOriginValue the user can prescribe only selected origin coordinates. The remaining coordinates are computed from the center of the bounding box of the mesh.

During the search for faces on which infinite elements are built, interior faces that are not on symmetry planes are found, too. When an (optional) pointer to inner_boundary_nodes is provided, then this vector will be filled with the nodes that lie on the inner boundary.

Faces which lie in at least one symmetry plane are skipped. The three optional booleans x_sym, y_sym, z_sym indicate symmetry planes (through the origin, obviously) perpendicular to the x, y and z direction, respectively. The flag be_verbose enables some diagnostic output.

Definition at line 82 of file inf_elem_builder.C.

References _mesh, build_inf_elem(), libMesh::Elem::build_side_ptr(), libMesh::MeshTools::create_bounding_box(), libMesh::MeshBase::elem_ref(), libMesh::MeshBase::node_ptr(), libMesh::out, libMesh::MeshBase::prepare_for_use(), libMesh::MeshBase::print_info(), side, and libMesh::TypeVector< T >::write_unformatted().

90 {
91  START_LOG("build_inf_elem()", "InfElemBuilder");
92 
93  // first determine the origin of the
94  // infinite elements. For this, the
95  // origin defaults to the given values,
96  // and may be overridden when the user
97  // provided values
98  Point origin(origin_x.second, origin_y.second, origin_z.second);
99 
100  // when only _one_ of the origin coordinates is _not_
101  // given, we have to determine it on our own
102  if ( !origin_x.first || !origin_y.first || !origin_z.first)
103  {
104  // determine origin
105  const BoundingBox b_box = MeshTools::create_bounding_box(_mesh);
106  const Point auto_origin = (b_box.first+b_box.second)/2;
107 
108  // override default values, if necessary
109  if (!origin_x.first)
110  origin(0) = auto_origin(0);
111  if (!origin_y.first)
112  origin(1) = auto_origin(1);
113  if (!origin_z.first)
114  origin(2) = auto_origin(2);
115 
116  if (be_verbose)
117  {
118  libMesh::out << " Origin for Infinite Elements:" << std::endl;
119 
120  if (!origin_x.first)
121  libMesh::out << " determined x-coordinate" << std::endl;
122  if (!origin_y.first)
123  libMesh::out << " determined y-coordinate" << std::endl;
124  if (!origin_z.first)
125  libMesh::out << " determined z-coordinate" << std::endl;
126 
127  libMesh::out << " coordinates: ";
128  origin.write_unformatted(libMesh::out);
129  libMesh::out << std::endl;
130  }
131  }
132 
133  else if (be_verbose)
134 
135  {
136  libMesh::out << " Origin for Infinite Elements:" << std::endl;
137  libMesh::out << " coordinates: ";
138  origin.write_unformatted(libMesh::out);
139  libMesh::out << std::endl;
140  }
141 
142 
143 
144  // Now that we have the origin, check if the user provided an \p
145  // inner_boundary_nodes. If so, we pass a std::set to the actual
146  // implementation of the build_inf_elem(), so that we can convert
147  // this to the Node * vector
148  if (inner_boundary_nodes != nullptr)
149  {
150  // note that the std::set that we will get
151  // from build_inf_elem() uses the index of
152  // the element in this->_elements vector,
153  // and the second entry is the side index
154  // for this element. Therefore, we do _not_
155  // need to renumber nodes and elements
156  // prior to building the infinite elements.
157  //
158  // However, note that this method here uses
159  // node id's... Do we need to renumber?
160 
161 
162  // Form the list of faces of elements which finally
163  // will tell us which nodes should receive boundary
164  // conditions (to form the std::vector<const Node *>)
165  std::set<std::pair<dof_id_type,
166  unsigned int>> inner_faces;
167 
168 
169  // build infinite elements
170  this->build_inf_elem(origin,
171  x_sym, y_sym, z_sym,
172  be_verbose,
173  &inner_faces);
174 
175  if (be_verbose)
176  {
177  this->_mesh.print_info();
178  libMesh::out << "Data pre-processing:" << std::endl
179  << " convert the <int,int> list to a Node * list..."
180  << std::endl;
181  }
182 
183  // First use a std::vector<dof_id_type> that holds
184  // the global node numbers. Then sort this vector,
185  // so that it can be made unique (no multiple occurrence
186  // of a node), and then finally insert the Node * in
187  // the vector inner_boundary_nodes.
188  //
189  // Reserve memory for the vector<> with
190  // 4 times the size of the number of elements in the
191  // std::set. This is a good bet for Quad4 face elements.
192  // For higher-order elements, this probably _has_ to lead
193  // to additional allocations...
194  // Practice has to show how this affects performance.
195  std::vector<dof_id_type> inner_boundary_node_numbers;
196  inner_boundary_node_numbers.reserve(4*inner_faces.size());
197 
198  // Now transform the set of pairs to a list of (possibly
199  // duplicate) global node numbers.
200  std::set<std::pair<dof_id_type,unsigned int>>::iterator face_it = inner_faces.begin();
201  const std::set<std::pair<dof_id_type,unsigned int>>::iterator face_end = inner_faces.end();
202  for (; face_it!=face_end; ++face_it)
203  {
204  std::pair<dof_id_type,unsigned int> p = *face_it;
205 
206  // build a full-ordered side element to get _all_ the base nodes
207  std::unique_ptr<Elem> side(this->_mesh.elem_ref(p.first).build_side_ptr(p.second));
208 
209  // insert all the node numbers in inner_boundary_node_numbers
210  for (unsigned int n=0; n<side->n_nodes(); n++)
211  inner_boundary_node_numbers.push_back(side->node_id(n));
212  }
213 
214 
215  // inner_boundary_node_numbers now still holds multiple entries of
216  // node numbers. So first sort, then unique the vector.
217  // Note that \p std::unique only puts the new ones in
218  // front, while to leftovers are not deleted. Instead,
219  // it returns a pointer to the end of the unique range.
220  //TODO:[BSK] int_ibn_size_before is not the same type as unique_size!
221 #ifndef NDEBUG
222  const std::size_t ibn_size_before = inner_boundary_node_numbers.size();
223 #endif
224  std::sort (inner_boundary_node_numbers.begin(), inner_boundary_node_numbers.end());
225  std::vector<dof_id_type>::iterator unique_end =
226  std::unique (inner_boundary_node_numbers.begin(), inner_boundary_node_numbers.end());
227 
228  std::size_t unique_size = std::distance(inner_boundary_node_numbers.begin(), unique_end);
229  libmesh_assert_less_equal (unique_size, ibn_size_before);
230 
231  // Finally, create const Node * in the inner_boundary_nodes
232  // vector. Reserve, not resize (otherwise, the push_back
233  // would append the interesting nodes, while nullptr-nodes
234  // live in the resize'd area...
235  inner_boundary_nodes->reserve (unique_size);
236  inner_boundary_nodes->clear();
237 
238 
239  std::vector<dof_id_type>::iterator pos_it = inner_boundary_node_numbers.begin();
240  for (; pos_it != unique_end; ++pos_it)
241  {
242  const Node * node = this->_mesh.node_ptr(*pos_it);
243  inner_boundary_nodes->push_back(node);
244  }
245 
246  if (be_verbose)
247  libMesh::out << " finished identifying " << unique_size
248  << " target nodes." << std::endl;
249  }
250 
251  else
252 
253  {
254  // There are no inner boundary nodes, so simply build the infinite elements
255  this->build_inf_elem(origin, x_sym, y_sym, z_sym, be_verbose);
256  }
257 
258 
259  STOP_LOG("build_inf_elem()", "InfElemBuilder");
260 
261  // when finished with building the Ifems,
262  // it remains to prepare the mesh for use:
263  // find neighbors again, partition (if needed)...
264  this->_mesh.prepare_for_use (/*skip_renumber =*/ false);
265 
266  return origin;
267 }
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:386
unsigned short int side
Definition: xdr_io.C:50
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=true)=0
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Definition: mesh_base.C:152
const Point build_inf_elem(const bool be_verbose=false)
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:504
void print_info(std::ostream &os=libMesh::out) const
Definition: mesh_base.C:412
virtual const Node * node_ptr(const dof_id_type i) const =0
OStreamProxy out(std::cout)
uint8_t dof_id_type
Definition: id_types.h:64

◆ build_inf_elem() [3/3]

void libMesh::InfElemBuilder::build_inf_elem ( const Point origin,
const bool  x_sym = false,
const bool  y_sym = false,
const bool  z_sym = false,
const bool  be_verbose = false,
std::set< std::pair< dof_id_type, unsigned int >> *  inner_faces = nullptr 
)
private

Build infinite elements atop a volume-based mesh. Actual implementation.

Definition at line 278 of file inf_elem_builder.C.

References _mesh, std::abs(), libMesh::MeshBase::active_element_ptr_range(), libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_point(), libMesh::Elem::build_side_ptr(), libMesh::Elem::dim(), libMesh::EDGE2, libMesh::EDGE3, libMesh::MeshBase::elem_ref(), libMesh::MeshBase::find_neighbors(), libMesh::DofObject::id(), libMesh::Elem::is_node_on_side(), libMesh::MeshBase::is_serial(), libMesh::MeshBase::libmesh_assert_valid_parallel_ids(), libMesh::MeshBase::max_elem_id(), libMesh::MeshBase::max_node_id(), libMesh::MeshBase::n_elem(), libMesh::Elem::n_sides(), libMesh::Elem::n_vertices(), libMesh::Elem::neighbor_ptr(), libMesh::MeshBase::node_ref(), libMesh::TypeVector< T >::norm(), libMesh::out, libMesh::MeshBase::parallel_max_unique_id(), libMesh::MeshBase::point(), libMesh::DofObject::processor_id(), libMesh::QUAD4, libMesh::QUAD8, libMesh::QUAD9, libMesh::Real, libMesh::remote_elem, libMesh::DofObject::set_id(), libMesh::Elem::set_neighbor(), libMesh::Elem::set_node(), libMesh::DofObject::set_unique_id(), side, libMesh::Elem::side_index_range(), libMesh::TRI3, and libMesh::TRI6.

285 {
286  if (be_verbose)
287  {
288 #ifdef DEBUG
289  libMesh::out << " Building Infinite Elements:" << std::endl;
290  libMesh::out << " updating element neighbor tables..." << std::endl;
291 #else
292  libMesh::out << " Verbose mode disabled in non-debug mode." << std::endl;
293 #endif
294  }
295 
296 
297  // update element neighbors
298  this->_mesh.find_neighbors();
299 
300  LOG_SCOPE("build_inf_elem()", "InfElemBuilder");
301 
302  // A set for storing element number, side number pairs.
303  // pair.first == element number, pair.second == side number
304  std::set<std::pair<dof_id_type,unsigned int>> faces;
305  std::set<std::pair<dof_id_type,unsigned int>> ofaces;
306 
307  // A set for storing node numbers on the outer faces.
308  std::set<dof_id_type> onodes;
309 
310  // The distance to the farthest point in the mesh from the origin
311  Real max_r=0.;
312 
313  // The index of the farthest point in the mesh from the origin
314  int max_r_node = -1;
315 
316 #ifdef DEBUG
317  if (be_verbose)
318  {
319  libMesh::out << " collecting boundary sides";
320  if (x_sym || y_sym || z_sym)
321  libMesh::out << ", skipping sides in symmetry planes..." << std::endl;
322  else
323  libMesh::out << "..." << std::endl;
324  }
325 #endif
326 
327  // Iterate through all elements and sides, collect indices of all active
328  // boundary sides in the faces set. Skip sides which lie in symmetry planes.
329  // Later, sides of the inner boundary will be sorted out.
330  for (const auto & elem : _mesh.active_element_ptr_range())
331  for (auto s : elem->side_index_range())
332  if (elem->neighbor_ptr(s) == nullptr)
333  {
334  // note that it is safe to use the Elem::side() method,
335  // which gives a non-full-ordered element
336  std::unique_ptr<Elem> side(elem->build_side_ptr(s));
337 
338  // bool flags for symmetry detection
339  bool sym_side=false;
340  bool on_x_sym=true;
341  bool on_y_sym=true;
342  bool on_z_sym=true;
343 
344 
345  // Loop over the nodes to check whether they are on the symmetry planes,
346  // and therefore sufficient to use a non-full-ordered side element
347  for (unsigned int n=0; n<side->n_nodes(); n++)
348  {
349  const Point dist_from_origin =
350  this->_mesh.point(side->node_id(n)) - origin;
351 
352  if (x_sym)
353  if (std::abs(dist_from_origin(0)) > 1.e-3)
354  on_x_sym=false;
355 
356  if (y_sym)
357  if (std::abs(dist_from_origin(1)) > 1.e-3)
358  on_y_sym=false;
359 
360  if (z_sym)
361  if (std::abs(dist_from_origin(2)) > 1.e-3)
362  on_z_sym=false;
363 
364  // if (x_sym)
365  // if (std::abs(dist_from_origin(0)) > 1.e-6)
366  // on_x_sym=false;
367 
368  // if (y_sym)
369  // if (std::abs(dist_from_origin(1)) > 1.e-6)
370  // on_y_sym=false;
371 
372  // if (z_sym)
373  // if (std::abs(dist_from_origin(2)) > 1.e-6)
374  // on_z_sym=false;
375 
376  //find the node most distant from origin
377 
378  Real r = dist_from_origin.norm();
379  if (r > max_r)
380  {
381  max_r = r;
382  max_r_node=side->node_id(n);
383  }
384 
385  }
386 
387  sym_side = (x_sym && on_x_sym) || (y_sym && on_y_sym) || (z_sym && on_z_sym);
388 
389  if (!sym_side)
390  faces.insert( std::make_pair(elem->id(), s) );
391 
392  } // neighbor(s) == nullptr
393 
394 
395 
396 
397 
398 
399  // If a boundary side has one node on the outer boundary,
400  // all points of this side are on the outer boundary.
401  // Start with the node most distant from origin, which has
402  // to be on the outer boundary, then recursively find all
403  // sides and nodes connected to it. Found sides are moved
404  // from faces to ofaces, nodes are collected in onodes.
405  // Here, the search is done iteratively, because, depending on
406  // the mesh, a very high level of recursion might be necessary.
407  if (max_r_node >= 0)
408  // include the possibility of the 1st element being most far away.
409  // Only the case of no outer boundary is to be excluded.
410  onodes.insert(max_r_node);
411 
412 
413  {
414  auto face_it = faces.begin();
415  auto face_end = faces.end();
416  unsigned int facesfound=0;
417  while (face_it != face_end) {
418  std::pair<dof_id_type, unsigned int> p = *face_it;
419 
420  // This has to be a full-ordered side element,
421  // since we need the correct n_nodes,
422  std::unique_ptr<Elem> side(this->_mesh.elem_ref(p.first).build_side_ptr(p.second));
423 
424  bool found=false;
425  for (unsigned int sn=0; sn<side->n_nodes(); sn++)
426  if (onodes.count(side->node_id(sn)))
427  {
428  found=true;
429  break;
430  }
431 
432  // If a new oface is found, include its nodes in onodes
433  if (found)
434  {
435  for (unsigned int sn=0; sn<side->n_nodes(); sn++)
436  onodes.insert(side->node_id(sn));
437 
438  ofaces.insert(p);
439  face_it = faces.erase(face_it); // increment is done here
440 
441  facesfound++;
442  }
443 
444  else
445  ++face_it; // increment is done here
446 
447  // If at least one new oface was found in this cycle,
448  // do another search cycle.
449  if (facesfound>0 && face_it == faces.end())
450  {
451  facesfound = 0;
452  face_it = faces.begin();
453  }
454  }
455  }
456 
457 
458 #ifdef DEBUG
459  if (be_verbose)
460  libMesh::out << " found "
461  << faces.size()
462  << " inner and "
463  << ofaces.size()
464  << " outer boundary faces"
465  << std::endl;
466 #endif
467 
468  // When the user provided a non-null pointer to
469  // inner_faces, that implies he wants to have
470  // this std::set. For now, simply copy the data.
471  if (inner_faces != nullptr)
472  *inner_faces = faces;
473 
474  // free memory, clear our local variable, no need
475  // for it any more.
476  faces.clear();
477 
478 
479  // outer_nodes maps onodes to their duplicates
480  std::map<dof_id_type, Node *> outer_nodes;
481 
482  // We may need to pick our own object ids in parallel
483  dof_id_type old_max_node_id = _mesh.max_node_id();
484  dof_id_type old_max_elem_id = _mesh.max_elem_id();
485 
486  // Likewise with our unique_ids
487 #ifdef LIBMESH_ENABLE_UNIQUE_ID
488  unique_id_type old_max_unique_id = _mesh.parallel_max_unique_id();
489 #endif
490 
491  // for each boundary node, add an outer_node with
492  // double distance from origin.
493  std::set<dof_id_type>::iterator on_it = onodes.begin();
494  for ( ; on_it != onodes.end(); ++on_it)
495  {
496  Point p = (Point(this->_mesh.point(*on_it)) * 2) - origin;
497  if (_mesh.is_serial())
498  {
499  // Add with a default id in serial
500  outer_nodes[*on_it]=this->_mesh.add_point(p);
501  }
502  else
503  {
504  // Pick a unique id in parallel
505  Node & bnode = _mesh.node_ref(*on_it);
506  dof_id_type new_id = bnode.id() + old_max_node_id;
507  Node * new_node =
508  this->_mesh.add_point(p, new_id,
509  bnode.processor_id());
510 #ifdef LIBMESH_ENABLE_UNIQUE_ID
511  new_node->set_unique_id() = old_max_unique_id + bnode.id();
512 #endif
513  outer_nodes[*on_it] = new_node;
514  }
515  }
516 
517 
518 #ifdef DEBUG
519  // for verbose, remember n_elem
520  dof_id_type n_conventional_elem = this->_mesh.n_elem();
521 #endif
522 
523 
524  // build Elems based on boundary side type
525  for (auto & p : ofaces)
526  {
527  Elem & belem = this->_mesh.elem_ref(p.first);
528 
529  // build a full-ordered side element to get the base nodes
530  std::unique_ptr<Elem> side(belem.build_side_ptr(p.second));
531 
532  // create cell depending on side type, assign nodes,
533  // use braces to force scope.
534  bool is_higher_order_elem = false;
535 
536  Elem * el;
537  switch(side->type())
538  {
539  // 3D infinite elements
540  // TRIs
541  case TRI3:
542  el=new InfPrism6;
543  break;
544 
545  case TRI6:
546  el=new InfPrism12;
547  is_higher_order_elem = true;
548  break;
549 
550  // QUADs
551  case QUAD4:
552  el=new InfHex8;
553  break;
554 
555  case QUAD8:
556  el=new InfHex16;
557  is_higher_order_elem = true;
558  break;
559 
560  case QUAD9:
561  el=new InfHex18;
562 
563  // the method of assigning nodes (which follows below)
564  // omits in the case of QUAD9 the bubble node; therefore
565  // we assign these first by hand here.
566  el->set_node(16) = side->node_ptr(8);
567  el->set_node(17) = outer_nodes[side->node_id(8)];
568  is_higher_order_elem=true;
569  break;
570 
571  // 2D infinite elements
572  case EDGE2:
573  el=new InfQuad4;
574  break;
575 
576  case EDGE3:
577  el=new InfQuad6;
578  el->set_node(4) = side->node_ptr(2);
579  break;
580 
581  // 1D infinite elements not supported
582  default:
583  libMesh::out << "InfElemBuilder::build_inf_elem(Point, bool, bool, bool, bool): "
584  << "invalid face element "
585  << std::endl;
586  continue;
587  }
588 
589  const unsigned int n_base_vertices = side->n_vertices();
590 
591  // On a distributed mesh, manually assign unique ids to the new
592  // element, and make sure any RemoteElem neighbor links are set.
593  if (!_mesh.is_serial())
594  {
595  el->processor_id() = belem.processor_id();
596 
597  // We'd better not have elements with more than 6 sides
598  libmesh_assert_less_equal(el->n_sides(), 6);
599  el->set_id (belem.id() * 6 + p.second + old_max_elem_id);
600 
601 #ifdef LIBMESH_ENABLE_UNIQUE_ID
602  el->set_unique_id() = old_max_unique_id + old_max_node_id + belem.id();
603 #endif
604 
605  // If we have a remote neighbor on a boundary element side
606  if (belem.dim() > 1)
607  for (auto s : belem.side_index_range())
608  if (belem.neighbor_ptr(s) == remote_elem)
609  {
610  // Find any corresponding infinite element side
611  std::unique_ptr<const Elem> remote_side(belem.build_side_ptr(s));
612 
613  for (auto inf_s : el->side_index_range())
614  {
615  // The base side 0 shares all vertices but isn't
616  // remote
617  if (!inf_s)
618  continue;
619 
620  // But another side, one which shares enough
621  // vertices to show it's the same side, is.
622  unsigned int n_shared_vertices = 0;
623  for (unsigned int i = 0; i != n_base_vertices; ++i)
624  for (auto & node : remote_side->node_ref_range())
625  if (side->node_ptr(i) == &node &&
626  el->is_node_on_side(i,inf_s))
627  ++n_shared_vertices;
628 
629  if (n_shared_vertices + 1 >= belem.dim())
630  {
631  el->set_neighbor
632  (inf_s, const_cast<RemoteElem *>(remote_elem));
633  break;
634  }
635  }
636  }
637  }
638 
639  // assign vertices to the new infinite element
640  for (unsigned int i=0; i<n_base_vertices; i++)
641  {
642  el->set_node(i ) = side->node_ptr(i);
643  el->set_node(i+n_base_vertices) = outer_nodes[side->node_id(i)];
644  }
645 
646 
647  // when this is a higher order element,
648  // assign also the nodes in between
649  if (is_higher_order_elem)
650  {
651  // n_safe_base_nodes is the number of nodes in \p side
652  // that may be safely assigned using below for loop.
653  // Actually, n_safe_base_nodes is _identical_ with el->n_vertices(),
654  // since for QUAD9, the 9th node was already assigned above
655  const unsigned int n_safe_base_nodes = el->n_vertices();
656 
657  for (unsigned int i=n_base_vertices; i<n_safe_base_nodes; i++)
658  {
659  el->set_node(i+n_base_vertices) = side->node_ptr(i);
660  el->set_node(i+n_safe_base_nodes) =
661  outer_nodes[side->node_id(i)];
662  }
663  }
664 
665 
666  // add infinite element to mesh
667  this->_mesh.add_elem(el);
668  } // for
669 
670 
671 #ifdef DEBUG
673 
674  if (be_verbose)
675  libMesh::out << " added "
676  << this->_mesh.n_elem() - n_conventional_elem
677  << " infinite elements and "
678  << onodes.size()
679  << " nodes to the mesh"
680  << std::endl
681  << std::endl;
682 #endif
683 }
double abs(double a)
unique_id_type & set_unique_id()
Definition: dof_object.h:685
virtual unique_id_type parallel_max_unique_id() const =0
unsigned short int side
Definition: xdr_io.C:50
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=true)=0
virtual bool is_serial() const
Definition: mesh_base.h:154
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
virtual Elem * add_elem(Elem *e)=0
virtual dof_id_type max_elem_id() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:504
virtual void libmesh_assert_valid_parallel_ids() const
Definition: mesh_base.h:1007
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:434
virtual const Point & point(const dof_id_type i) const =0
virtual dof_id_type max_node_id() const =0
virtual dof_id_type n_elem() const =0
OStreamProxy out(std::cout)
uint8_t unique_id_type
Definition: id_types.h:79
uint8_t dof_id_type
Definition: id_types.h:64
const RemoteElem * remote_elem
Definition: remote_elem.C:57

Member Data Documentation

◆ _mesh

MeshBase& libMesh::InfElemBuilder::_mesh
private

Reference to the mesh we're building infinite elements for.

Definition at line 130 of file inf_elem_builder.h.

Referenced by build_inf_elem().


The documentation for this class was generated from the following files: