libMesh
Loading...
Searching...
No Matches
inf_elem_builder.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18#include "libmesh/libmesh_config.h"
19
20#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
21
22// C++ includes
23
24// Local includes
25#include "libmesh/inf_elem_builder.h"
26#include "libmesh/libmesh_logging.h"
27#include "libmesh/mesh_tools.h"
28#include "libmesh/face_inf_quad4.h"
29#include "libmesh/face_inf_quad6.h"
30#include "libmesh/cell_inf_prism6.h"
31#include "libmesh/cell_inf_prism12.h"
32#include "libmesh/cell_inf_hex8.h"
33#include "libmesh/cell_inf_hex16.h"
34#include "libmesh/cell_inf_hex18.h"
35#include "libmesh/mesh_base.h"
36#include "libmesh/remote_elem.h"
37
39
40namespace libMesh
41{
42
44{
45 // determine origin automatically,
46 // works only if the mesh has no symmetry planes.
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 << " ";
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}
72
73
74
75
76
77
78
79
80
81
82
83
85 const InfElemOriginValue & origin_y,
86 const InfElemOriginValue & origin_z,
87 const bool x_sym,
88 const bool y_sym,
89 const bool z_sym,
90 const bool be_verbose,
91 std::vector<const Node *> * inner_boundary_nodes)
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
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: ";
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: ";
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}
265
266
267
268
269
270
271
272
273
274// The actual implementation of building elements.
276 const bool x_sym,
277 const bool y_sym,
278 const bool z_sym,
279 const bool be_verbose,
280 std::set<std::pair<dof_id_type,
281 unsigned int>> * inner_faces)
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}
735
736} // namespace libMesh
737
738
739
740
741
742#endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
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
Defines a Cartesian bounding box by the two corner extremum.
processor_id_type processor_id() const
Definition dof_object.h:881
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition elem.h:2635
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
virtual unsigned short dim() const =0
virtual unsigned int n_sides() const =0
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2615
IntRange< unsigned short > side_index_range() const
Definition elem.h:2727
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
const Point build_inf_elem(const bool be_verbose=false)
Build infinite elements atop a volume-based mesh, determine origin automatically.
std::pair< bool, double > InfElemOriginValue
Useful typedef.
MeshBase & _mesh
Reference to the mesh we're building infinite elements for.
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 const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_elem() const =0
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
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 const Elem & elem_ref(const dof_id_type i) const
Definition mesh_base.h:788
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
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
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
A Node is like a Point, but with more information.
Definition node.h:55
static std::unique_ptr< Node > build(const Node &n)
Definition node.h:315
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
In parallel meshes where a ghost element has neighbors which do not exist on the local processor,...
Definition remote_elem.h:61
void write_unformatted(std::ostream &out_stream, const bool newline=true) const
Unformatted print to the stream out.
Definition type_vector.C:51
auto norm() const
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition mesh_tools.C:566
The libMesh namespace provides an interface to certain functionality in the library.
uint8_t unique_id_type
Definition id_types.h:86
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
libmesh_assert(ctx)
OStreamProxy out
const RemoteElem * remote_elem
Definition remote_elem.C:57
uint8_t dof_id_type
Definition id_types.h:67
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