libMesh
boundary_info.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 
19 
20 // C++ includes
21 #include <iterator> // std::distance
22 
23 // Local includes
24 #include "libmesh/libmesh_config.h"
25 #include "libmesh/libmesh_logging.h"
26 #include "libmesh/boundary_info.h"
27 #include "libmesh/distributed_mesh.h"
28 #include "libmesh/elem.h"
29 #include "libmesh/mesh_communication.h"
30 #include "libmesh/mesh_serializer.h"
31 #include "libmesh/parallel.h"
32 #include "libmesh/partitioner.h"
33 #include "libmesh/remote_elem.h"
34 #include "libmesh/unstructured_mesh.h"
35 
36 namespace
37 {
38 
39 // Templated helper function for removing a subset of keys from a
40 // multimap that further satisfy a given predicate on the
41 // corresponding values.
42 template <class Key, class T, class Pred>
43 void erase_if(std::multimap<Key,T> & map, Key k, Pred pred)
44 {
45  auto rng = map.equal_range(k);
46  auto it = rng.first;
47  while (it != rng.second)
48  {
49  if (pred(it->second))
50  it = map.erase(it);
51  else
52  ++it;
53  }
54 }
55 
56 // Similar to the helper function above but doesn't take a key,
57 // instead it applies the predicate to every value in the map.
58 template <class Key, class T, class Pred>
59 void erase_if(std::multimap<Key,T> & map, Pred pred)
60 {
61  auto it = map.begin();
62  while (it != map.end())
63  {
64  if (pred(it->second))
65  it = map.erase(it);
66  else
67  ++it;
68  }
69 }
70 
71 }
72 
73 namespace libMesh
74 {
75 
76 
77 
78 //------------------------------------------------------
79 // BoundaryInfo static member initializations
81 
82 
83 
84 //------------------------------------------------------
85 // BoundaryInfo functions
87  ParallelObject(m.comm()),
88  _mesh (m)
89 {
90 }
91 
92 BoundaryInfo & BoundaryInfo::operator=(const BoundaryInfo & other_boundary_info)
93 {
94  // Overwrite any preexisting boundary info
95  this->clear();
96 
107  // Copy node boundary info
108  for (const auto & pr : other_boundary_info._boundary_node_id)
109  _boundary_node_id.insert(std::make_pair(_mesh.node_ptr(pr.first->id()),
110  pr.second));
111 
112  // Copy edge boundary info
113  for (const auto & pr : other_boundary_info._boundary_edge_id)
114  _boundary_edge_id.insert(std::make_pair(_mesh.elem_ptr(pr.first->id()),
115  pr.second));
116 
117  // Copy shellface boundary info
118  for (const auto & pr : other_boundary_info._boundary_shellface_id)
119  _boundary_shellface_id.insert(std::make_pair(_mesh.elem_ptr(pr.first->id()),
120  pr.second));
121 
122  // Copy side boundary info
123  for (const auto & pr : other_boundary_info._boundary_side_id)
124  _boundary_side_id.insert(std::make_pair(_mesh.elem_ptr(pr.first->id()),
125  pr.second));
126 
127  _boundary_ids = other_boundary_info._boundary_ids;
128  _side_boundary_ids = other_boundary_info._side_boundary_ids;
129  _node_boundary_ids = other_boundary_info._node_boundary_ids;
130  _edge_boundary_ids = other_boundary_info._edge_boundary_ids;
131  _shellface_boundary_ids = other_boundary_info._shellface_boundary_ids;
132 
133  return *this;
134 }
135 
136 
138 {
139  this->clear();
140 }
141 
142 
143 
145 {
146  _boundary_node_id.clear();
147  _boundary_side_id.clear();
148  _boundary_edge_id.clear();
149  _boundary_shellface_id.clear();
150  _boundary_ids.clear();
151  _side_boundary_ids.clear();
152  _node_boundary_ids.clear();
153  _edge_boundary_ids.clear();
154  _shellface_boundary_ids.clear();
155 }
156 
157 
158 
160 {
161  // Clear the old caches
162  _boundary_ids.clear();
163  _side_boundary_ids.clear();
164  _node_boundary_ids.clear();
165  _edge_boundary_ids.clear();
166  _shellface_boundary_ids.clear();
167 
168  // Loop over id maps to regenerate each set.
169  for (const auto & pr : _boundary_node_id)
170  {
171  const boundary_id_type id = pr.second;
172  _boundary_ids.insert(id);
173  _node_boundary_ids.insert(id);
174  }
175 
176  for (const auto & pr : _boundary_edge_id)
177  {
178  const boundary_id_type id = pr.second.second;
179  _boundary_ids.insert(id);
180  _edge_boundary_ids.insert(id);
181  }
182 
183  for (const auto & pr : _boundary_side_id)
184  {
185  const boundary_id_type id = pr.second.second;
186  _boundary_ids.insert(id);
187  _side_boundary_ids.insert(id);
188  }
189 
190  for (const auto & pr : _boundary_shellface_id)
191  {
192  const boundary_id_type id = pr.second.second;
193  _boundary_ids.insert(id);
194  _shellface_boundary_ids.insert(id);
195  }
196 }
197 
198 
199 
200 void BoundaryInfo::sync (UnstructuredMesh & boundary_mesh)
201 {
202  std::set<boundary_id_type> request_boundary_ids(_boundary_ids);
203  request_boundary_ids.insert(invalid_id);
204  if (!_mesh.is_serial())
205  this->comm().set_union(request_boundary_ids);
206 
207  this->sync(request_boundary_ids,
208  boundary_mesh);
209 }
210 
211 
212 
213 void BoundaryInfo::sync (const std::set<boundary_id_type> & requested_boundary_ids,
214  UnstructuredMesh & boundary_mesh)
215 {
216  // Call the 3 argument version of this function with a dummy value for the third set.
217  std::set<subdomain_id_type> subdomains_relative_to;
218  subdomains_relative_to.insert(Elem::invalid_subdomain_id);
219 
220  this->sync(requested_boundary_ids,
221  boundary_mesh,
222  subdomains_relative_to);
223 }
224 
225 
226 
227 void BoundaryInfo::sync (const std::set<boundary_id_type> & requested_boundary_ids,
228  UnstructuredMesh & boundary_mesh,
229  const std::set<subdomain_id_type> & subdomains_relative_to)
230 {
231  LOG_SCOPE("sync()", "BoundaryInfo");
232 
233  boundary_mesh.clear();
234 
240  if (!_mesh.is_serial())
241  boundary_mesh.delete_remote_elements();
242 
249  MeshSerializer serializer
250  (const_cast<MeshBase &>(_mesh), boundary_mesh.is_serial());
251 
256  boundary_mesh.set_n_partitions() = _mesh.n_partitions();
257 
258  std::map<dof_id_type, dof_id_type> node_id_map;
259  std::map<std::pair<dof_id_type, unsigned char>, dof_id_type> side_id_map;
260 
261  this->_find_id_maps(requested_boundary_ids, 0, &node_id_map, 0, &side_id_map, subdomains_relative_to);
262 
263  // Let's add all the boundary nodes we found to the boundary mesh
264  for (const auto & node : _mesh.node_ptr_range())
265  {
266  dof_id_type node_id = node->id();
267  if (node_id_map.count(node_id))
268  {
269  boundary_mesh.add_point(*node, node_id_map[node_id], node->processor_id());
270 
271  // Copy over all the node's boundary IDs to boundary_mesh
272  std::vector<boundary_id_type> node_boundary_ids;
273  this->boundary_ids(node, node_boundary_ids);
274  for (const auto & node_bid : node_boundary_ids)
275  boundary_mesh.get_boundary_info().add_node(node_id_map[node_id], node_bid);
276  }
277  }
278 
279  // Let's add the elements
280  this->add_elements (requested_boundary_ids, boundary_mesh, subdomains_relative_to);
281 
282  // The new elements are currently using the interior mesh's nodes;
283  // we want them to use the boundary mesh's nodes instead.
284 
285  // This side's Node pointers still point to the nodes of the original mesh.
286  // We need to re-point them to the boundary mesh's nodes! Since we copied *ALL* of
287  // the original mesh's nodes over, we should be guaranteed to have the same ordering.
288  for (auto & new_elem : boundary_mesh.element_ptr_range())
289  {
290  for (auto nn : new_elem->node_index_range())
291  {
292  // Get the correct node pointer, based on the id()
293  Node * new_node =
294  boundary_mesh.node_ptr(node_id_map[new_elem->node_id(nn)]);
295 
296  // sanity check: be sure that the new Node exists and its
297  // global id really matches
298  libmesh_assert (new_node);
299  libmesh_assert_equal_to (new_node->id(),
300  node_id_map[new_elem->node_id(nn)]);
301 
302  // Assign the new node pointer
303  new_elem->set_node(nn) = new_node;
304  }
305  }
306 
307  // Don't repartition this mesh; we want it to stay in sync with the
308  // interior partitioning.
309  boundary_mesh.partitioner().reset(nullptr);
310 
311  // Make boundary_mesh nodes and elements contiguous
312  boundary_mesh.prepare_for_use(/*skip_renumber =*/ false);
313 
314  // and finally distribute element partitioning to the nodes
316 }
317 
318 
320  std::map<dof_id_type, dof_id_type> & node_id_map,
321  std::map<dof_id_type, unsigned char> & side_id_map,
322  Real tolerance)
323 {
324  LOG_SCOPE("get_side_and_node_maps()", "BoundaryInfo");
325 
326  node_id_map.clear();
327  side_id_map.clear();
328 
329  // Pull objects out of the loop to reduce heap operations
330  std::unique_ptr<const Elem> interior_parent_side;
331 
332  for (const auto & boundary_elem : boundary_mesh.active_element_ptr_range())
333  {
334  const Elem * interior_parent = boundary_elem->interior_parent();
335 
336  // Find out which side of interior_parent boundary_elem corresponds to.
337  // Use centroid comparison as a way to check.
338  unsigned char interior_parent_side_index = 0;
339  bool found_matching_sides = false;
340  for (auto side : interior_parent->side_index_range())
341  {
342  interior_parent->build_side_ptr(interior_parent_side, side);
343  Real centroid_distance = (boundary_elem->centroid() - interior_parent_side->centroid()).norm();
344 
345  if (centroid_distance < (tolerance * boundary_elem->hmin()))
346  {
347  interior_parent_side_index = cast_int<unsigned char>(side);
348  found_matching_sides = true;
349  break;
350  }
351  }
352 
353  if (!found_matching_sides)
354  libmesh_error_msg("No matching side found within the specified tolerance");
355 
356  side_id_map[boundary_elem->id()] = interior_parent_side_index;
357 
358  for (auto local_node_index : boundary_elem->node_index_range())
359  {
360  dof_id_type boundary_node_id = boundary_elem->node_id(local_node_index);
361  dof_id_type interior_node_id = interior_parent_side->node_id(local_node_index);
362 
363  node_id_map[interior_node_id] = boundary_node_id;
364  }
365  }
366 }
367 
368 
369 
370 void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_boundary_ids,
371  UnstructuredMesh & boundary_mesh)
372 {
373  // Call the 3 argument version of this function with a dummy value for the third arg.
374  std::set<subdomain_id_type> subdomains_relative_to;
375  subdomains_relative_to.insert(Elem::invalid_subdomain_id);
376 
377  this->add_elements(requested_boundary_ids,
378  boundary_mesh,
379  subdomains_relative_to);
380 }
381 
382 
383 
384 void BoundaryInfo::add_elements(const std::set<boundary_id_type> & requested_boundary_ids,
385  UnstructuredMesh & boundary_mesh,
386  const std::set<subdomain_id_type> & subdomains_relative_to)
387 {
388  LOG_SCOPE("add_elements()", "BoundaryInfo");
389 
390  // We're not prepared to mix serial and distributed meshes in this
391  // method, so make sure they match from the start.
392  libmesh_assert_equal_to(_mesh.is_serial(),
393  boundary_mesh.is_serial());
394 
395  std::map<std::pair<dof_id_type, unsigned char>, dof_id_type> side_id_map;
396  this->_find_id_maps(requested_boundary_ids,
397  0,
398  nullptr,
399  boundary_mesh.max_elem_id(),
400  &side_id_map,
401  subdomains_relative_to);
402 
403  // We have to add sides *outside* any element loop, because if
404  // boundary_mesh and _mesh are the same then those additions can
405  // invalidate our element iterators. So we just use the element
406  // loop to make a list of sides to add.
407  typedef std::vector<std::pair<dof_id_type, unsigned char>>
408  side_container;
409  side_container sides_to_add;
410 
411  for (const auto & elem : _mesh.element_ptr_range())
412  {
413  // If the subdomains_relative_to container has the
414  // invalid_subdomain_id, we fall back on the "old" behavior of
415  // adding sides regardless of this Elem's subdomain. Otherwise,
416  // if the subdomains_relative_to container doesn't contain the
417  // current Elem's subdomain_id(), we won't add any sides from
418  // it.
419  if (!subdomains_relative_to.count(Elem::invalid_subdomain_id) &&
420  !subdomains_relative_to.count(elem->subdomain_id()))
421  continue;
422 
423  // Get the top-level parent for this element
424  const Elem * top_parent = elem->top_parent();
425 
426  // Find all the boundary side ids for this Elem.
427  auto bounds = _boundary_side_id.equal_range(top_parent);
428 
429  for (auto s : elem->side_index_range())
430  {
431  bool add_this_side = false;
432  boundary_id_type this_bcid = invalid_id;
433 
434  for (const auto & pr : as_range(bounds))
435  {
436  this_bcid = pr.second.second;
437 
438  // if this side is flagged with a boundary condition
439  // and the user wants this id
440  if ((pr.second.first == s) &&
441  (requested_boundary_ids.count(this_bcid)))
442  {
443  add_this_side = true;
444  break;
445  }
446  }
447 
448  // We may still want to add this side if the user called
449  // sync() with no requested_boundary_ids. This corresponds
450  // to the "old" style of calling sync() in which the entire
451  // boundary was copied to the BoundaryMesh, and handles the
452  // case where elements on the geometric boundary are not in
453  // any sidesets.
454  if (bounds.first == bounds.second &&
455  requested_boundary_ids.count(invalid_id) &&
456  elem->neighbor_ptr(s) == nullptr)
457  add_this_side = true;
458 
459  if (add_this_side)
460  sides_to_add.push_back(std::make_pair(elem->id(), s));
461  }
462  }
463 
464 #ifdef LIBMESH_ENABLE_UNIQUE_ID
465  unique_id_type old_max_unique_id = boundary_mesh.parallel_max_unique_id();
466 #endif
467 
468  for (const auto & pr : sides_to_add)
469  {
470  const dof_id_type elem_id = pr.first;
471  const unsigned char s = pr.second;
472  Elem * elem = _mesh.elem_ptr(elem_id);
473 
474  // Build the side - do not use a "proxy" element here:
475  // This will be going into the boundary_mesh and needs to
476  // stand on its own.
477  std::unique_ptr<Elem> side (elem->build_side_ptr(s, false));
478 
479  side->processor_id() = elem->processor_id();
480 
481  const std::pair<dof_id_type, unsigned char> side_pair(elem_id, s);
482 
483  libmesh_assert(side_id_map.count(side_pair));
484 
485  const dof_id_type new_side_id = side_id_map[side_pair];
486 
487  side->set_id(new_side_id);
488 
489 #ifdef LIBMESH_ENABLE_UNIQUE_ID
490  side->set_unique_id() = old_max_unique_id + new_side_id;
491 #endif
492 
493  // Add the side
494  Elem * new_elem = boundary_mesh.add_elem(side.release());
495 
496 #ifdef LIBMESH_ENABLE_AMR
497  // Set parent links
498  if (elem->parent())
499  {
500  const std::pair<dof_id_type, unsigned char> parent_side_pair(elem->parent()->id(), s);
501 
502  libmesh_assert(side_id_map.count(parent_side_pair));
503 
504  Elem * side_parent = boundary_mesh.elem_ptr(side_id_map[parent_side_pair]);
505 
506  libmesh_assert(side_parent);
507 
508  new_elem->set_parent(side_parent);
509 
510  side_parent->set_refinement_flag(Elem::INACTIVE);
511 
512  // Figuring out which child we are of our parent
513  // is a trick. Due to libMesh child numbering
514  // conventions, if we are an element on a vertex,
515  // then we share that vertex with our parent, with
516  // the same local index.
517  bool found_child = false;
518  for (auto v : IntRange<unsigned int>(0, new_elem->n_vertices()))
519  if (new_elem->node_ptr(v) == side_parent->node_ptr(v))
520  {
521  side_parent->add_child(new_elem, v);
522  found_child = true;
523  }
524 
525  // If we don't share any vertex with our parent,
526  // then we're the fourth child (index 3) of a
527  // triangle.
528  if (!found_child)
529  {
530  libmesh_assert_equal_to (new_elem->n_vertices(), 3);
531  side_parent->add_child(new_elem, 3);
532  }
533  }
534 #endif
535 
536  new_elem->set_interior_parent (elem);
537 
538  // On non-local elements on DistributedMesh we might have
539  // RemoteElem neighbor links to construct
540  if (!_mesh.is_serial() &&
541  (elem->processor_id() != this->processor_id()))
542  {
543  const unsigned short n_nodes = elem->n_nodes();
544 
545  const unsigned short bdy_n_sides = new_elem->n_sides();
546  const unsigned short bdy_n_nodes = new_elem->n_nodes();
547 
548  // Check every interior side for a RemoteElem
549  for (auto interior_side : elem->side_index_range())
550  {
551  // Might this interior side have a RemoteElem that
552  // needs a corresponding Remote on a boundary side?
553  if (elem->neighbor_ptr(interior_side) != remote_elem)
554  continue;
555 
556  // Which boundary side?
557  for (unsigned short boundary_side = 0;
558  boundary_side != bdy_n_sides; ++boundary_side)
559  {
560  // Look for matching node points. This is safe in
561  // *this* context.
562  bool found_all_nodes = true;
563  for (unsigned short boundary_node = 0;
564  boundary_node != bdy_n_nodes; ++boundary_node)
565  {
566  if (!new_elem->is_node_on_side(boundary_node,
567  boundary_side))
568  continue;
569 
570  bool found_this_node = false;
571  for (unsigned short interior_node = 0;
572  interior_node != n_nodes; ++interior_node)
573  {
574  if (!elem->is_node_on_side(interior_node,
575  interior_side))
576  continue;
577 
578  if (new_elem->point(boundary_node) ==
579  elem->point(interior_node))
580  {
581  found_this_node = true;
582  break;
583  }
584  }
585  if (!found_this_node)
586  {
587  found_all_nodes = false;
588  break;
589  }
590  }
591 
592  if (found_all_nodes)
593  {
594  new_elem->set_neighbor
595  (boundary_side,
596  const_cast<RemoteElem *>(remote_elem));
597  break;
598  }
599  }
600  }
601  }
602  }
603 
604  // We haven't been bothering to keep unique ids consistent on ghost
605  // elements
606  if (!boundary_mesh.is_serial())
608 
609  // Make sure we didn't add ids inconsistently
610 #ifdef DEBUG
611 # ifdef LIBMESH_HAVE_RTTI
612  DistributedMesh * parmesh = dynamic_cast<DistributedMesh *>(&boundary_mesh);
613  if (parmesh)
615 # endif
616 #endif
617 }
618 
619 
620 
622  const boundary_id_type id)
623 {
624  const Node * node_ptr = _mesh.query_node_ptr(node_id);
625 
626  // The user could easily ask for an invalid node id, so let's throw
627  // an easy-to-understand error message when this happens.
628  if (!node_ptr)
629  libmesh_error_msg("BoundaryInfo::add_node(): Could not retrieve pointer for node " << node_id << ", no boundary id was added.");
630 
631  this->add_node (node_ptr, id);
632 }
633 
634 
635 
636 void BoundaryInfo::add_node(const Node * node,
637  const boundary_id_type id)
638 {
639  if (id == invalid_id)
640  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
641  << invalid_id \
642  << "\n That is reserved for internal use.");
643 
644  // Don't add the same ID twice
645  for (const auto & pr : as_range(_boundary_node_id.equal_range(node)))
646  if (pr.second == id)
647  return;
648 
649  _boundary_node_id.insert(std::make_pair(node, id));
650  _boundary_ids.insert(id);
651  _node_boundary_ids.insert(id); // Also add this ID to the set of node boundary IDs
652 }
653 
654 
655 
656 void BoundaryInfo::add_node(const Node * node,
657  const std::vector<boundary_id_type> & ids)
658 {
659  if (ids.empty())
660  return;
661 
662  libmesh_assert(node);
663 
664  // Don't add the same ID twice
665  auto bounds = _boundary_node_id.equal_range(node);
666 
667  // The entries in the ids vector may be non-unique. If we expected
668  // *lots* of ids, it might be fastest to construct a std::set from
669  // the entries, but for a small number of entries, which is more
670  // typical, it is probably faster to copy the vector and do sort+unique.
671  // http://stackoverflow.com/questions/1041620/whats-the-most-efficient-way-to-erase-duplicates-and-sort-a-vector
672  std::vector<boundary_id_type> unique_ids(ids.begin(), ids.end());
673  std::sort(unique_ids.begin(), unique_ids.end());
674  std::vector<boundary_id_type>::iterator new_end =
675  std::unique(unique_ids.begin(), unique_ids.end());
676 
677  for (auto & id : as_range(unique_ids.begin(), new_end))
678  {
679  if (id == invalid_id)
680  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
681  << invalid_id \
682  << "\n That is reserved for internal use.");
683 
684  bool already_inserted = false;
685  for (const auto & pr : as_range(bounds))
686  if (pr.second == id)
687  {
688  already_inserted = true;
689  break;
690  }
691  if (already_inserted)
692  continue;
693 
694  _boundary_node_id.insert(std::make_pair(node,id));
695  _boundary_ids.insert(id);
696  _node_boundary_ids.insert(id); // Also add this ID to the set of node boundary IDs
697  }
698 }
699 
700 
701 
703 {
704  _boundary_node_id.clear();
705 }
706 
708  const unsigned short int edge,
709  const boundary_id_type id)
710 {
711  this->add_edge (_mesh.elem_ptr(e), edge, id);
712 }
713 
714 
715 
716 void BoundaryInfo::add_edge(const Elem * elem,
717  const unsigned short int edge,
718  const boundary_id_type id)
719 {
720  libmesh_assert(elem);
721 
722  // Only add BCs for level-0 elements.
723  libmesh_assert_equal_to (elem->level(), 0);
724 
725  if (id == invalid_id)
726  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
727  << invalid_id \
728  << "\n That is reserved for internal use.");
729 
730  // Don't add the same ID twice
731  for (const auto & pr : as_range(_boundary_edge_id.equal_range(elem)))
732  if (pr.second.first == edge &&
733  pr.second.second == id)
734  return;
735 
736  _boundary_edge_id.insert(std::make_pair(elem, std::make_pair(edge, id)));
737  _boundary_ids.insert(id);
738  _edge_boundary_ids.insert(id); // Also add this ID to the set of edge boundary IDs
739 }
740 
741 
742 
743 void BoundaryInfo::add_edge(const Elem * elem,
744  const unsigned short int edge,
745  const std::vector<boundary_id_type> & ids)
746 {
747  if (ids.empty())
748  return;
749 
750  libmesh_assert(elem);
751 
752  // Only add BCs for level-0 elements.
753  libmesh_assert_equal_to (elem->level(), 0);
754 
755  // Don't add the same ID twice
756  auto bounds = _boundary_edge_id.equal_range(elem);
757 
758  // The entries in the ids vector may be non-unique. If we expected
759  // *lots* of ids, it might be fastest to construct a std::set from
760  // the entries, but for a small number of entries, which is more
761  // typical, it is probably faster to copy the vector and do sort+unique.
762  // http://stackoverflow.com/questions/1041620/whats-the-most-efficient-way-to-erase-duplicates-and-sort-a-vector
763  std::vector<boundary_id_type> unique_ids(ids.begin(), ids.end());
764  std::sort(unique_ids.begin(), unique_ids.end());
765  std::vector<boundary_id_type>::iterator new_end =
766  std::unique(unique_ids.begin(), unique_ids.end());
767 
768  for (auto & id : as_range(unique_ids.begin(), new_end))
769  {
770  if (id == invalid_id)
771  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
772  << invalid_id \
773  << "\n That is reserved for internal use.");
774 
775  bool already_inserted = false;
776  for (const auto & pr : as_range(bounds))
777  if (pr.second.first == edge &&
778  pr.second.second == id)
779  {
780  already_inserted = true;
781  break;
782  }
783  if (already_inserted)
784  continue;
785 
786  _boundary_edge_id.insert(std::make_pair(elem, std::make_pair(edge, id)));
787  _boundary_ids.insert(id);
788  _edge_boundary_ids.insert(id); // Also add this ID to the set of edge boundary IDs
789  }
790 }
791 
792 
793 
795  const unsigned short int shellface,
796  const boundary_id_type id)
797 {
798  this->add_shellface (_mesh.elem_ptr(e), shellface, id);
799 }
800 
801 
802 
804  const unsigned short int shellface,
805  const boundary_id_type id)
806 {
807  libmesh_assert(elem);
808 
809  // Only add BCs for level-0 elements.
810  libmesh_assert_equal_to (elem->level(), 0);
811 
812  // Shells only have 2 faces
813  libmesh_assert_less(shellface, 2);
814 
815  if (id == invalid_id)
816  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
817  << invalid_id \
818  << "\n That is reserved for internal use.");
819 
820  // Don't add the same ID twice
821  for (const auto & pr : as_range(_boundary_shellface_id.equal_range(elem)))
822  if (pr.second.first == shellface &&
823  pr.second.second == id)
824  return;
825 
826  _boundary_shellface_id.insert(std::make_pair(elem, std::make_pair(shellface, id)));
827  _boundary_ids.insert(id);
828  _shellface_boundary_ids.insert(id); // Also add this ID to the set of shellface boundary IDs
829 }
830 
831 
832 
834  const unsigned short int shellface,
835  const std::vector<boundary_id_type> & ids)
836 {
837  if (ids.empty())
838  return;
839 
840  libmesh_assert(elem);
841 
842  // Only add BCs for level-0 elements.
843  libmesh_assert_equal_to (elem->level(), 0);
844 
845  // Shells only have 2 faces
846  libmesh_assert_less(shellface, 2);
847 
848  // Don't add the same ID twice
849  auto bounds = _boundary_shellface_id.equal_range(elem);
850 
851  // The entries in the ids vector may be non-unique. If we expected
852  // *lots* of ids, it might be fastest to construct a std::set from
853  // the entries, but for a small number of entries, which is more
854  // typical, it is probably faster to copy the vector and do sort+unique.
855  // http://stackoverflow.com/questions/1041620/whats-the-most-efficient-way-to-erase-duplicates-and-sort-a-vector
856  std::vector<boundary_id_type> unique_ids(ids.begin(), ids.end());
857  std::sort(unique_ids.begin(), unique_ids.end());
858  std::vector<boundary_id_type>::iterator new_end =
859  std::unique(unique_ids.begin(), unique_ids.end());
860 
861  for (auto & id : as_range(unique_ids.begin(), new_end))
862  {
863  if (id == invalid_id)
864  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
865  << invalid_id \
866  << "\n That is reserved for internal use.");
867 
868  bool already_inserted = false;
869  for (const auto & pr : as_range(bounds))
870  if (pr.second.first == shellface &&
871  pr.second.second == id)
872  {
873  already_inserted = true;
874  break;
875  }
876  if (already_inserted)
877  continue;
878 
879  _boundary_shellface_id.insert(std::make_pair(elem, std::make_pair(shellface, id)));
880  _boundary_ids.insert(id);
881  _shellface_boundary_ids.insert(id); // Also add this ID to the set of shellface boundary IDs
882  }
883 }
884 
885 
887  const unsigned short int side,
888  const boundary_id_type id)
889 {
890  this->add_side (_mesh.elem_ptr(e), side, id);
891 }
892 
893 
894 
895 void BoundaryInfo::add_side(const Elem * elem,
896  const unsigned short int side,
897  const boundary_id_type id)
898 {
899  libmesh_assert(elem);
900 
901  // Only add BCs for level-0 elements.
902  libmesh_assert_equal_to (elem->level(), 0);
903 
904  if (id == invalid_id)
905  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
906  << invalid_id \
907  << "\n That is reserved for internal use.");
908 
909  // Don't add the same ID twice
910  for (const auto & pr : as_range(_boundary_side_id.equal_range(elem)))
911  if (pr.second.first == side &&
912  pr.second.second == id)
913  return;
914 
915  _boundary_side_id.insert(std::make_pair(elem, std::make_pair(side, id)));
916  _boundary_ids.insert(id);
917  _side_boundary_ids.insert(id); // Also add this ID to the set of side boundary IDs
918 }
919 
920 
921 
922 void BoundaryInfo::add_side(const Elem * elem,
923  const unsigned short int side,
924  const std::vector<boundary_id_type> & ids)
925 {
926  if (ids.empty())
927  return;
928 
929  libmesh_assert(elem);
930 
931  // Only add BCs for level-0 elements.
932  libmesh_assert_equal_to (elem->level(), 0);
933 
934  // Don't add the same ID twice
935  auto bounds = _boundary_side_id.equal_range(elem);
936 
937  // The entries in the ids vector may be non-unique. If we expected
938  // *lots* of ids, it might be fastest to construct a std::set from
939  // the entries, but for a small number of entries, which is more
940  // typical, it is probably faster to copy the vector and do sort+unique.
941  // http://stackoverflow.com/questions/1041620/whats-the-most-efficient-way-to-erase-duplicates-and-sort-a-vector
942  std::vector<boundary_id_type> unique_ids(ids.begin(), ids.end());
943  std::sort(unique_ids.begin(), unique_ids.end());
944  std::vector<boundary_id_type>::iterator new_end =
945  std::unique(unique_ids.begin(), unique_ids.end());
946 
947  for (auto & id : as_range(unique_ids.begin(), new_end))
948  {
949  if (id == invalid_id)
950  libmesh_error_msg("ERROR: You may not set a boundary ID of " \
951  << invalid_id \
952  << "\n That is reserved for internal use.");
953 
954  bool already_inserted = false;
955  for (const auto & pr : as_range(bounds))
956  if (pr.second.first == side && pr.second.second == id)
957  {
958  already_inserted = true;
959  break;
960  }
961  if (already_inserted)
962  continue;
963 
964  _boundary_side_id.insert(std::make_pair(elem, std::make_pair(side, id)));
965  _boundary_ids.insert(id);
966  _side_boundary_ids.insert(id); // Also add this ID to the set of side boundary IDs
967  }
968 }
969 
970 
971 
972 bool BoundaryInfo::has_boundary_id(const Node * const node,
973  const boundary_id_type id) const
974 {
975  for (const auto & pr : as_range(_boundary_node_id.equal_range(node)))
976  if (pr.second == id)
977  return true;
978 
979  return false;
980 }
981 
982 
983 
984 #ifdef LIBMESH_ENABLE_DEPRECATED
985 std::vector<boundary_id_type> BoundaryInfo::boundary_ids(const Node * node) const
986 {
987  libmesh_deprecated();
988 
989  std::vector<boundary_id_type> ids;
990  this->boundary_ids(node, ids);
991  return ids;
992 }
993 #endif
994 
995 
996 
997 void BoundaryInfo::boundary_ids (const Node * node,
998  std::vector<boundary_id_type> & vec_to_fill) const
999 {
1000  // Clear out any previous contents
1001  vec_to_fill.clear();
1002 
1003  for (const auto & pr : as_range(_boundary_node_id.equal_range(node)))
1004  vec_to_fill.push_back(pr.second);
1005 }
1006 
1007 
1008 
1009 unsigned int BoundaryInfo::n_boundary_ids(const Node * node) const
1010 {
1011  auto pos = _boundary_node_id.equal_range(node);
1012  return cast_int<unsigned int>(std::distance(pos.first, pos.second));
1013 }
1014 
1015 
1016 
1017 #ifdef LIBMESH_ENABLE_DEPRECATED
1018 std::vector<boundary_id_type> BoundaryInfo::edge_boundary_ids (const Elem * const elem,
1019  const unsigned short int edge) const
1020 {
1021  libmesh_deprecated();
1022 
1023  std::vector<boundary_id_type> ids;
1024  this->edge_boundary_ids(elem, edge, ids);
1025  return ids;
1026 }
1027 #endif
1028 
1029 
1030 
1031 void BoundaryInfo::edge_boundary_ids (const Elem * const elem,
1032  const unsigned short int edge,
1033  std::vector<boundary_id_type> & vec_to_fill) const
1034 {
1035  libmesh_assert(elem);
1036 
1037  // Clear out any previous contents
1038  vec_to_fill.clear();
1039 
1040  // Only level-0 elements store BCs. If this is not a level-0
1041  // element get its level-0 parent and infer the BCs.
1042  const Elem * searched_elem = elem;
1043 #ifdef LIBMESH_ENABLE_AMR
1044  if (elem->level() != 0)
1045  {
1046  // Find all the sides that contain edge. If one of those is a boundary
1047  // side, then this must be a boundary edge. In that case, we just use the
1048  // top-level parent.
1049  bool found_boundary_edge = false;
1050  for (auto side : elem->side_index_range())
1051  {
1052  if (elem->is_edge_on_side(edge,side))
1053  {
1054  if (elem->neighbor_ptr(side) == nullptr)
1055  {
1056  searched_elem = elem->top_parent ();
1057  found_boundary_edge = true;
1058  break;
1059  }
1060  }
1061  }
1062 
1063  if (!found_boundary_edge)
1064  {
1065  // Child element is not on external edge, but it may have internal
1066  // "boundary" IDs. We will walk up the tree, at each level checking that
1067  // the current child is actually on the same edge of the parent that is
1068  // currently being searched for (i.e. that was passed in as "edge").
1069  while (searched_elem->parent() != nullptr)
1070  {
1071  const Elem * parent = searched_elem->parent();
1072  if (parent->is_child_on_edge(parent->which_child_am_i(searched_elem), edge) == false)
1073  return;
1074  searched_elem = parent;
1075  }
1076  }
1077  }
1078 #endif
1079 
1080  // Check each element in the range to see if its edge matches the requested edge.
1081  for (const auto & pr : as_range(_boundary_edge_id.equal_range(searched_elem)))
1082  if (pr.second.first == edge)
1083  vec_to_fill.push_back(pr.second.second);
1084 }
1085 
1086 
1087 
1088 unsigned int BoundaryInfo::n_edge_boundary_ids (const Elem * const elem,
1089  const unsigned short int edge) const
1090 {
1091  std::vector<boundary_id_type> ids;
1092  this->edge_boundary_ids(elem, edge, ids);
1093  return cast_int<unsigned int>(ids.size());
1094 }
1095 
1096 
1097 
1098 #ifdef LIBMESH_ENABLE_DEPRECATED
1099 std::vector<boundary_id_type> BoundaryInfo::raw_edge_boundary_ids (const Elem * const elem,
1100  const unsigned short int edge) const
1101 {
1102  libmesh_deprecated();
1103 
1104  std::vector<boundary_id_type> ids;
1105  this->raw_edge_boundary_ids(elem, edge, ids);
1106  return ids;
1107 }
1108 #endif
1109 
1110 
1111 
1113  const unsigned short int edge,
1114  std::vector<boundary_id_type> & vec_to_fill) const
1115 {
1116  libmesh_assert(elem);
1117 
1118  // Clear out any previous contents
1119  vec_to_fill.clear();
1120 
1121  // Only level-0 elements store BCs.
1122  if (elem->parent())
1123  return;
1124 
1125  // Check each element in the range to see if its edge matches the requested edge.
1126  for (const auto & pr : as_range(_boundary_edge_id.equal_range(elem)))
1127  if (pr.second.first == edge)
1128  vec_to_fill.push_back(pr.second.second);
1129 }
1130 
1131 
1132 
1134  const unsigned short int shellface,
1135  std::vector<boundary_id_type> & vec_to_fill) const
1136 {
1137  libmesh_assert(elem);
1138 
1139  // Shells only have 2 faces
1140  libmesh_assert_less(shellface, 2);
1141 
1142  // Clear out any previous contents
1143  vec_to_fill.clear();
1144 
1145  // Only level-0 elements store BCs. If this is not a level-0
1146  // element get its level-0 parent and infer the BCs.
1147  const Elem * searched_elem = elem;
1148 #ifdef LIBMESH_ENABLE_AMR
1149  if (elem->level() != 0)
1150  {
1151  while (searched_elem->parent() != nullptr)
1152  {
1153  const Elem * parent = searched_elem->parent();
1154  searched_elem = parent;
1155  }
1156  }
1157 #endif
1158 
1159  // Check each element in the range to see if its shellface matches the requested shellface.
1160  for (const auto & pr : as_range(_boundary_shellface_id.equal_range(searched_elem)))
1161  if (pr.second.first == shellface)
1162  vec_to_fill.push_back(pr.second.second);
1163 }
1164 
1165 
1166 
1167 unsigned int BoundaryInfo::n_shellface_boundary_ids (const Elem * const elem,
1168  const unsigned short int shellface) const
1169 {
1170  std::vector<boundary_id_type> ids;
1171  this->shellface_boundary_ids(elem, shellface, ids);
1172  return cast_int<unsigned int>(ids.size());
1173 }
1174 
1175 
1176 
1178  const unsigned short int shellface,
1179  std::vector<boundary_id_type> & vec_to_fill) const
1180 {
1181  libmesh_assert(elem);
1182 
1183  // Shells only have 2 faces
1184  libmesh_assert_less(shellface, 2);
1185 
1186  // Clear out any previous contents
1187  vec_to_fill.clear();
1188 
1189  // Only level-0 elements store BCs.
1190  if (elem->parent())
1191  return;
1192 
1193  // Check each element in the range to see if its shellface matches the requested shellface.
1194  for (const auto & pr : as_range(_boundary_shellface_id.equal_range(elem)))
1195  if (pr.second.first == shellface)
1196  vec_to_fill.push_back(pr.second.second);
1197 }
1198 
1199 
1200 #ifdef LIBMESH_ENABLE_DEPRECATED
1202  const unsigned short int side) const
1203 {
1204  libmesh_deprecated();
1205 
1206  std::vector<boundary_id_type> ids;
1207  this->boundary_ids(elem, side, ids);
1208 
1209  // If the set is empty, return invalid_id
1210  if (ids.empty())
1211  return invalid_id;
1212 
1213  // Otherwise, just return the first id we came across for this
1214  // element on this side.
1215  return *(ids.begin());
1216 }
1217 #endif
1218 
1219 
1220 
1221 bool BoundaryInfo::has_boundary_id(const Elem * const elem,
1222  const unsigned short int side,
1223  const boundary_id_type id) const
1224 {
1225  std::vector<boundary_id_type> ids;
1226  this->boundary_ids(elem, side, ids);
1227  return (std::find(ids.begin(), ids.end(), id) != ids.end());
1228 }
1229 
1230 
1231 
1232 #ifdef LIBMESH_ENABLE_DEPRECATED
1233 std::vector<boundary_id_type> BoundaryInfo::boundary_ids (const Elem * const elem,
1234  const unsigned short int side) const
1235 {
1236  libmesh_deprecated();
1237 
1238  std::vector<boundary_id_type> ids;
1239  this->boundary_ids(elem, side, ids);
1240  return ids;
1241 }
1242 #endif
1243 
1244 
1245 
1246 void BoundaryInfo::boundary_ids (const Elem * const elem,
1247  const unsigned short int side,
1248  std::vector<boundary_id_type> & vec_to_fill) const
1249 {
1250  libmesh_assert(elem);
1251 
1252  // Clear out any previous contents
1253  vec_to_fill.clear();
1254 
1255  // Only level-0 elements store BCs. If this is not a level-0
1256  // element get its level-0 parent and infer the BCs.
1257  const Elem * searched_elem = elem;
1258  if (elem->level() != 0)
1259  {
1260  if (elem->neighbor_ptr(side) == nullptr)
1261  searched_elem = elem->top_parent ();
1262 #ifdef LIBMESH_ENABLE_AMR
1263  else
1264  while (searched_elem->parent() != nullptr)
1265  {
1266  const Elem * parent = searched_elem->parent();
1267  if (parent->is_child_on_side(parent->which_child_am_i(searched_elem), side) == false)
1268  return;
1269  searched_elem = parent;
1270  }
1271 #endif
1272  }
1273 
1274  // Check each element in the range to see if its side matches the requested side.
1275  for (const auto & pr : as_range(_boundary_side_id.equal_range(searched_elem)))
1276  if (pr.second.first == side)
1277  vec_to_fill.push_back(pr.second.second);
1278 }
1279 
1280 
1281 
1282 
1283 unsigned int BoundaryInfo::n_boundary_ids (const Elem * const elem,
1284  const unsigned short int side) const
1285 {
1286  std::vector<boundary_id_type> ids;
1287  this->boundary_ids(elem, side, ids);
1288  return cast_int<unsigned int>(ids.size());
1289 }
1290 
1291 
1292 
1293 #ifdef LIBMESH_ENABLE_DEPRECATED
1294 std::vector<boundary_id_type> BoundaryInfo::raw_boundary_ids (const Elem * const elem,
1295  const unsigned short int side) const
1296 {
1297  libmesh_deprecated();
1298 
1299  std::vector<boundary_id_type> ids;
1300  this->raw_boundary_ids(elem, side, ids);
1301  return ids;
1302 }
1303 #endif
1304 
1305 
1306 
1307 void BoundaryInfo::raw_boundary_ids (const Elem * const elem,
1308  const unsigned short int side,
1309  std::vector<boundary_id_type> & vec_to_fill) const
1310 {
1311  libmesh_assert(elem);
1312 
1313  // Clear out any previous contents
1314  vec_to_fill.clear();
1315 
1316  // Only level-0 elements store BCs.
1317  if (elem->parent())
1318  return;
1319 
1320  // Check each element in the range to see if its side matches the requested side.
1321  for (const auto & pr : as_range(_boundary_side_id.equal_range(elem)))
1322  if (pr.second.first == side)
1323  vec_to_fill.push_back(pr.second.second);
1324 }
1325 
1326 
1327 
1328 void BoundaryInfo::copy_boundary_ids (const BoundaryInfo & old_boundary_info,
1329  const Elem * const old_elem,
1330  const Elem * const new_elem)
1331 {
1332  libmesh_assert_equal_to (old_elem->n_sides(), new_elem->n_sides());
1333  libmesh_assert_equal_to (old_elem->n_edges(), new_elem->n_edges());
1334 
1335  std::vector<boundary_id_type> bndry_ids;
1336 
1337  for (auto s : old_elem->side_index_range())
1338  {
1339  old_boundary_info.raw_boundary_ids (old_elem, s, bndry_ids);
1340  this->add_side (new_elem, s, bndry_ids);
1341  }
1342 
1343  for (auto e : old_elem->edge_index_range())
1344  {
1345  old_boundary_info.raw_edge_boundary_ids (old_elem, e, bndry_ids);
1346  this->add_edge (new_elem, e, bndry_ids);
1347  }
1348 
1349  for (unsigned short sf=0; sf != 2; sf++)
1350  {
1351  old_boundary_info.raw_shellface_boundary_ids (old_elem, sf, bndry_ids);
1352  this->add_shellface (new_elem, sf, bndry_ids);
1353  }
1354 }
1355 
1356 
1357 
1358 void BoundaryInfo::remove (const Node * node)
1359 {
1360  libmesh_assert(node);
1361 
1362  // Erase everything associated with node
1363  _boundary_node_id.erase (node);
1364 }
1365 
1366 
1367 
1368 void BoundaryInfo::remove_node (const Node * node,
1369  const boundary_id_type id)
1370 {
1371  libmesh_assert(node);
1372 
1373  // Erase (node, id) entry from map.
1374  erase_if(_boundary_node_id, node,
1375  [id](decltype(_boundary_node_id)::mapped_type & val)
1376  {return val == id;});
1377 }
1378 
1379 
1380 
1381 void BoundaryInfo::remove (const Elem * elem)
1382 {
1383  libmesh_assert(elem);
1384 
1385  // Erase everything associated with elem
1386  _boundary_edge_id.erase (elem);
1387  _boundary_side_id.erase (elem);
1388  _boundary_shellface_id.erase (elem);
1389 }
1390 
1391 
1392 
1393 void BoundaryInfo::remove_edge (const Elem * elem,
1394  const unsigned short int edge)
1395 {
1396  libmesh_assert(elem);
1397 
1398  // Only level 0 elements are stored in BoundaryInfo.
1399  libmesh_assert_equal_to (elem->level(), 0);
1400 
1401  // Erase (elem, edge, *) entries from map.
1402  erase_if(_boundary_edge_id, elem,
1403  [edge](decltype(_boundary_edge_id)::mapped_type & pr)
1404  {return pr.first == edge;});
1405 }
1406 
1407 
1408 
1409 void BoundaryInfo::remove_edge (const Elem * elem,
1410  const unsigned short int edge,
1411  const boundary_id_type id)
1412 {
1413  libmesh_assert(elem);
1414 
1415  // Only level 0 elements are stored in BoundaryInfo.
1416  libmesh_assert_equal_to (elem->level(), 0);
1417 
1418  // Erase (elem, edge, id) entries from map.
1419  erase_if(_boundary_edge_id, elem,
1420  [edge, id](decltype(_boundary_edge_id)::mapped_type & pr)
1421  {return pr.first == edge && pr.second == id;});
1422 }
1423 
1424 
1426  const unsigned short int shellface)
1427 {
1428  libmesh_assert(elem);
1429 
1430  // Only level 0 elements are stored in BoundaryInfo.
1431  libmesh_assert_equal_to (elem->level(), 0);
1432 
1433  // Shells only have 2 faces
1434  libmesh_assert_less(shellface, 2);
1435 
1436  // Erase (elem, shellface, *) entries from map.
1437  erase_if(_boundary_shellface_id, elem,
1438  [shellface](decltype(_boundary_shellface_id)::mapped_type & pr)
1439  {return pr.first == shellface;});
1440 }
1441 
1442 
1443 
1445  const unsigned short int shellface,
1446  const boundary_id_type id)
1447 {
1448  libmesh_assert(elem);
1449 
1450  // Only level 0 elements are stored in BoundaryInfo.
1451  libmesh_assert_equal_to (elem->level(), 0);
1452 
1453  // Shells only have 2 faces
1454  libmesh_assert_less(shellface, 2);
1455 
1456  // Erase (elem, shellface, id) entries from map.
1457  erase_if(_boundary_shellface_id, elem,
1458  [shellface, id](decltype(_boundary_shellface_id)::mapped_type & pr)
1459  {return pr.first == shellface && pr.second == id;});
1460 }
1461 
1462 void BoundaryInfo::remove_side (const Elem * elem,
1463  const unsigned short int side)
1464 {
1465  libmesh_assert(elem);
1466 
1467  // Only level 0 elements are stored in BoundaryInfo.
1468  libmesh_assert_equal_to (elem->level(), 0);
1469 
1470  // Erase (elem, side, *) entries from map.
1471  erase_if(_boundary_side_id, elem,
1472  [side](decltype(_boundary_side_id)::mapped_type & pr)
1473  {return pr.first == side;});
1474 }
1475 
1476 
1477 
1478 void BoundaryInfo::remove_side (const Elem * elem,
1479  const unsigned short int side,
1480  const boundary_id_type id)
1481 {
1482  libmesh_assert(elem);
1483 
1484  // Erase (elem, side, id) entries from map.
1485  erase_if(_boundary_side_id, elem,
1486  [side, id](decltype(_boundary_side_id)::mapped_type & pr)
1487  {return pr.first == side && pr.second == id;});
1488 }
1489 
1490 
1491 
1493 {
1494  // Erase id from ids containers
1495  _boundary_ids.erase(id);
1496  _side_boundary_ids.erase(id);
1497  _edge_boundary_ids.erase(id);
1498  _shellface_boundary_ids.erase(id);
1499  _node_boundary_ids.erase(id);
1500  _ss_id_to_name.erase(id);
1501  _ns_id_to_name.erase(id);
1502  _es_id_to_name.erase(id);
1503 
1504  // Erase (*, id) entries from map.
1505  erase_if(_boundary_node_id,
1506  [id](decltype(_boundary_node_id)::mapped_type & val)
1507  {return val == id;});
1508 
1509  // Erase (*, *, id) entries from map.
1510  erase_if(_boundary_edge_id,
1511  [id](decltype(_boundary_edge_id)::mapped_type & pr)
1512  {return pr.second == id;});
1513 
1514  // Erase (*, *, id) entries from map.
1515  erase_if(_boundary_shellface_id,
1516  [id](decltype(_boundary_shellface_id)::mapped_type & pr)
1517  {return pr.second == id;});
1518 
1519  // Erase (*, *, id) entries from map.
1520  erase_if(_boundary_side_id,
1521  [id](decltype(_boundary_side_id)::mapped_type & pr)
1522  {return pr.second == id;});
1523 }
1524 
1525 
1526 
1527 unsigned int BoundaryInfo::side_with_boundary_id(const Elem * const elem,
1528  const boundary_id_type boundary_id_in) const
1529 {
1530  const Elem * searched_elem = elem;
1531  if (elem->level() != 0)
1532  searched_elem = elem->top_parent();
1533 
1534  // elem may have zero or multiple occurrences
1535  for (const auto & pr : as_range(_boundary_side_id.equal_range(searched_elem)))
1536  {
1537  // if this is true we found the requested boundary_id
1538  // of the element and want to return the side
1539  if (pr.second.second == boundary_id_in)
1540  {
1541  unsigned int side = pr.second.first;
1542 
1543  // If we're on this external boundary then we share this
1544  // external boundary id
1545  if (elem->neighbor_ptr(side) == nullptr)
1546  return side;
1547 
1548  // If we're on an internal boundary then we need to be sure
1549  // it's the same internal boundary as our top_parent
1550  const Elem * p = elem;
1551 
1552 #ifdef LIBMESH_ENABLE_AMR
1553 
1554  while (p != nullptr)
1555  {
1556  const Elem * parent = p->parent();
1557  if (!parent->is_child_on_side(parent->which_child_am_i(p), side))
1558  break;
1559  p = parent;
1560  }
1561 #endif
1562  // We're on that side of our top_parent; return it
1563  if (!p)
1564  return side;
1565  }
1566  }
1567 
1568  // if we get here, we found elem in the data structure but not
1569  // the requested boundary id, so return the default value
1570  return libMesh::invalid_uint;
1571 }
1572 
1573 void
1574 BoundaryInfo::build_node_boundary_ids(std::vector<boundary_id_type> & b_ids) const
1575 {
1576  b_ids.clear();
1577 
1578  for (const auto & pr : _boundary_node_id)
1579  {
1580  boundary_id_type id = pr.second;
1581 
1582  if (std::find(b_ids.begin(),b_ids.end(),id) == b_ids.end())
1583  b_ids.push_back(id);
1584  }
1585 }
1586 
1587 void
1588 BoundaryInfo::build_side_boundary_ids(std::vector<boundary_id_type> & b_ids) const
1589 {
1590  b_ids.clear();
1591 
1592  for (const auto & pr : _boundary_side_id)
1593  {
1594  boundary_id_type id = pr.second.second;
1595 
1596  if (std::find(b_ids.begin(),b_ids.end(),id) == b_ids.end())
1597  b_ids.push_back(id);
1598  }
1599 }
1600 
1601 void
1602 BoundaryInfo::build_shellface_boundary_ids(std::vector<boundary_id_type> & b_ids) const
1603 {
1604  b_ids.clear();
1605 
1606  for (const auto & pr :_boundary_shellface_id)
1607  {
1608  boundary_id_type id = pr.second.second;
1609 
1610  if (std::find(b_ids.begin(),b_ids.end(),id) == b_ids.end())
1611  b_ids.push_back(id);
1612  }
1613 }
1614 
1616 {
1617  // in serial we know the number of bcs from the
1618  // size of the container
1619  if (_mesh.is_serial())
1620  return _boundary_side_id.size();
1621 
1622  // in parallel we need to sum the number of local bcs
1623  parallel_object_only();
1624 
1625  std::size_t nbcs=0;
1626 
1627  for (const auto & pr : _boundary_side_id)
1628  if (pr.first->processor_id() == this->processor_id())
1629  nbcs++;
1630 
1631  this->comm().sum (nbcs);
1632 
1633  return nbcs;
1634 }
1635 
1636 std::size_t BoundaryInfo::n_edge_conds () const
1637 {
1638  // in serial we know the number of nodesets from the
1639  // size of the container
1640  if (_mesh.is_serial())
1641  return _boundary_edge_id.size();
1642 
1643  // in parallel we need to sum the number of local nodesets
1644  parallel_object_only();
1645 
1646  std::size_t n_edge_bcs=0;
1647 
1648  for (const auto & pr : _boundary_edge_id)
1649  if (pr.first->processor_id() == this->processor_id())
1650  n_edge_bcs++;
1651 
1652  this->comm().sum (n_edge_bcs);
1653 
1654  return n_edge_bcs;
1655 }
1656 
1657 
1659 {
1660  // in serial we know the number of nodesets from the
1661  // size of the container
1662  if (_mesh.is_serial())
1663  return _boundary_shellface_id.size();
1664 
1665  // in parallel we need to sum the number of local nodesets
1666  parallel_object_only();
1667 
1668  std::size_t n_shellface_bcs=0;
1669 
1670  for (const auto & pr : _boundary_shellface_id)
1671  if (pr.first->processor_id() == this->processor_id())
1672  n_shellface_bcs++;
1673 
1674  this->comm().sum (n_shellface_bcs);
1675 
1676  return n_shellface_bcs;
1677 }
1678 
1679 
1680 std::size_t BoundaryInfo::n_nodeset_conds () const
1681 {
1682  // in serial we know the number of nodesets from the
1683  // size of the container
1684  if (_mesh.is_serial())
1685  return _boundary_node_id.size();
1686 
1687  // in parallel we need to sum the number of local nodesets
1688  parallel_object_only();
1689 
1690  std::size_t n_nodesets=0;
1691 
1692  for (const auto & pr : _boundary_node_id)
1693  if (pr.first->processor_id() == this->processor_id())
1694  n_nodesets++;
1695 
1696  this->comm().sum (n_nodesets);
1697 
1698  return n_nodesets;
1699 }
1700 
1701 
1702 
1703 #ifdef LIBMESH_ENABLE_DEPRECATED
1704 void BoundaryInfo::build_node_list (std::vector<dof_id_type> & nl,
1705  std::vector<boundary_id_type> & il) const
1706 {
1707  libmesh_deprecated();
1708 
1709  // Call the non-deprecated version of this function.
1710  auto bc_tuples = this->build_node_list();
1711 
1712  // Clear the input vectors, just in case they were used for
1713  // something else recently...
1714  nl.clear();
1715  il.clear();
1716 
1717  // Reserve the size, then use push_back
1718  nl.reserve (bc_tuples.size());
1719  il.reserve (bc_tuples.size());
1720 
1721  for (const auto & t : bc_tuples)
1722  {
1723  nl.push_back(std::get<0>(t));
1724  il.push_back(std::get<1>(t));
1725  }
1726 }
1727 #endif
1728 
1729 
1730 std::vector<std::tuple<dof_id_type, boundary_id_type>>
1732 {
1733  std::vector<std::tuple<dof_id_type, boundary_id_type>> bc_tuples;
1734  bc_tuples.reserve(_boundary_node_id.size());
1735 
1736  for (const auto & pr : _boundary_node_id)
1737  bc_tuples.emplace_back(pr.first->id(), pr.second);
1738 
1739  // This list is currently in memory address (arbitrary) order, so
1740  // sort to make it consistent on all procs.
1741  std::sort(bc_tuples.begin(), bc_tuples.end());
1742 
1743  return bc_tuples;
1744 }
1745 
1746 
1747 void
1749 {
1750  // If we're on a distributed mesh, even the owner of a node is not
1751  // guaranteed to be able to properly assign its new boundary id(s)!
1752  // Nodal neighbors are not always ghosted, and a nodal neighbor
1753  // might have a boundary side.
1754  const bool mesh_is_serial = _mesh.is_serial();
1755 
1756  typedef std::set<std::pair<dof_id_type, boundary_id_type>> set_type;
1757 
1758  const processor_id_type n_proc = this->n_processors();
1759  const processor_id_type my_proc_id = this->processor_id();
1760  std::vector<set_type> nodes_to_push(n_proc);
1761 
1762  // Pull objects out of the loop to reduce heap operations
1763  std::unique_ptr<const Elem> side;
1764 
1765  // Loop over the side list
1766  for (const auto & pr : _boundary_side_id)
1767  {
1768  // Don't add remote sides
1769  if (pr.first->is_remote())
1770  continue;
1771 
1772  // Need to loop over the sides of any possible children
1773  std::vector<const Elem *> family;
1774 #ifdef LIBMESH_ENABLE_AMR
1775  pr.first->active_family_tree_by_side (family, pr.second.first);
1776 #else
1777  family.push_back(pr.first);
1778 #endif
1779 
1780  for (const auto & cur_elem : family)
1781  {
1782  cur_elem->build_side_ptr(side, pr.second.first);
1783 
1784  // Add each node node on the side with the side's boundary id
1785  for (auto i : side->node_index_range())
1786  {
1787  const boundary_id_type bcid = pr.second.second;
1788  this->add_node(side->node_ptr(i), bcid);
1789  if (!mesh_is_serial)
1790  {
1791  const processor_id_type proc_id =
1792  side->node_ptr(i)->processor_id();
1793  if (proc_id != my_proc_id)
1794  nodes_to_push[proc_id].insert
1795  (std::make_pair(side->node_id(i), bcid));
1796  }
1797  }
1798  }
1799  }
1800 
1801  // If we're on a serial mesh then we're done.
1802  if (mesh_is_serial)
1803  return;
1804 
1805  // Otherwise we need to push ghost node bcids to their owners, then
1806  // pull ghost node bcids from their owners.
1807  Parallel::MessageTag
1808  node_pushes_tag = this->comm().get_unique_tag(),
1809  node_pulls_tag = this->comm().get_unique_tag(),
1810  node_responses_tag = this->comm().get_unique_tag();
1811 
1812  std::vector<Parallel::Request> node_push_requests(n_proc-1);
1813 
1814  for (processor_id_type p = 0; p != n_proc; ++p)
1815  {
1816  if (p == my_proc_id)
1817  continue;
1818 
1819  Parallel::Request &request =
1820  node_push_requests[p - (p > my_proc_id)];
1821 
1822  this->comm().send
1823  (p, nodes_to_push[p], request, node_pushes_tag);
1824  }
1825 
1826  for (processor_id_type p = 1; p != n_proc; ++p)
1827  {
1828  set_type received_nodes;
1829 
1830  this->comm().receive
1831  (Parallel::any_source, received_nodes, node_pushes_tag);
1832 
1833  for (const auto & pr : received_nodes)
1834  this->add_node(_mesh.node_ptr(pr.first), pr.second);
1835  }
1836 
1837  // At this point we should know all the BCs for our own nodes; now
1838  // we need BCs for ghost nodes.
1839  //
1840  // FIXME - parallel_ghost_sync.h doesn't work here because it
1841  // assumes a fixed size datum on each node.
1842  std::vector<std::vector<dof_id_type>> node_ids_requested(n_proc);
1843 
1844  // Determine what nodes we need to request
1845  for (const auto & node : _mesh.node_ptr_range())
1846  {
1847  const processor_id_type pid = node->processor_id();
1848  if (pid != my_proc_id)
1849  node_ids_requested[pid].push_back(node->id());
1850  }
1851 
1852  typedef std::vector<std::pair<dof_id_type, boundary_id_type>> vec_type;
1853 
1854  std::vector<Parallel::Request>
1855  node_pull_requests(n_proc-1),
1856  node_response_requests(n_proc-1);
1857 
1858  // Make all requests
1859  for (processor_id_type p = 0; p != n_proc; ++p)
1860  {
1861  if (p == my_proc_id)
1862  continue;
1863 
1864  Parallel::Request &request =
1865  node_pull_requests[p - (p > my_proc_id)];
1866 
1867  this->comm().send
1868  (p, node_ids_requested[p], request, node_pulls_tag);
1869  }
1870 
1871  // Process all incoming requests
1872  std::vector<vec_type> responses(n_proc-1);
1873 
1874  for (processor_id_type p = 1; p != n_proc; ++p)
1875  {
1876  std::vector<dof_id_type> requested_nodes;
1877 
1878  Parallel::Status
1879  status(this->comm().probe (Parallel::any_source, node_pulls_tag));
1880  const processor_id_type
1881  source_pid = cast_int<processor_id_type>(status.source());
1882 
1883  this->comm().receive
1884  (source_pid, requested_nodes, node_pulls_tag);
1885 
1886  Parallel::Request &request =
1887  node_response_requests[p-1];
1888 
1889  std::vector<boundary_id_type> bcids;
1890 
1891  for (const auto & id : requested_nodes)
1892  {
1893  this->boundary_ids(_mesh.node_ptr(id), bcids);
1894 
1895  for (const auto & b : bcids)
1896  responses[p-1].push_back(std::make_pair(id, b));
1897  }
1898 
1899  this->comm().send
1900  (source_pid, responses[p-1], request, node_responses_tag);
1901  }
1902 
1903  // Process all incoming responses
1904  for (processor_id_type p = 1; p != n_proc; ++p)
1905  {
1906  Parallel::Status
1907  status(this->comm().probe (Parallel::any_source, node_responses_tag));
1908  const processor_id_type
1909  source_pid = cast_int<processor_id_type>(status.source());
1910 
1911  vec_type response;
1912 
1913  this->comm().receive
1914  (source_pid, response, node_responses_tag);
1915 
1916  for (const auto & pr : response)
1917  this->add_node(_mesh.node_ptr(pr.first), pr.second);
1918  }
1919 
1920  Parallel::wait (node_push_requests);
1921  Parallel::wait (node_pull_requests);
1922  Parallel::wait (node_response_requests);
1923 }
1924 
1925 
1926 
1927 
1929 {
1930  // Check for early return
1931  if (_boundary_node_id.empty())
1932  {
1933  libMesh::out << "No boundary node IDs have been added: cannot build side list!" << std::endl;
1934  return;
1935  }
1936 
1937  // Pull objects out of the loop to reduce heap operations
1938  std::unique_ptr<const Elem> side_elem;
1939 
1940  for (const auto & elem : _mesh.active_element_ptr_range())
1941  for (auto side : elem->side_index_range())
1942  {
1943  elem->build_side_ptr(side_elem, side);
1944 
1945  // map from nodeset_id to count for that ID
1946  std::map<boundary_id_type, unsigned> nodesets_node_count;
1947 
1948  // For each nodeset that this node is a member of, increment the associated
1949  // nodeset ID count
1950  for (const auto & node : side_elem->node_ref_range())
1951  for (const auto & pr : as_range(_boundary_node_id.equal_range(&node)))
1952  nodesets_node_count[pr.second]++;
1953 
1954  // Now check to see what nodeset_counts have the correct
1955  // number of nodes in them. For any that do, add this side to
1956  // the sideset, making sure the sideset inherits the
1957  // nodeset's name, if there is one.
1958  for (const auto & pr : nodesets_node_count)
1959  if (pr.second == side_elem->n_nodes())
1960  {
1961  add_side(elem, side, pr.first);
1962 
1963  // Let the sideset inherit any non-empty name from the nodeset
1964  std::string & nset_name = nodeset_name(pr.first);
1965 
1966  if (nset_name != "")
1967  sideset_name(pr.first) = nset_name;
1968  }
1969  } // end for side
1970 }
1971 
1972 
1973 
1974 
1975 #ifdef LIBMESH_ENABLE_DEPRECATED
1976 void BoundaryInfo::build_side_list (std::vector<dof_id_type> & el,
1977  std::vector<unsigned short int> & sl,
1978  std::vector<boundary_id_type> & il) const
1979 {
1980  libmesh_deprecated();
1981 
1982  // Call the non-deprecated version of this function.
1983  auto bc_tuples = this->build_side_list();
1984 
1985  // Clear the input vectors, just in case they were used for
1986  // something else recently...
1987  el.clear();
1988  sl.clear();
1989  il.clear();
1990 
1991  // Reserve the size, then use push_back
1992  el.reserve (bc_tuples.size());
1993  sl.reserve (bc_tuples.size());
1994  il.reserve (bc_tuples.size());
1995 
1996  for (const auto & t : bc_tuples)
1997  {
1998  el.push_back(std::get<0>(t));
1999  sl.push_back(std::get<1>(t));
2000  il.push_back(std::get<2>(t));
2001  }
2002 }
2003 #endif
2004 
2005 
2006 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
2008 {
2009  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> bc_triples;
2010  bc_triples.reserve(_boundary_side_id.size());
2011 
2012  for (const auto & pr : _boundary_side_id)
2013  bc_triples.emplace_back(pr.first->id(), pr.second.first, pr.second.second);
2014 
2015  // bc_triples is currently in whatever order the Elem pointers in
2016  // the _boundary_side_id multimap are in, and in particular might be
2017  // in different orders on different processors. To avoid this
2018  // inconsistency, we'll sort using the default operator< for tuples.
2019  std::sort(bc_triples.begin(), bc_triples.end());
2020 
2021  return bc_triples;
2022 }
2023 
2024 
2025 
2026 #ifdef LIBMESH_ENABLE_DEPRECATED
2027 void BoundaryInfo::build_active_side_list (std::vector<dof_id_type> & el,
2028  std::vector<unsigned short int> & sl,
2029  std::vector<boundary_id_type> & il) const
2030 {
2031  libmesh_deprecated();
2032 
2033  // Call the non-deprecated version of this function.
2034  auto bc_tuples = this->build_active_side_list();
2035 
2036  // Clear the input vectors, just in case they were used for
2037  // something else recently...
2038  el.clear();
2039  sl.clear();
2040  il.clear();
2041 
2042  // Reserve the size, then use push_back
2043  el.reserve (bc_tuples.size());
2044  sl.reserve (bc_tuples.size());
2045  il.reserve (bc_tuples.size());
2046 
2047  for (const auto & t : bc_tuples)
2048  {
2049  el.push_back(std::get<0>(t));
2050  sl.push_back(std::get<1>(t));
2051  il.push_back(std::get<2>(t));
2052  }
2053 }
2054 #endif
2055 
2056 
2057 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
2059 {
2060  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> bc_triples;
2061  bc_triples.reserve(_boundary_side_id.size());
2062 
2063  for (const auto & pr : _boundary_side_id)
2064  {
2065  // Don't add remote sides
2066  if (pr.first->is_remote())
2067  continue;
2068 
2069  // Loop over the sides of possible children
2070  std::vector<const Elem *> family;
2071 #ifdef LIBMESH_ENABLE_AMR
2072  pr.first->active_family_tree_by_side(family, pr.second.first);
2073 #else
2074  family.push_back(pr.first);
2075 #endif
2076 
2077  // Populate the list items
2078  for (const auto & elem : family)
2079  bc_triples.emplace_back(elem->id(), pr.second.first, pr.second.second);
2080  }
2081 
2082  // This list is currently in memory address (arbitrary) order, so
2083  // sort to make it consistent on all procs.
2084  std::sort(bc_triples.begin(), bc_triples.end());
2085 
2086  return bc_triples;
2087 }
2088 
2089 
2090 #ifdef LIBMESH_ENABLE_DEPRECATED
2091 void BoundaryInfo::build_edge_list (std::vector<dof_id_type> & el,
2092  std::vector<unsigned short int> & sl,
2093  std::vector<boundary_id_type> & il) const
2094 {
2095  libmesh_deprecated();
2096 
2097  // Call the non-deprecated version of this function.
2098  auto bc_tuples = this->build_edge_list();
2099 
2100  // Clear the input vectors, just in case they were used for
2101  // something else recently...
2102  el.clear();
2103  sl.clear();
2104  il.clear();
2105 
2106  // Reserve the size, then use push_back
2107  el.reserve (bc_tuples.size());
2108  sl.reserve (bc_tuples.size());
2109  il.reserve (bc_tuples.size());
2110 
2111  for (const auto & t : bc_tuples)
2112  {
2113  el.push_back(std::get<0>(t));
2114  sl.push_back(std::get<1>(t));
2115  il.push_back(std::get<2>(t));
2116  }
2117 }
2118 #endif
2119 
2120 
2121 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
2123 {
2124  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> bc_triples;
2125  bc_triples.reserve(_boundary_edge_id.size());
2126 
2127  for (const auto & pr : _boundary_edge_id)
2128  bc_triples.emplace_back(pr.first->id(), pr.second.first, pr.second.second);
2129 
2130  // This list is currently in memory address (arbitrary) order, so
2131  // sort to make it consistent on all procs.
2132  std::sort(bc_triples.begin(), bc_triples.end());
2133 
2134  return bc_triples;
2135 }
2136 
2137 
2138 #ifdef LIBMESH_ENABLE_DEPRECATED
2139 void BoundaryInfo::build_shellface_list (std::vector<dof_id_type> & el,
2140  std::vector<unsigned short int> & sl,
2141  std::vector<boundary_id_type> & il) const
2142 {
2143  libmesh_deprecated();
2144 
2145  // Call the non-deprecated version of this function.
2146  auto bc_tuples = this->build_shellface_list();
2147 
2148  // Clear the input vectors, just in case they were used for
2149  // something else recently...
2150  el.clear();
2151  sl.clear();
2152  il.clear();
2153 
2154  // Reserve the size, then use push_back
2155  el.reserve (bc_tuples.size());
2156  sl.reserve (bc_tuples.size());
2157  il.reserve (bc_tuples.size());
2158 
2159  for (const auto & t : bc_tuples)
2160  {
2161  el.push_back(std::get<0>(t));
2162  sl.push_back(std::get<1>(t));
2163  il.push_back(std::get<2>(t));
2164  }
2165 }
2166 #endif
2167 
2168 
2169 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
2171 {
2172  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> bc_triples;
2173  bc_triples.reserve(_boundary_shellface_id.size());
2174 
2175  for (const auto & pr : _boundary_shellface_id)
2176  bc_triples.emplace_back(pr.first->id(), pr.second.first, pr.second.second);
2177 
2178  // This list is currently in memory address (arbitrary) order, so
2179  // sort to make it consistent on all procs.
2180  std::sort(bc_triples.begin(), bc_triples.end());
2181 
2182  return bc_triples;
2183 }
2184 
2185 
2186 void BoundaryInfo::print_info(std::ostream & out_stream) const
2187 {
2188  // Print out the nodal BCs
2189  if (!_boundary_node_id.empty())
2190  {
2191  out_stream << "Nodal Boundary conditions:" << std::endl
2192  << "--------------------------" << std::endl
2193  << " (Node No., ID) " << std::endl;
2194 
2195  for (const auto & pr : _boundary_node_id)
2196  out_stream << " (" << pr.first->id()
2197  << ", " << pr.second
2198  << ")" << std::endl;
2199  }
2200 
2201  // Print out the element edge BCs
2202  if (!_boundary_edge_id.empty())
2203  {
2204  out_stream << std::endl
2205  << "Edge Boundary conditions:" << std::endl
2206  << "-------------------------" << std::endl
2207  << " (Elem No., Edge No., ID) " << std::endl;
2208 
2209  for (const auto & pr : _boundary_edge_id)
2210  out_stream << " (" << pr.first->id()
2211  << ", " << pr.second.first
2212  << ", " << pr.second.second
2213  << ")" << std::endl;
2214  }
2215 
2216  // Print out the element shellface BCs
2217  if (!_boundary_shellface_id.empty())
2218  {
2219  out_stream << std::endl
2220  << "Shell-face Boundary conditions:" << std::endl
2221  << "-------------------------" << std::endl
2222  << " (Elem No., Shell-face No., ID) " << std::endl;
2223 
2224  for (const auto & pr : _boundary_shellface_id)
2225  out_stream << " (" << pr.first->id()
2226  << ", " << pr.second.first
2227  << ", " << pr.second.second
2228  << ")" << std::endl;
2229  }
2230 
2231  // Print out the element side BCs
2232  if (!_boundary_side_id.empty())
2233  {
2234  out_stream << std::endl
2235  << "Side Boundary conditions:" << std::endl
2236  << "-------------------------" << std::endl
2237  << " (Elem No., Side No., ID) " << std::endl;
2238 
2239  for (const auto & pr : _boundary_side_id)
2240  out_stream << " (" << pr.first->id()
2241  << ", " << pr.second.first
2242  << ", " << pr.second.second
2243  << ")" << std::endl;
2244  }
2245 }
2246 
2247 
2248 
2249 void BoundaryInfo::print_summary(std::ostream & out_stream) const
2250 {
2251  // Print out the nodal BCs
2252  if (!_boundary_node_id.empty())
2253  {
2254  out_stream << "Nodal Boundary conditions:" << std::endl
2255  << "--------------------------" << std::endl
2256  << " (ID, number of nodes) " << std::endl;
2257 
2258  std::map<boundary_id_type, std::size_t> ID_counts;
2259 
2260  for (const auto & pr : _boundary_node_id)
2261  ID_counts[pr.second]++;
2262 
2263  for (const auto & pr : ID_counts)
2264  out_stream << " (" << pr.first
2265  << ", " << pr.second
2266  << ")" << std::endl;
2267  }
2268 
2269  // Print out the element edge BCs
2270  if (!_boundary_edge_id.empty())
2271  {
2272  out_stream << std::endl
2273  << "Edge Boundary conditions:" << std::endl
2274  << "-------------------------" << std::endl
2275  << " (ID, number of edges) " << std::endl;
2276 
2277  std::map<boundary_id_type, std::size_t> ID_counts;
2278 
2279  for (const auto & pr : _boundary_edge_id)
2280  ID_counts[pr.second.second]++;
2281 
2282  for (const auto & pr : ID_counts)
2283  out_stream << " (" << pr.first
2284  << ", " << pr.second
2285  << ")" << std::endl;
2286  }
2287 
2288 
2289  // Print out the element edge BCs
2290  if (!_boundary_shellface_id.empty())
2291  {
2292  out_stream << std::endl
2293  << "Shell-face Boundary conditions:" << std::endl
2294  << "-------------------------" << std::endl
2295  << " (ID, number of shellfaces) " << std::endl;
2296 
2297  std::map<boundary_id_type, std::size_t> ID_counts;
2298 
2299  for (const auto & pr : _boundary_shellface_id)
2300  ID_counts[pr.second.second]++;
2301 
2302  for (const auto & pr : ID_counts)
2303  out_stream << " (" << pr.first
2304  << ", " << pr.second
2305  << ")" << std::endl;
2306  }
2307 
2308  // Print out the element side BCs
2309  if (!_boundary_side_id.empty())
2310  {
2311  out_stream << std::endl
2312  << "Side Boundary conditions:" << std::endl
2313  << "-------------------------" << std::endl
2314  << " (ID, number of sides) " << std::endl;
2315 
2316  std::map<boundary_id_type, std::size_t> ID_counts;
2317 
2318  for (const auto & pr : _boundary_side_id)
2319  ID_counts[pr.second.second]++;
2320 
2321  for (const auto & pr : ID_counts)
2322  out_stream << " (" << pr.first
2323  << ", " << pr.second
2324  << ")" << std::endl;
2325  }
2326 }
2327 
2328 
2330 {
2331  static const std::string empty_string;
2332  std::map<boundary_id_type, std::string>::const_iterator it =
2333  _ss_id_to_name.find(id);
2334  if (it == _ss_id_to_name.end())
2335  return empty_string;
2336  else
2337  return it->second;
2338 }
2339 
2340 
2342 {
2343  return _ss_id_to_name[id];
2344 }
2345 
2347 {
2348  static const std::string empty_string;
2349  std::map<boundary_id_type, std::string>::const_iterator it =
2350  _ns_id_to_name.find(id);
2351  if (it == _ns_id_to_name.end())
2352  return empty_string;
2353  else
2354  return it->second;
2355 }
2356 
2358 {
2359  return _ns_id_to_name[id];
2360 }
2361 
2363 {
2364  static const std::string empty_string;
2365  std::map<boundary_id_type, std::string>::const_iterator it =
2366  _es_id_to_name.find(id);
2367  if (it == _es_id_to_name.end())
2368  return empty_string;
2369  else
2370  return it->second;
2371 }
2372 
2373 
2375 {
2376  return _es_id_to_name[id];
2377 }
2378 
2380 {
2381  // Search sidesets
2382  for (const auto & pr : _ss_id_to_name)
2383  if (pr.second == name)
2384  return pr.first;
2385 
2386  // Search nodesets
2387  for (const auto & pr : _ns_id_to_name)
2388  if (pr.second == name)
2389  return pr.first;
2390 
2391  // Search edgesets
2392  for (const auto & pr : _es_id_to_name)
2393  if (pr.second == name)
2394  return pr.first;
2395 
2396  // If we made it here without returning, we don't have a sideset,
2397  // nodeset, or edgeset by the requested name, so return invalid_id
2398  return invalid_id;
2399 }
2400 
2401 
2402 
2403 void BoundaryInfo::_find_id_maps(const std::set<boundary_id_type> & requested_boundary_ids,
2404  dof_id_type first_free_node_id,
2405  std::map<dof_id_type, dof_id_type> * node_id_map,
2406  dof_id_type first_free_elem_id,
2407  std::map<std::pair<dof_id_type, unsigned char>, dof_id_type> * side_id_map,
2408  const std::set<subdomain_id_type> & subdomains_relative_to)
2409 {
2410  // We'll do the same modulus trick that DistributedMesh uses to avoid
2411  // id conflicts between different processors
2412  dof_id_type
2413  next_node_id = first_free_node_id + this->processor_id(),
2414  next_elem_id = first_free_elem_id + this->processor_id();
2415 
2416  // Pull objects out of the loop to reduce heap operations
2417  std::unique_ptr<const Elem> side;
2418 
2419  // We'll pass through the mesh once first to build
2420  // the maps and count boundary nodes and elements.
2421  // To find local boundary nodes, we have to examine all elements
2422  // here rather than just local elements, because it's possible to
2423  // have a local boundary node that's not on a local boundary
2424  // element, e.g. at the tip of a triangle.
2425 
2426  // We'll loop through two different ranges here: first all elements,
2427  // looking for local nodes, and second through unpartitioned
2428  // elements, looking for all remaining nodes.
2430  bool hit_end_el = false;
2431  const MeshBase::const_element_iterator end_unpartitioned_el =
2433 
2435  !hit_end_el || (el != end_unpartitioned_el); ++el)
2436  {
2437  if ((el == end_el) && !hit_end_el)
2438  {
2439  // Note that we're done with local nodes and just looking
2440  // for remaining unpartitioned nodes
2441  hit_end_el = true;
2442 
2443  // Join up the local results from other processors
2444  if (side_id_map)
2445  this->comm().set_union(*side_id_map);
2446  if (node_id_map)
2447  this->comm().set_union(*node_id_map);
2448 
2449  // Finally we'll pass through any unpartitioned elements to add them
2450  // to the maps and counts.
2451  next_node_id = first_free_node_id + this->n_processors();
2452  next_elem_id = first_free_elem_id + this->n_processors();
2453 
2455  if (el == end_unpartitioned_el)
2456  break;
2457  }
2458 
2459  const Elem * elem = *el;
2460 
2461  // If the subdomains_relative_to container has the
2462  // invalid_subdomain_id, we fall back on the "old" behavior of
2463  // adding sides regardless of this Elem's subdomain. Otherwise,
2464  // if the subdomains_relative_to container doesn't contain the
2465  // current Elem's subdomain_id(), we won't add any sides from
2466  // it.
2467  if (!subdomains_relative_to.count(Elem::invalid_subdomain_id) &&
2468  !subdomains_relative_to.count(elem->subdomain_id()))
2469  continue;
2470 
2471  // Get the top-level parent for this element. This is used for
2472  // searching for boundary sides on this element.
2473  const Elem * top_parent = elem->top_parent();
2474 
2475  // Find all the boundary side ids for this Elem.
2476  auto bounds = _boundary_side_id.equal_range(top_parent);
2477 
2478  for (auto s : elem->side_index_range())
2479  {
2480  bool add_this_side = false;
2481  boundary_id_type this_bcid = invalid_id;
2482 
2483  for (const auto & pr : as_range(bounds))
2484  {
2485  this_bcid = pr.second.second;
2486 
2487  // if this side is flagged with a boundary condition
2488  // and the user wants this id
2489  if ((pr.second.first == s) &&
2490  (requested_boundary_ids.count(this_bcid)))
2491  {
2492  add_this_side = true;
2493  break;
2494  }
2495  }
2496 
2497  // We may still want to add this side if the user called
2498  // sync() with no requested_boundary_ids. This corresponds
2499  // to the "old" style of calling sync() in which the entire
2500  // boundary was copied to the BoundaryMesh, and handles the
2501  // case where elements on the geometric boundary are not in
2502  // any sidesets.
2503  if (bounds.first == bounds.second &&
2504  requested_boundary_ids.count(invalid_id) &&
2505  elem->neighbor_ptr(s) == nullptr)
2506  add_this_side = true;
2507 
2508  if (add_this_side)
2509  {
2510  // We only assign ids for our own and for
2511  // unpartitioned elements
2512  if (side_id_map &&
2513  ((elem->processor_id() == this->processor_id()) ||
2514  (elem->processor_id() ==
2516  {
2517  std::pair<dof_id_type, unsigned char> side_pair(elem->id(), s);
2518  libmesh_assert (!side_id_map->count(side_pair));
2519  (*side_id_map)[side_pair] = next_elem_id;
2520  next_elem_id += this->n_processors() + 1;
2521  }
2522 
2523  elem->build_side_ptr(side, s);
2524  for (auto n : side->node_index_range())
2525  {
2526  const Node & node = side->node_ref(n);
2527 
2528  // In parallel we don't know enough to number
2529  // others' nodes ourselves.
2530  if (!hit_end_el &&
2531  (node.processor_id() != this->processor_id()))
2532  continue;
2533 
2534  dof_id_type node_id = node.id();
2535  if (node_id_map && !node_id_map->count(node_id))
2536  {
2537  (*node_id_map)[node_id] = next_node_id;
2538  next_node_id += this->n_processors() + 1;
2539  }
2540  }
2541  }
2542  }
2543  }
2544 
2545  // FIXME: ought to renumber side/node_id_map image to be contiguous
2546  // to save memory, also ought to reserve memory
2547 }
2548 
2549 
2550 } // namespace libMesh
libMesh::BoundaryInfo::_mesh
MeshBase & _mesh
The Mesh this boundary info pertains to.
Definition: boundary_info.h:919
libMesh::MeshBase::pid_elements_begin
virtual element_iterator pid_elements_begin(processor_id_type proc_id)=0
Iterate over all elements with a specified processor id.
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::BoundaryInfo::boundary_ids
std::vector< boundary_id_type > boundary_ids(const Node *node) const
Definition: boundary_info.C:985
libMesh::BoundaryInfo::_node_boundary_ids
std::set< boundary_id_type > _node_boundary_ids
Set of user-specified boundary IDs for nodes only.
Definition: boundary_info.h:986
libMesh::BoundaryInfo::remove_id
void remove_id(boundary_id_type id)
Removes all entities (nodes, sides, edges, shellfaces) with boundary id id from their respective cont...
Definition: boundary_info.C:1492
libMesh::BoundaryInfo
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Definition: boundary_info.h:57
libMesh::Elem::is_node_on_side
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
libMesh::Elem::n_edges
virtual unsigned int n_edges() const =0
libMesh::invalid_uint
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value.
Definition: libmesh.h:249
libMesh::MeshBase::set_n_partitions
unsigned int & set_n_partitions()
Definition: mesh_base.h:1667
libMesh::Elem::build_side_ptr
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=true)=0
libMesh::Elem::set_parent
void set_parent(Elem *p)
Sets the pointer to the element's parent.
Definition: elem.h:2450
libMesh::unique_id_type
uint8_t unique_id_type
Definition: id_types.h:86
libMesh::BoundaryInfo::operator=
BoundaryInfo & operator=(const BoundaryInfo &other_boundary_info)
Actual copying operation.
Definition: boundary_info.C:92
libMesh::MeshBase::get_boundary_info
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:132
libMesh::Elem::set_interior_parent
void set_interior_parent(Elem *p)
Sets the pointer to the element's interior_parent.
Definition: elem.C:801
libMesh::MeshBase::is_serial
virtual bool is_serial() const
Definition: mesh_base.h:159
libMesh::Elem::level
unsigned int level() const
Definition: elem.h:2478
libMesh::Elem::n_nodes
virtual unsigned int n_nodes() const =0
libMesh::BoundaryInfo::add_node
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
Definition: boundary_info.C:636
libMesh::BoundaryInfo::get_edgeset_name
const std::string & get_edgeset_name(boundary_id_type id) const
Definition: boundary_info.C:2362
libMesh::Elem::edge_index_range
IntRange< unsigned short > edge_index_range() const
Definition: elem.h:2179
libMesh::BoundaryInfo::get_id_by_name
boundary_id_type get_id_by_name(const std::string &name) const
Definition: boundary_info.C:2379
libMesh::BoundaryInfo::n_boundary_conds
std::size_t n_boundary_conds() const
Definition: boundary_info.C:1615
libMesh::BoundaryInfo::shellface_boundary_ids
void shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface, std::vector< boundary_id_type > &vec_to_fill) const
Definition: boundary_info.C:1133
libMesh::BoundaryInfo::build_active_side_list
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > build_active_side_list() const
As above, but the library creates and fills in a vector of (elem-id, side-id, bc-id) triplets and ret...
Definition: boundary_info.C:2058
libMesh::BoundaryInfo::edge_boundary_ids
std::vector< boundary_id_type > edge_boundary_ids(const Elem *const elem, const unsigned short int edge) const
Definition: boundary_info.C:1018
libMesh::MeshBase::pid_elements_end
virtual element_iterator pid_elements_end(processor_id_type proc_id)=0
libMesh::MeshBase::active_element_ptr_range
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
libMesh::MeshBase::max_elem_id
virtual dof_id_type max_elem_id() const =0
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::BoundaryInfo::sideset_name
std::string & sideset_name(boundary_id_type id)
Definition: boundary_info.C:2341
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::Elem::set_neighbor
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition: elem.h:2105
libMesh::BoundaryInfo::_boundary_ids
std::set< boundary_id_type > _boundary_ids
A collection of user-specified boundary ids for sides, edges, nodes, and shell faces.
Definition: boundary_info.h:959
libMesh::BoundaryInfo::n_shellface_conds
std::size_t n_shellface_conds() const
Definition: boundary_info.C:1658
libMesh::BoundaryInfo::build_side_list
std::vector< BCTuple > build_side_list() const
Definition: boundary_info.C:2007
libMesh::BoundaryInfo::n_edge_conds
std::size_t n_edge_conds() const
Definition: boundary_info.C:1636
libMesh::MeshBase::n_partitions
unsigned int n_partitions() const
Definition: mesh_base.h:1153
libMesh::MeshBase::node_ptr
virtual const Node * node_ptr(const dof_id_type i) const =0
libMesh::BoundaryInfo::remove_edge
void remove_edge(const Elem *elem, const unsigned short int edge)
Removes all boundary conditions associated with edge edge of element elem, if any exist.
Definition: boundary_info.C:1393
libMesh::boundary_id_type
int8_t boundary_id_type
Definition: id_types.h:51
libMesh::DofObject::processor_id
processor_id_type processor_id() const
Definition: dof_object.h:829
libMesh::Elem::is_child_on_edge
virtual bool is_child_on_edge(const unsigned int c, const unsigned int e) const
Definition: elem.C:1646
libMesh::MeshBase::elem_ptr
virtual const Elem * elem_ptr(const dof_id_type i) const =0
libMesh::MeshBase::elements_begin
virtual element_iterator elements_begin()=0
Iterate over all the elements in the Mesh.
libMesh::BoundaryInfo::edgeset_name
std::string & edgeset_name(boundary_id_type id)
Definition: boundary_info.C:2374
libMesh::BoundaryInfo::remove
void remove(const Node *node)
Removes the boundary conditions associated with node node, if any exist.
Definition: boundary_info.C:1358
Pred
The actual predicate is held as a template parameter here.
Definition: variant_filter_iterator.h:248
libMesh::Elem::point
const Point & point(const unsigned int i) const
Definition: elem.h:1955
libMesh::BoundaryInfo::_side_boundary_ids
std::set< boundary_id_type > _side_boundary_ids
Set of user-specified boundary IDs for sides only.
Definition: boundary_info.h:968
libMesh::BoundaryInfo::BoundaryInfo
BoundaryInfo(MeshBase &m)
Constructor.
Definition: boundary_info.C:86
libMesh::BoundaryInfo::copy_boundary_ids
void copy_boundary_ids(const BoundaryInfo &old_boundary_info, const Elem *const old_elem, const Elem *const new_elem)
Definition: boundary_info.C:1328
libMesh::BoundaryInfo::build_node_boundary_ids
void build_node_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique node boundary ids.
Definition: boundary_info.C:1574
libMesh::Elem::invalid_subdomain_id
static const subdomain_id_type invalid_subdomain_id
A static integral constant representing an invalid subdomain id.
Definition: elem.h:244
libMesh::BoundaryInfo::_ss_id_to_name
std::map< boundary_id_type, std::string > _ss_id_to_name
This structure maintains the mapping of named side sets for file formats that support named blocks.
Definition: boundary_info.h:1003
libMesh::BoundaryInfo::nodeset_name
std::string & nodeset_name(boundary_id_type id)
Definition: boundary_info.C:2357
libMesh::MeshBase::element_ptr_range
virtual SimpleRange< element_iterator > element_ptr_range()=0
libMesh::BoundaryInfo::_shellface_boundary_ids
std::set< boundary_id_type > _shellface_boundary_ids
Set of user-specified boundary IDs for shellfaces only.
Definition: boundary_info.h:996
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::IntRange
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition: int_range.h:53
libMesh::BoundaryInfo::print_summary
void print_summary(std::ostream &out=libMesh::out) const
Prints a summary of the boundary information.
Definition: boundary_info.C:2249
libMesh::BoundaryInfo::build_shellface_list
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > build_shellface_list() const
As above, but the library creates and fills in a vector of (elem-id, side-id, bc-id) triplets and ret...
Definition: boundary_info.C:2170
libMesh::BoundaryInfo::clear_boundary_node_ids
void clear_boundary_node_ids()
Clears all the boundary information from all of the nodes in the mesh.
Definition: boundary_info.C:702
libMesh::MeshCommunication::make_node_unique_ids_parallel_consistent
void make_node_unique_ids_parallel_consistent(MeshBase &)
Assuming all unique_ids on local nodes are globally unique, and assuming all processor ids are parall...
Definition: mesh_communication.C:1489
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::BoundaryInfo::print_info
void print_info(std::ostream &out=libMesh::out) const
Prints the boundary information data structure.
Definition: boundary_info.C:2186
libMesh::BoundaryInfo::raw_edge_boundary_ids
std::vector< boundary_id_type > raw_edge_boundary_ids(const Elem *const elem, const unsigned short int edge) const
Definition: boundary_info.C:1099
libMesh::MeshSerializer
Temporarily serialize a DistributedMesh for output; a distributed mesh is allgathered by the MeshSeri...
Definition: mesh_serializer.h:42
libMesh::ParallelObject::n_processors
processor_id_type n_processors() const
Definition: parallel_object.h:100
libMesh::MeshBase::node_ptr_range
virtual SimpleRange< node_iterator > node_ptr_range()=0
libMesh::BoundaryInfo::remove_node
void remove_node(const Node *node, const boundary_id_type id)
Removes boundary id id from node node, if it exists.
Definition: boundary_info.C:1368
libMesh::BoundaryInfo::build_side_list_from_node_list
void build_side_list_from_node_list()
Adds sides to a sideset if every node on that side are in the same sideset.
Definition: boundary_info.C:1928
libMesh::BoundaryInfo::_edge_boundary_ids
std::set< boundary_id_type > _edge_boundary_ids
Set of user-specified boundary IDs for edges only.
Definition: boundary_info.h:977
libMesh::ParallelObject::processor_id
processor_id_type processor_id() const
Definition: parallel_object.h:106
libMesh::BoundaryInfo::get_nodeset_name
const std::string & get_nodeset_name(boundary_id_type id) const
Definition: boundary_info.C:2346
libMesh::BoundaryInfo::side_with_boundary_id
unsigned int side_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
Definition: boundary_info.C:1527
pred
PredBase * pred
The predicate object.
Definition: variant_filter_iterator.h:350
libMesh::BoundaryInfo::n_nodeset_conds
std::size_t n_nodeset_conds() const
Definition: boundary_info.C:1680
libMesh::BoundaryInfo::raw_shellface_boundary_ids
void raw_shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface, std::vector< boundary_id_type > &vec_to_fill) const
Definition: boundary_info.C:1177
libMesh::processor_id_type
uint8_t processor_id_type
Definition: id_types.h:104
libMesh::BoundaryInfo::build_shellface_boundary_ids
void build_shellface_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique shellface boundary ids.
Definition: boundary_info.C:1602
libMesh::BoundaryInfo::clear
void clear()
Clears the underlying data structures and restores the object to a pristine state with no data stored...
Definition: boundary_info.C:144
libMesh::Elem::n_vertices
virtual unsigned int n_vertices() const =0
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::BoundaryInfo::n_boundary_ids
std::size_t n_boundary_ids() const
Definition: boundary_info.h:360
libMesh::BoundaryInfo::remove_side
void remove_side(const Elem *elem, const unsigned short int side)
Removes all boundary conditions associated with side side of element elem, if any exist.
Definition: boundary_info.C:1462
libMesh::as_range
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
n_nodes
const dof_id_type n_nodes
Definition: tecplot_io.C:68
libMesh::Elem::is_child_on_side
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const =0
libMesh::BoundaryInfo::get_side_and_node_maps
void get_side_and_node_maps(UnstructuredMesh &boundary_mesh, std::map< dof_id_type, dof_id_type > &node_id_map, std::map< dof_id_type, unsigned char > &side_id_map, Real tolerance=1.e-6)
Suppose we have used sync to create boundary_mesh.
Definition: boundary_info.C:319
libMesh::BoundaryInfo::regenerate_id_sets
void regenerate_id_sets()
Clears and regenerates the cached sets of ids.
Definition: boundary_info.C:159
libMesh::MeshBase::const_element_iterator
The definition of the const_element_iterator struct.
Definition: mesh_base.h:1891
libMesh::BoundaryInfo::_find_id_maps
void _find_id_maps(const std::set< boundary_id_type > &requested_boundary_ids, dof_id_type first_free_node_id, std::map< dof_id_type, dof_id_type > *node_id_map, dof_id_type first_free_elem_id, std::map< std::pair< dof_id_type, unsigned char >, dof_id_type > *side_id_map, const std::set< subdomain_id_type > &subdomains_relative_to)
Helper method for finding consistent maps of interior to boundary dof_object ids.
Definition: boundary_info.C:2403
libMesh::BoundaryInfo::add_elements
void add_elements(const std::set< boundary_id_type > &requested_boundary_ids, UnstructuredMesh &boundary_mesh)
Generates elements along the boundary of our _mesh, which use pre-existing nodes on the boundary_mesh...
Definition: boundary_info.C:370
libMesh::MeshBase::delete_remote_elements
virtual void delete_remote_elements()
When supported, deletes all nonlocal elements of the mesh except for "ghosts" which touch a local ele...
Definition: mesh_base.h:201
libMesh::BoundaryInfo::_ns_id_to_name
std::map< boundary_id_type, std::string > _ns_id_to_name
This structure maintains the mapping of named node sets for file formats that support named blocks.
Definition: boundary_info.h:1010
libMesh::UnstructuredMesh
The UnstructuredMesh class is derived from the MeshBase class.
Definition: unstructured_mesh.h:48
libMesh::BoundaryInfo::raw_boundary_ids
std::vector< boundary_id_type > raw_boundary_ids(const Elem *const elem, const unsigned short int side) const
Definition: boundary_info.C:1294
libMesh::Elem::parent
const Elem * parent() const
Definition: elem.h:2434
distance
Real distance(const Point &p)
Definition: subdomains_ex3.C:50
libMesh::Elem::interior_parent
const Elem * interior_parent() const
Definition: elem.C:749
libMesh::BoundaryInfo::~BoundaryInfo
~BoundaryInfo()
Destructor.
Definition: boundary_info.C:137
libMesh::BoundaryInfo::get_sideset_name
const std::string & get_sideset_name(boundary_id_type id) const
Definition: boundary_info.C:2329
libMesh::BoundaryInfo::_boundary_edge_id
std::multimap< const Elem *, std::pair< unsigned short int, boundary_id_type > > _boundary_edge_id
Data structure that maps edges of elements to boundary ids.
Definition: boundary_info.h:934
libMesh::MeshBase::add_elem
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
libMesh::Partitioner::set_node_processor_ids
static void set_node_processor_ids(MeshBase &mesh)
This function is called after partitioning to set the processor IDs for the nodes.
Definition: partitioner.C:691
libMesh::Elem::subdomain_id
subdomain_id_type subdomain_id() const
Definition: elem.h:2069
libMesh::DofObject::id
dof_id_type id() const
Definition: dof_object.h:767
libMesh::DistributedMesh::libmesh_assert_valid_parallel_ids
virtual void libmesh_assert_valid_parallel_ids() const override
Verify id and processor_id consistency of our elements and nodes containers.
Definition: distributed_mesh.C:968
libMesh::BoundaryInfo::add_edge
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure.
Definition: boundary_info.C:707
libMesh::MeshBase::elements_end
virtual element_iterator elements_end()=0
libMesh::BoundaryInfo::build_side_boundary_ids
void build_side_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique side boundary ids.
Definition: boundary_info.C:1588
libMesh::BoundaryInfo::build_node_list
std::vector< std::tuple< dof_id_type, boundary_id_type > > build_node_list() const
As above, but the library creates and fills in a vector of (node-id, bc-id) pairs and returns it to t...
Definition: boundary_info.C:1731
libMesh::BoundaryInfo::build_node_list_from_side_list
void build_node_list_from_side_list()
Adds nodes with boundary ids based on the side's boundary ids they are connected to.
Definition: boundary_info.C:1748
libMesh::Elem::side_index_range
IntRange< unsigned short > side_index_range() const
Definition: elem.h:2188
libMesh::BoundaryInfo::_boundary_side_id
std::multimap< const Elem *, std::pair< unsigned short int, boundary_id_type > > _boundary_side_id
Data structure that maps sides of elements to boundary ids.
Definition: boundary_info.h:950
libMesh::DofObject::invalid_processor_id
static const processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Definition: dof_object.h:432
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::BoundaryInfo::n_shellface_boundary_ids
unsigned int n_shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface) const
Definition: boundary_info.C:1167
std::norm
MetaPhysicL::DualNumber< T, D > norm(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::Elem::is_edge_on_side
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const =0
libMesh::BoundaryInfo::_es_id_to_name
std::map< boundary_id_type, std::string > _es_id_to_name
This structure maintains the mapping of named edge sets for file formats that support named blocks.
Definition: boundary_info.h:1017
libMesh::BoundaryInfo::n_edge_boundary_ids
unsigned int n_edge_boundary_ids(const Elem *const elem, const unsigned short int edge) const
Definition: boundary_info.C:1088
libMesh::BoundaryInfo::add_shellface
void add_shellface(const dof_id_type elem, const unsigned short int shellface, const boundary_id_type id)
Add shell face shellface of element number elem with boundary id id to the boundary information data ...
Definition: boundary_info.C:794
libMesh::MeshBase::add_point
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.
libMesh::MeshBase::parallel_max_unique_id
virtual unique_id_type parallel_max_unique_id() const =0
libMesh::Elem::neighbor_ptr
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2085
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::MeshBase::prepare_for_use
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:318
libMesh::ParallelObject
An object whose state is distributed along a set of processors.
Definition: parallel_object.h:55
libMesh::Elem::INACTIVE
Definition: elem.h:1174
libMesh::MeshCommunication
This is the MeshCommunication class.
Definition: mesh_communication.h:50
libMesh::MeshBase::clear
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:429
libMesh::Elem::n_sides
virtual unsigned int n_sides() const =0
libMesh::BoundaryInfo::has_boundary_id
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
Definition: boundary_info.C:972
libMesh::MeshBase::query_node_ptr
virtual const Node * query_node_ptr(const dof_id_type i) const =0
libMesh::BoundaryInfo::invalid_id
static const boundary_id_type invalid_id
Number used for internal use.
Definition: boundary_info.h:899
libMesh::out
OStreamProxy out
libMesh::Elem::node_ptr
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2009
libMesh::BoundaryInfo::add_side
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
Definition: boundary_info.C:886
libMesh::BoundaryInfo::build_edge_list
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > build_edge_list() const
As above, but the library creates and fills in a vector of (elem-id, side-id, bc-id) triplets and ret...
Definition: boundary_info.C:2122
libMesh::DistributedMesh
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
Definition: distributed_mesh.h:50
libMesh::remote_elem
const RemoteElem * remote_elem
Definition: remote_elem.C:57
libMesh::BoundaryInfo::_boundary_node_id
std::multimap< const Node *, boundary_id_type > _boundary_node_id
Data structure that maps nodes in the mesh to boundary ids.
Definition: boundary_info.h:926
libMesh::Elem::which_child_am_i
unsigned int which_child_am_i(const Elem *e) const
Definition: elem.h:2596
libMesh::Quality::name
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
libMesh::BoundaryInfo::_boundary_shellface_id
std::multimap< const Elem *, std::pair< unsigned short int, boundary_id_type > > _boundary_shellface_id
Data structure that maps faces of shell elements to boundary ids.
Definition: boundary_info.h:942
libMesh::BoundaryInfo::remove_shellface
void remove_shellface(const Elem *elem, const unsigned short int shellface)
Removes all boundary conditions associated with shell face shellface of element elem,...
Definition: boundary_info.C:1425
libMesh::BoundaryInfo::sync
void sync(UnstructuredMesh &boundary_mesh)
Generates boundary_mesh data structures corresponding to the mesh data structures.
Definition: boundary_info.C:200
libMesh::BoundaryInfo::boundary_id
boundary_id_type boundary_id(const Elem *const elem, const unsigned short int side) const
Definition: boundary_info.C:1201
libMesh::Elem::top_parent
const Elem * top_parent() const
Definition: elem.h:2460
libMesh::MeshBase::partitioner
virtual std::unique_ptr< Partitioner > & partitioner()
A partitioner to use at each prepare_for_use()
Definition: mesh_base.h:127