libMesh
Loading...
Searching...
No Matches
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.
 

Public Member Functions

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

Private Attributes

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

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
Reference to the mesh we're building infinite elements for.
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 43 of file inf_elem_builder.C.

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

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

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

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

References _mesh, libMesh::as_range(), 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(), and libMesh::TypeVector< T >::write_unformatted().

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

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

References _mesh, libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_node(), libMesh::MeshBase::add_point(), libMesh::Parallel::Communicator::broadcast(), libMesh::Elem::build(), libMesh::Node::build(), libMesh::Elem::build_side_ptr(), libMesh::ParallelObject::comm(), 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::libmesh_assert(), libMesh::MeshBase::libmesh_assert_valid_parallel_ids(), libMesh::make_range(), libMesh::Parallel::Communicator::max(), libMesh::MeshBase::max_elem_id(), libMesh::MeshBase::max_node_id(), libMesh::Parallel::Communicator::maxloc(), libMesh::MeshBase::n_elem(), libMesh::Elem::n_sides(), 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::MeshBase::query_node_ptr(), libMesh::Real, libMesh::remote_elem, libMesh::Elem::set_neighbor(), libMesh::Parallel::Communicator::set_union(), libMesh::Elem::side_index_range(), libMesh::TRI3, and libMesh::TRI6.

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(), build_inf_elem(), and build_inf_elem().


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