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=libmesh_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=libmesh_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

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

Useful typedef

Definition at line 65 of file inf_elem_builder.h.

Constructor & Destructor Documentation

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

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:329
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Definition: mesh_base.C:176
const Point build_inf_elem(const bool be_verbose=false)
OStreamProxy out(std::cout)
processor_id_type processor_id() const
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 = libmesh_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_nullptr, 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 != libmesh_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 NULL-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:329
unsigned short int side
Definition: xdr_io.C:49
const class libmesh_nullptr_t libmesh_nullptr
virtual const Node * node_ptr(const dof_id_type i) const =0
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:176
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:491
const Point build_inf_elem(const bool be_verbose=false)
OStreamProxy out(std::cout)
void print_info(std::ostream &os=libMesh::out) const
Definition: mesh_base.C:450
uint8_t dof_id_type
Definition: id_types.h:64
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 = libmesh_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_nullptr, 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) == libmesh_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) == libmesh_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  std::set<std::pair<dof_id_type,unsigned int>>::iterator face_it = faces.begin();
415  unsigned int facesfound=0;
416  while (face_it != faces.end()) {
417 
418  std::pair<dof_id_type, unsigned int> p;
419  p = *face_it;
420 
421  // This has to be a full-ordered side element,
422  // since we need the correct n_nodes,
423  std::unique_ptr<Elem> side(this->_mesh.elem_ref(p.first).build_side_ptr(p.second));
424 
425  bool found=false;
426  for (unsigned int sn=0; sn<side->n_nodes(); sn++)
427  if (onodes.count(side->node_id(sn)))
428  {
429  found=true;
430  break;
431  }
432 
433 
434  // If a new oface is found, include its nodes in onodes
435  if (found)
436  {
437  for (unsigned int sn=0; sn<side->n_nodes(); sn++)
438  onodes.insert(side->node_id(sn));
439 
440  ofaces.insert(p);
441  ++face_it; // iteration is done here
442  faces.erase(p);
443 
444  facesfound++;
445  }
446 
447  else
448  ++face_it; // iteration is done here
449 
450  // If at least one new oface was found in this cycle,
451  // do another search cycle.
452  if (facesfound>0 && face_it == faces.end())
453  {
454  facesfound = 0;
455  face_it = faces.begin();
456  }
457 
458  }
459  }
460 
461 
462 #ifdef DEBUG
463  if (be_verbose)
464  libMesh::out << " found "
465  << faces.size()
466  << " inner and "
467  << ofaces.size()
468  << " outer boundary faces"
469  << std::endl;
470 #endif
471 
472  // When the user provided a non-null pointer to
473  // inner_faces, that implies he wants to have
474  // this std::set. For now, simply copy the data.
475  if (inner_faces != libmesh_nullptr)
476  *inner_faces = faces;
477 
478  // free memory, clear our local variable, no need
479  // for it any more.
480  faces.clear();
481 
482 
483  // outer_nodes maps onodes to their duplicates
484  std::map<dof_id_type, Node *> outer_nodes;
485 
486  // We may need to pick our own object ids in parallel
487  dof_id_type old_max_node_id = _mesh.max_node_id();
488  dof_id_type old_max_elem_id = _mesh.max_elem_id();
489 
490  // Likewise with our unique_ids
491 #ifdef LIBMESH_ENABLE_UNIQUE_ID
492  dof_id_type old_max_unique_id = _mesh.parallel_max_unique_id();
493 #endif
494 
495  // for each boundary node, add an outer_node with
496  // double distance from origin.
497  std::set<dof_id_type>::iterator on_it = onodes.begin();
498  for ( ; on_it != onodes.end(); ++on_it)
499  {
500  Point p = (Point(this->_mesh.point(*on_it)) * 2) - origin;
501  if (_mesh.is_serial())
502  {
503  // Add with a default id in serial
504  outer_nodes[*on_it]=this->_mesh.add_point(p);
505  }
506  else
507  {
508  // Pick a unique id in parallel
509  Node & bnode = _mesh.node_ref(*on_it);
510  dof_id_type new_id = bnode.id() + old_max_node_id;
511  Node * new_node =
512  this->_mesh.add_point(p, new_id,
513  bnode.processor_id());
514 #ifdef LIBMESH_ENABLE_UNIQUE_ID
515  new_node->set_unique_id() = old_max_unique_id + bnode.id();
516 #endif
517  outer_nodes[*on_it] = new_node;
518  }
519  }
520 
521 
522 #ifdef DEBUG
523  // for verbose, remember n_elem
524  dof_id_type n_conventional_elem = this->_mesh.n_elem();
525 #endif
526 
527 
528  // build Elems based on boundary side type
529  for (auto & p : ofaces)
530  {
531  Elem & belem = this->_mesh.elem_ref(p.first);
532 
533  // build a full-ordered side element to get the base nodes
534  std::unique_ptr<Elem> side(belem.build_side_ptr(p.second));
535 
536  // create cell depending on side type, assign nodes,
537  // use braces to force scope.
538  bool is_higher_order_elem = false;
539 
540  Elem * el;
541  switch(side->type())
542  {
543  // 3D infinite elements
544  // TRIs
545  case TRI3:
546  el=new InfPrism6;
547  break;
548 
549  case TRI6:
550  el=new InfPrism12;
551  is_higher_order_elem = true;
552  break;
553 
554  // QUADs
555  case QUAD4:
556  el=new InfHex8;
557  break;
558 
559  case QUAD8:
560  el=new InfHex16;
561  is_higher_order_elem = true;
562  break;
563 
564  case QUAD9:
565  el=new InfHex18;
566 
567  // the method of assigning nodes (which follows below)
568  // omits in the case of QUAD9 the bubble node; therefore
569  // we assign these first by hand here.
570  el->set_node(16) = side->node_ptr(8);
571  el->set_node(17) = outer_nodes[side->node_id(8)];
572  is_higher_order_elem=true;
573  break;
574 
575  // 2D infinite elements
576  case EDGE2:
577  el=new InfQuad4;
578  break;
579 
580  case EDGE3:
581  el=new InfQuad6;
582  el->set_node(4) = side->node_ptr(2);
583  break;
584 
585  // 1D infinite elements not supported
586  default:
587  libMesh::out << "InfElemBuilder::build_inf_elem(Point, bool, bool, bool, bool): "
588  << "invalid face element "
589  << std::endl;
590  continue;
591  }
592 
593  const unsigned int n_base_vertices = side->n_vertices();
594 
595  // On a distributed mesh, manually assign unique ids to the new
596  // element, and make sure any RemoteElem neighbor links are set.
597  if (!_mesh.is_serial())
598  {
599  el->processor_id() = belem.processor_id();
600 
601  // We'd better not have elements with more than 6 sides
602  libmesh_assert_less_equal(el->n_sides(), 6);
603  el->set_id (belem.id() * 6 + p.second + old_max_elem_id);
604 
605 #ifdef LIBMESH_ENABLE_UNIQUE_ID
606  el->set_unique_id() = old_max_unique_id + old_max_node_id + belem.id();
607 #endif
608 
609  // If we have a remote neighbor on a boundary element side
610  if (belem.dim() > 1)
611  for (auto s : belem.side_index_range())
612  if (belem.neighbor_ptr(s) == remote_elem)
613  {
614  // Find any corresponding infinite element side
615  std::unique_ptr<const Elem> remote_side(belem.build_side_ptr(s));
616 
617  for (auto inf_s : el->side_index_range())
618  {
619  // The base side 0 shares all vertices but isn't
620  // remote
621  if (!inf_s)
622  continue;
623 
624  // But another side, one which shares enough
625  // vertices to show it's the same side, is.
626  unsigned int n_shared_vertices = 0;
627  for (unsigned int i = 0; i != n_base_vertices; ++i)
628  for (auto & node : remote_side->node_ref_range())
629  if (side->node_ptr(i) == &node &&
630  el->is_node_on_side(i,inf_s))
631  ++n_shared_vertices;
632 
633  if (n_shared_vertices + 1 >= belem.dim())
634  {
635  el->set_neighbor
636  (inf_s, const_cast<RemoteElem *>(remote_elem));
637  break;
638  }
639  }
640  }
641  }
642 
643  // assign vertices to the new infinite element
644  for (unsigned int i=0; i<n_base_vertices; i++)
645  {
646  el->set_node(i ) = side->node_ptr(i);
647  el->set_node(i+n_base_vertices) = outer_nodes[side->node_id(i)];
648  }
649 
650 
651  // when this is a higher order element,
652  // assign also the nodes in between
653  if (is_higher_order_elem)
654  {
655  // n_safe_base_nodes is the number of nodes in \p side
656  // that may be safely assigned using below for loop.
657  // Actually, n_safe_base_nodes is _identical_ with el->n_vertices(),
658  // since for QUAD9, the 9th node was already assigned above
659  const unsigned int n_safe_base_nodes = el->n_vertices();
660 
661  for (unsigned int i=n_base_vertices; i<n_safe_base_nodes; i++)
662  {
663  el->set_node(i+n_base_vertices) = side->node_ptr(i);
664  el->set_node(i+n_safe_base_nodes) =
665  outer_nodes[side->node_id(i)];
666  }
667  }
668 
669 
670  // add infinite element to mesh
671  this->_mesh.add_elem(el);
672  } // for
673 
674 
675 #ifdef DEBUG
677 
678  if (be_verbose)
679  libMesh::out << " added "
680  << this->_mesh.n_elem() - n_conventional_elem
681  << " infinite elements and "
682  << onodes.size()
683  << " nodes to the mesh"
684  << std::endl
685  << std::endl;
686 #endif
687 }
virtual unique_id_type parallel_max_unique_id() const =0
double abs(double a)
unique_id_type & set_unique_id()
Definition: dof_object.h:662
virtual void libmesh_assert_valid_parallel_ids() const
Definition: mesh_base.h:966
virtual bool is_serial() const
Definition: mesh_base.h:141
virtual const Point & point(const dof_id_type i) const =0
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:421
unsigned short int side
Definition: xdr_io.C:49
virtual dof_id_type max_node_id() const =0
const class libmesh_nullptr_t libmesh_nullptr
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 dof_id_type max_elem_id() const =0
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 const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:491
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual dof_id_type n_elem() const =0
OStreamProxy out(std::cout)
uint8_t dof_id_type
Definition: id_types.h:64
const RemoteElem * remote_elem
Definition: remote_elem.C:57

Member Data Documentation

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: