libMesh
Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
libMesh::InfElemBuilder Class Reference

This class is used to build infinite elements on top of an existing mesh. More...

#include <inf_elem_builder.h>

Public Types

typedef std::pair< bool, double > InfElemOriginValue
 Useful typedef. More...
 

Public Member Functions

 InfElemBuilder (MeshBase &mesh)
 Constructor. More...
 
const Point build_inf_elem (const bool be_verbose=false)
 Build infinite elements atop a volume-based mesh, determine origin automatically. More...
 
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)
 Build infinite elements atop a volume-based mesh. More...
 

Private Attributes

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

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
MeshBase & _mesh
Reference to the mesh we&#39;re building infinite elements for.

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(), main(), InfFERadialTest::testInfQuants(), InfFERadialTest::testInfQuants_numericDeriv(), InfFERadialTest::testRefinement(), InfFERadialTest::testSides(), and InfFERadialTest::testSingleOrder().

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 ();
67 
68  return origin;
69 }
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:558
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:710
const Point build_inf_elem(const bool be_verbose=false)
Build infinite elements atop a volume-based mesh, determine origin automatically. ...
OStreamProxy out
processor_id_type processor_id() const
MeshBase & _mesh
Reference to the mesh we&#39;re building infinite elements for.

◆ 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, libMesh::as_range(), build_inf_elem(), libMesh::Elem::build_side_ptr(), libMesh::MeshTools::create_bounding_box(), distance(), libMesh::MeshBase::elem_ref(), libMesh::MeshBase::node_ptr(), libMesh::out, libMesh::MeshBase::prepare_for_use(), libMesh::MeshBase::print_info(), and libMesh::TypeVector< T >::write_unformatted().

90 {
91  LOG_SCOPE("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 LIBMESH_DIM > 1
112  if (!origin_y.first)
113  origin(1) = auto_origin(1);
114 #endif
115 #if LIBMESH_DIM > 2
116  if (!origin_z.first)
117  origin(2) = auto_origin(2);
118 #endif
119 
120  if (be_verbose)
121  {
122  libMesh::out << " Origin for Infinite Elements:" << std::endl;
123 
124  if (!origin_x.first)
125  libMesh::out << " determined x-coordinate" << std::endl;
126  if (!origin_y.first)
127  libMesh::out << " determined y-coordinate" << std::endl;
128  if (!origin_z.first)
129  libMesh::out << " determined z-coordinate" << std::endl;
130 
131  libMesh::out << " coordinates: ";
132  origin.write_unformatted(libMesh::out);
133  libMesh::out << std::endl;
134  }
135  }
136 
137  else if (be_verbose)
138 
139  {
140  libMesh::out << " Origin for Infinite Elements:" << std::endl;
141  libMesh::out << " coordinates: ";
142  origin.write_unformatted(libMesh::out);
143  libMesh::out << std::endl;
144  }
145 
146 
147 
148  // Now that we have the origin, check if the user provided an \p
149  // inner_boundary_nodes. If so, we pass a std::set to the actual
150  // implementation of the build_inf_elem(), so that we can convert
151  // this to the Node * vector
152  if (inner_boundary_nodes != nullptr)
153  {
154  // note that the std::set that we will get
155  // from build_inf_elem() uses the index of
156  // the element in this->_elements vector,
157  // and the second entry is the side index
158  // for this element. Therefore, we do _not_
159  // need to renumber nodes and elements
160  // prior to building the infinite elements.
161  //
162  // However, note that this method here uses
163  // node id's... Do we need to renumber?
164 
165 
166  // Form the list of faces of elements which finally
167  // will tell us which nodes should receive boundary
168  // conditions (to form the std::vector<const Node *>)
169  std::set<std::pair<dof_id_type,
170  unsigned int>> inner_faces;
171 
172 
173  // build infinite elements
174  this->build_inf_elem(origin,
175  x_sym, y_sym, z_sym,
176  be_verbose,
177  &inner_faces);
178 
179  if (be_verbose)
180  {
181  this->_mesh.print_info();
182  libMesh::out << "Data pre-processing:" << std::endl
183  << " convert the <int,int> list to a Node * list..."
184  << std::endl;
185  }
186 
187  // First use a std::vector<dof_id_type> that holds
188  // the global node numbers. Then sort this vector,
189  // so that it can be made unique (no multiple occurrence
190  // of a node), and then finally insert the Node * in
191  // the vector inner_boundary_nodes.
192  //
193  // Reserve memory for the vector<> with
194  // 4 times the size of the number of elements in the
195  // std::set. This is a good bet for Quad4 face elements.
196  // For higher-order elements, this probably _has_ to lead
197  // to additional allocations...
198  // Practice has to show how this affects performance.
199  std::vector<dof_id_type> inner_boundary_node_numbers;
200  inner_boundary_node_numbers.reserve(4*inner_faces.size());
201 
202  // Now transform the set of pairs to a list of (possibly
203  // duplicate) global node numbers.
204  for (const auto & p : inner_faces)
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 (const Node & node : side->node_ref_range())
211  inner_boundary_node_numbers.push_back(node.id());
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  auto 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  for (const auto & dof : as_range(inner_boundary_node_numbers.begin(), unique_end))
239  {
240  const Node * node = this->_mesh.node_ptr(dof);
241  inner_boundary_nodes->push_back(node);
242  }
243 
244  if (be_verbose)
245  libMesh::out << " finished identifying " << unique_size
246  << " target nodes." << std::endl;
247  }
248 
249  else
250 
251  {
252  // There are no inner boundary nodes, so simply build the infinite elements
253  this->build_inf_elem(origin, x_sym, y_sym, z_sym, be_verbose);
254  }
255 
256  // when finished with building the Ifems,
257  // it remains to prepare the mesh for use:
258  // find neighbors again, partition (if needed)...
259  this->_mesh.prepare_for_use ();
260 
261  return origin;
262 }
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:558
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:710
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=false)=0
Real distance(const Point &p)
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition: mesh_base.C:1489
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
const Point build_inf_elem(const bool be_verbose=false)
Build infinite elements atop a volume-based mesh, determine origin automatically. ...
OStreamProxy out
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:618
virtual const Node * node_ptr(const dof_id_type i) const =0
MeshBase & _mesh
Reference to the mesh we&#39;re building infinite elements for.
uint8_t dof_id_type
Definition: id_types.h:67

◆ 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 273 of file inf_elem_builder.C.

References _mesh, std::abs(), libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_node(), libMesh::MeshBase::add_point(), libMesh::Node::build(), libMesh::Elem::build(), libMesh::Elem::build_side_ptr(), libMesh::Elem::dim(), libMesh::EDGE2, libMesh::EDGE3, libMesh::MeshBase::elem_ref(), libMesh::MeshBase::find_neighbors(), libMesh::DofObject::id(), libMesh::INFHEX16, libMesh::INFHEX18, libMesh::INFHEX8, libMesh::INFPRISM12, libMesh::INFPRISM6, libMesh::INFQUAD4, libMesh::INFQUAD6, 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::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::Elem::side_index_range(), libMesh::TRI3, and libMesh::TRI6.

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

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: