$extrastylesheet
boundary_info.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 // C++ includes
00021 #include <iterator>  // std::distance
00022 
00023 // Local includes
00024 #include "libmesh/libmesh_config.h"
00025 #include "libmesh/boundary_info.h"
00026 #include "libmesh/elem.h"
00027 #include "libmesh/mesh_data.h"
00028 #include "libmesh/mesh_serializer.h"
00029 #include "libmesh/parallel.h"
00030 #include "libmesh/partitioner.h"
00031 #include "libmesh/unstructured_mesh.h"
00032 
00033 namespace libMesh
00034 {
00035 
00036 
00037 
00038 //------------------------------------------------------
00039 // BoundaryInfo static member initializations
00040 const boundary_id_type BoundaryInfo::invalid_id = -123;
00041 
00042 
00043 
00044 //------------------------------------------------------
00045 // BoundaryInfo functions
00046 BoundaryInfo::BoundaryInfo(const MeshBase& m) :
00047   ParallelObject(m.comm()),
00048   _mesh (m)
00049 {
00050 }
00051 
00052 BoundaryInfo& BoundaryInfo::operator=(const BoundaryInfo& other_boundary_info)
00053 {
00060   // Copy node boundary info
00061   {
00062     std::multimap<const Node*, boundary_id_type>::const_iterator it = other_boundary_info._boundary_node_id.begin();
00063     const std::multimap<const Node*, boundary_id_type>::const_iterator end = other_boundary_info._boundary_node_id.end();
00064 
00065     for(; it != end; ++it)
00066       {
00067         const Node * other_node = it->first;
00068         _boundary_node_id.insert
00069           (std::pair<const Node*, boundary_id_type>
00070            (_mesh.node_ptr(other_node->id()), it->second) );
00071       }
00072   }
00073 
00074   // Copy edge boundary info
00075   {
00076     std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00077       const_iterator it = other_boundary_info._boundary_edge_id.begin();
00078     const std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00079       const_iterator end = other_boundary_info._boundary_edge_id.end();
00080 
00081     for(; it != end; ++it)
00082       {
00083         const Elem * other_elem = it->first;
00084         _boundary_edge_id.insert
00085           (std::pair<const Elem*, std::pair<unsigned short int, boundary_id_type> >
00086            (_mesh.elem(other_elem->id()), it->second) );
00087       }
00088   }
00089 
00090   // Copy side boundary info
00091   {
00092     std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00093       const_iterator it = other_boundary_info._boundary_side_id.begin();
00094     const std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00095       const_iterator end = other_boundary_info._boundary_side_id.end();
00096 
00097     for(; it != end; ++it)
00098       {
00099         const Elem * other_elem = it->first;
00100         _boundary_side_id.insert
00101           (std::pair<const Elem*, std::pair<unsigned short int, boundary_id_type> >
00102            (_mesh.elem(other_elem->id()), it->second) );
00103       }
00104   }
00105 
00106   _boundary_ids = other_boundary_info._boundary_ids;
00107   _side_boundary_ids = other_boundary_info._side_boundary_ids;
00108   _node_boundary_ids = other_boundary_info._node_boundary_ids;
00109 
00110   return *this;
00111 }
00112 
00113 
00114 BoundaryInfo::~BoundaryInfo()
00115 {
00116   this->clear();
00117 }
00118 
00119 
00120 
00121 void BoundaryInfo::clear()
00122 {
00123   _boundary_node_id.clear();
00124   _boundary_side_id.clear();
00125   _boundary_ids.clear();
00126   _side_boundary_ids.clear();
00127   _node_boundary_ids.clear();
00128 }
00129 
00130 
00131 
00132 void BoundaryInfo::sync (UnstructuredMesh& boundary_mesh,
00133                          MeshData*     boundary_mesh_data,
00134                          MeshData*     this_mesh_data)
00135 {
00136   std::set<boundary_id_type> request_boundary_ids(_boundary_ids);
00137   request_boundary_ids.insert(invalid_id);
00138   if (!_mesh.is_serial())
00139     this->comm().set_union(request_boundary_ids);
00140 
00141   this->sync(request_boundary_ids, boundary_mesh,
00142              boundary_mesh_data, this_mesh_data);
00143 }
00144 
00145 
00146 
00147 void BoundaryInfo::sync (const std::set<boundary_id_type> &requested_boundary_ids,
00148                          UnstructuredMesh& boundary_mesh,
00149                          MeshData*     boundary_mesh_data,
00150                          MeshData*     this_mesh_data)
00151 {
00152   START_LOG("sync()", "BoundaryInfo");
00153 
00154   boundary_mesh.clear();
00155 
00161   if (!_mesh.is_serial())
00162     boundary_mesh.delete_remote_elements();
00163 
00170   MeshSerializer serializer
00171     (const_cast<MeshBase&>(_mesh), boundary_mesh.is_serial());
00172 
00186   boundary_mesh.set_n_partitions() = _mesh.n_partitions();
00187 
00188   std::map<dof_id_type, dof_id_type> node_id_map;
00189   std::map<std::pair<dof_id_type, unsigned char>, dof_id_type> side_id_map;
00190 
00191   // We'll do the same modulus trick that ParallelMesh uses to avoid
00192   // id conflicts between different processors
00193   dof_id_type next_node_id = this->processor_id(),
00194     next_elem_id = this->processor_id();
00195 
00196   // We'll pass through the mesh once first to build
00197   // the maps and count boundary nodes and elements
00198   // We have to examine all elements here rather than just local
00199   // elements, because it's possible to have a local boundary node
00200   // that's not on a local boundary element, e.g. at the tip of a
00201   // triangle.
00202   const MeshBase::const_element_iterator end_el = _mesh.elements_end();
00203   for (MeshBase::const_element_iterator el = _mesh.elements_begin();
00204        el != end_el; ++el)
00205     {
00206       const Elem *elem = *el;
00207 
00208       for (unsigned char s=0; s<elem->n_sides(); s++)
00209         if (elem->neighbor(s) == NULL) // on the boundary
00210           {
00211             // Get the top-level parent for this element
00212             const Elem* top_parent = elem->top_parent();
00213 
00214             // A convenient typedef
00215             typedef
00216               std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00217               const_iterator Iter;
00218 
00219             // Find the right id number for that side
00220             std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(top_parent);
00221 
00222             bool add_this_side = false;
00223             boundary_id_type this_bcid = invalid_id;
00224 
00225             for (; pos.first != pos.second; ++pos.first)
00226               {
00227                 this_bcid = pos.first->second.second;
00228 
00229                 // if this side is flagged with a boundary condition
00230                 // and the user wants this id
00231                 if ((pos.first->second.first == s) &&
00232                     (requested_boundary_ids.count(this_bcid)))
00233                   {
00234                     add_this_side = true;
00235                     break;
00236                   }
00237               }
00238 
00239             // if side s wasn't found or doesn't have a boundary
00240             // condition we may still want to add it
00241             if (pos.first == pos.second)
00242               {
00243                 this_bcid = invalid_id;
00244                 if (requested_boundary_ids.count(this_bcid))
00245                   add_this_side = true;
00246               }
00247 
00248             if (add_this_side)
00249               {
00250                 std::pair<dof_id_type, unsigned char> side_pair(elem->id(), s);
00251                 libmesh_assert (!side_id_map.count(side_pair));
00252                 side_id_map[side_pair] = next_elem_id;
00253                 next_elem_id += this->n_processors() + 1;
00254 
00255                 // Use a proxy element for the side to query nodes
00256                 UniquePtr<Elem> side (elem->build_side(s));
00257                 for (unsigned int n = 0; n != side->n_nodes(); ++n)
00258                   {
00259                     Node *node = side->get_node(n);
00260                     libmesh_assert(node);
00261 
00262                     // In parallel we only know enough to number our own nodes.
00263                     if (node->processor_id() != this->processor_id())
00264                       continue;
00265 
00266                     dof_id_type node_id = node->id();
00267                     if (!node_id_map.count(node_id))
00268                       {
00269                         node_id_map[node_id] = next_node_id;
00270                         next_node_id += this->n_processors() + 1;
00271                       }
00272                   }
00273               }
00274           }
00275     }
00276 
00277   // Join up the results from other processors
00278   this->comm().set_union(side_id_map);
00279   this->comm().set_union(node_id_map);
00280 
00281   // Finally we'll pass through any unpartitioned elements to add them
00282   // to the maps and counts.
00283   next_node_id = this->n_processors();
00284   next_elem_id = this->n_processors();
00285 
00286   const MeshBase::const_element_iterator end_unpartitioned_el =
00287     _mesh.pid_elements_end(DofObject::invalid_processor_id);
00288   for (MeshBase::const_element_iterator el =
00289          _mesh.pid_elements_begin(DofObject::invalid_processor_id);
00290        el != end_unpartitioned_el; ++el)
00291     {
00292       const Elem *elem = *el;
00293 
00294       for (unsigned char s=0; s<elem->n_sides(); s++)
00295         if (elem->neighbor(s) == NULL) // on the boundary
00296           {
00297             // Get the top-level parent for this element
00298             const Elem* top_parent = elem->top_parent();
00299 
00300             // A convenient typedef
00301             typedef
00302               std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00303               const_iterator Iter;
00304 
00305             // Find the right id number for that side
00306             std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(top_parent);
00307 
00308             bool add_this_side = false;
00309             boundary_id_type this_bcid = invalid_id;
00310 
00311             for (; pos.first != pos.second; ++pos.first)
00312               {
00313                 this_bcid = pos.first->second.second;
00314                 // if this side is flagged with a boundary condition
00315                 // and the user wants this id
00316                 if ((pos.first->second.first == s) &&
00317                     (requested_boundary_ids.count(this_bcid)))
00318                   {
00319                     add_this_side = true;
00320                     break;
00321                   }
00322               }
00323 
00324             // if side s doesn't have a boundary condition we may
00325             // still want to add it
00326             if (pos.first == pos.second)
00327               {
00328                 this_bcid = invalid_id;
00329                 if (requested_boundary_ids.count(this_bcid))
00330                   add_this_side = true;
00331               }
00332 
00333             if (add_this_side)
00334               {
00335                 std::pair<dof_id_type, unsigned char> side_pair(elem->id(), s);
00336                 libmesh_assert (!side_id_map.count(side_pair));
00337                 side_id_map[side_pair] = next_elem_id;
00338                 next_elem_id += this->n_processors() + 1;
00339 
00340                 // Use a proxy element for the side to query nodes
00341                 UniquePtr<Elem> side (elem->build_side(s));
00342                 for (unsigned int n = 0; n != side->n_nodes(); ++n)
00343                   {
00344                     Node *node = side->get_node(n);
00345                     libmesh_assert(node);
00346                     dof_id_type node_id = node->id();
00347                     if (!node_id_map.count(node_id))
00348                       {
00349                         node_id_map[node_id] = next_node_id;
00350                         next_node_id += this->n_processors() + 1;
00351                       }
00352                   }
00353               }
00354           }
00355     }
00356 
00357   // FIXME: ought to renumber side/node_id_map image to be contiguous
00358   // to save memory, also ought to reserve memory
00359 
00360   // Let's add all the nodes to the boundary mesh
00361 
00362   MeshBase::const_node_iterator n_end  = _mesh.nodes_end();
00363 
00364   for(MeshBase::const_node_iterator n_it = _mesh.nodes_begin();
00365       n_it != n_end; ++n_it)
00366     {
00367       const Node* node = *n_it;
00368       dof_id_type node_id = node->id();
00369       if (node_id_map.count(node_id))
00370         boundary_mesh.add_point(*node, node_id_map[node_id], node->processor_id());
00371     }
00372 
00373 
00374   // Finally let's add the elements
00375 
00376 
00377   for (MeshBase::const_element_iterator el = _mesh.elements_begin();
00378        el != end_el; ++el)
00379     {
00380       const Elem* elem = *el;
00381 
00382       for (unsigned int s=0; s<elem->n_sides(); s++)
00383         if (elem->neighbor(s) == NULL) // on the boundary
00384           {
00385             // Get the top-level parent for this element
00386             const Elem* top_parent = elem->top_parent();
00387 
00388             // A convenient typedef
00389             typedef
00390               std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00391               const_iterator Iter;
00392 
00393             // Find the right id number for that side
00394             std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(top_parent);
00395 
00396             bool add_this_side = false;
00397             boundary_id_type this_bcid = invalid_id;
00398 
00399             for (; pos.first != pos.second; ++pos.first)
00400               {
00401                 this_bcid = pos.first->second.second;
00402 
00403                 // if this side is flagged with a boundary condition
00404                 // and the user wants this id
00405                 if ((pos.first->second.first == s) &&
00406                     (requested_boundary_ids.count(this_bcid)))
00407                   {
00408                     add_this_side = true;
00409                     break;
00410                   }
00411               }
00412 
00413             // if side s wasn't found or doesn't have a boundary
00414             // condition we may still want to add it
00415             if (pos.first == pos.second)
00416               {
00417                 this_bcid = invalid_id;
00418                 if (requested_boundary_ids.count(this_bcid))
00419                   add_this_side = true;
00420               }
00421 
00422             if (add_this_side)
00423               {
00424                 // Build the side - do not use a "proxy" element here:
00425                 // This will be going into the boundary_mesh and needs to
00426                 // stand on its own.
00427                 UniquePtr<Elem> side (elem->build_side(s, false));
00428 
00429                 side->processor_id() = elem->processor_id();
00430 
00431                 const std::pair<dof_id_type, unsigned char> side_pair(elem->id(), s);
00432 
00433                 libmesh_assert(side_id_map.count(side_pair));
00434 
00435                 side->set_id(side_id_map[side_pair]);
00436 
00437                 // Add the side
00438                 Elem* new_elem = boundary_mesh.add_elem(side.release());
00439 
00440                 // This side's Node pointers still point to the nodes of the original mesh.
00441                 // We need to re-point them to the boundary mesh's nodes!  Since we copied *ALL* of
00442                 // the original mesh's nodes over, we should be guaranteed to have the same ordering.
00443                 for (unsigned int nn=0; nn<new_elem->n_nodes(); ++nn)
00444                   {
00445                     // Get the correct node pointer, based on the id()
00446                     Node* new_node = boundary_mesh.node_ptr(node_id_map[new_elem->node(nn)]);
00447 
00448                     // sanity check: be sure that the new Node exists
00449                     // and its global id really matches
00450                     libmesh_assert (new_node);
00451                     libmesh_assert_equal_to (new_node->id(), node_id_map[new_elem->node(nn)]);
00452 
00453                     // Assign the new node pointer
00454                     new_elem->set_node(nn) = new_node;
00455                   }
00456 
00457 #ifdef LIBMESH_ENABLE_AMR
00458                 // Finally, set the parent and interior_parent links
00459                 if (elem->parent())
00460                   {
00461                     const std::pair<dof_id_type, unsigned char> parent_side_pair(elem->parent()->id(), s);
00462 
00463                     libmesh_assert(side_id_map.count(parent_side_pair));
00464 
00465                     Elem* side_parent = boundary_mesh.elem(side_id_map[parent_side_pair]);
00466 
00467                     libmesh_assert(side_parent);
00468 
00469                     new_elem->set_parent(side_parent);
00470 
00471                     side_parent->set_refinement_flag(Elem::INACTIVE);
00472 
00473                     // Figuring out which child we are of our parent
00474                     // is a trick.  Due to libMesh child numbering
00475                     // conventions, if we are an element on a vertex,
00476                     // then we share that vertex with our parent, with
00477                     // the same local index.
00478                     bool found_child = false;
00479                     for (unsigned int v=0; v != new_elem->n_vertices(); ++v)
00480                       if (new_elem->get_node(v) == side_parent->get_node(v))
00481                         {
00482                           side_parent->add_child(new_elem, v);
00483                           found_child = true;
00484                         }
00485 
00486                     // If we don't share any vertex with our parent,
00487                     // then we're the fourth child (index 3) of a
00488                     // triangle.
00489                     if (!found_child)
00490                       {
00491                         libmesh_assert_equal_to (new_elem->n_vertices(), 3);
00492                         side_parent->add_child(new_elem, 3);
00493                       }
00494                   }
00495 #endif
00496 
00497                 new_elem->set_interior_parent (const_cast<Elem*>(elem));
00498               }
00499           }
00500     }
00501 
00502   // When desired, copy the MeshData
00503   // to the boundary_mesh
00504   if ((boundary_mesh_data != NULL) && (this_mesh_data != NULL))
00505     boundary_mesh_data->assign(*this_mesh_data);
00506 
00507   // Don't repartition this mesh; we want it to stay in sync with the
00508   // interior partitioning.
00509   boundary_mesh.partitioner().reset(NULL);
00510 
00511   // Make boundary_mesh nodes and elements contiguous
00512   boundary_mesh.prepare_for_use(/*skip_renumber =*/ false);
00513 
00514   // and finally distribute element partitioning to the nodes
00515   Partitioner::set_node_processor_ids(boundary_mesh);
00516 
00517   STOP_LOG("sync()", "BoundaryInfo");
00518 }
00519 
00520 
00521 
00522 void BoundaryInfo::add_node(const dof_id_type node,
00523                             const boundary_id_type id)
00524 {
00525   this->add_node (_mesh.node_ptr(node), id);
00526 }
00527 
00528 
00529 
00530 void BoundaryInfo::add_node(const Node* node,
00531                             const boundary_id_type id)
00532 {
00533   if (id == invalid_id)
00534     libmesh_error_msg("ERROR: You may not set a boundary ID of "   \
00535                       << invalid_id                                \
00536                       << "\n That is reserved for internal use.");
00537 
00538   // A convenient typedef
00539   typedef std::multimap<const Node*, boundary_id_type>::const_iterator Iter;
00540 
00541   // Don't add the same ID twice
00542   std::pair<Iter, Iter> pos = _boundary_node_id.equal_range(node);
00543 
00544   for (;pos.first != pos.second; ++pos.first)
00545     if (pos.first->second == id)
00546       return;
00547 
00548   std::pair<const Node*, boundary_id_type> kv (node, id);
00549 
00550   _boundary_node_id.insert(kv);
00551   _boundary_ids.insert(id);
00552   _node_boundary_ids.insert(id); // Also add this ID to the set of node boundary IDs
00553 }
00554 
00555 void BoundaryInfo::add_node(const Node* node,
00556                             const std::vector<boundary_id_type>& ids)
00557 {
00558   if (ids.empty())
00559     return;
00560 
00561   libmesh_assert(node);
00562 
00563   // A convenient typedef
00564   typedef std::multimap<const Node*, boundary_id_type>::const_iterator Iter;
00565 
00566   // Don't add the same ID twice
00567   std::pair<Iter, Iter> pos = _boundary_node_id.equal_range(node);
00568 
00569   for (unsigned int i=0; i!= ids.size(); ++i)
00570     {
00571       boundary_id_type id=ids[i];
00572 
00573       if (id == invalid_id)
00574         libmesh_error_msg("ERROR: You may not set a boundary ID of "    \
00575                           << invalid_id                                 \
00576                           << "\n That is reserved for internal use.");
00577 
00578       bool already_inserted = false;
00579       for (Iter p = pos.first;p != pos.second; ++p)
00580         if (p->second == id)
00581           {
00582             already_inserted = true;
00583             break;
00584           }
00585       if (already_inserted)
00586         continue;
00587 
00588       std::pair<const Node*, boundary_id_type> kv (node, id);
00589 
00590       _boundary_node_id.insert(kv);
00591       _boundary_ids.insert(id);
00592       _node_boundary_ids.insert(id); // Also add this ID to the set of node boundary IDs
00593     }
00594 }
00595 
00596 
00597 void BoundaryInfo::clear_boundary_node_ids()
00598 {
00599   _boundary_node_id.clear();
00600 }
00601 
00602 void BoundaryInfo::add_edge(const dof_id_type e,
00603                             const unsigned short int edge,
00604                             const boundary_id_type id)
00605 {
00606   this->add_edge (_mesh.elem(e), edge, id);
00607 }
00608 
00609 
00610 
00611 void BoundaryInfo::add_edge(const Elem* elem,
00612                             const unsigned short int edge,
00613                             const boundary_id_type id)
00614 {
00615   libmesh_assert(elem);
00616 
00617   // Only add BCs for level-0 elements.
00618   libmesh_assert_equal_to (elem->level(), 0);
00619 
00620   if (id == invalid_id)
00621     libmesh_error_msg("ERROR: You may not set a boundary ID of "        \
00622                       << invalid_id                                     \
00623                       << "\n That is reserved for internal use.");
00624 
00625   // A convenient typedef
00626   typedef std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00627     const_iterator Iter;
00628 
00629   // Don't add the same ID twice
00630   std::pair<Iter, Iter> pos = _boundary_edge_id.equal_range(elem);
00631 
00632   for (;pos.first != pos.second; ++pos.first)
00633     if (pos.first->second.first == edge &&
00634         pos.first->second.second == id)
00635       return;
00636 
00637   std::pair<unsigned short int, boundary_id_type> p(edge,id);
00638   std::pair<const Elem*, std::pair<unsigned short int, boundary_id_type> >
00639     kv (elem, p);
00640 
00641   _boundary_edge_id.insert(kv);
00642   _boundary_ids.insert(id);
00643   _edge_boundary_ids.insert(id); // Also add this ID to the set of edge boundary IDs
00644 }
00645 
00646 
00647 
00648 void BoundaryInfo::add_edge(const Elem* elem,
00649                             const unsigned short int edge,
00650                             const std::vector<boundary_id_type>& ids)
00651 {
00652   if (ids.empty())
00653     return;
00654 
00655   libmesh_assert(elem);
00656 
00657   // Only add BCs for level-0 elements.
00658   libmesh_assert_equal_to (elem->level(), 0);
00659 
00660   // A convenient typedef
00661   typedef std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00662     const_iterator Iter;
00663 
00664   // Don't add the same ID twice
00665   std::pair<Iter, Iter> pos = _boundary_edge_id.equal_range(elem);
00666 
00667   for (unsigned int i=0; i!= ids.size(); ++i)
00668     {
00669       boundary_id_type id=ids[i];
00670 
00671       if (id == invalid_id)
00672         libmesh_error_msg("ERROR: You may not set a boundary ID of "   \
00673                           << invalid_id                                \
00674                           << "\n That is reserved for internal use.");
00675 
00676       bool already_inserted = false;
00677       for (Iter p = pos.first;p != pos.second; ++p)
00678         if (p->second.first == edge &&
00679             p->second.second == id)
00680           {
00681             already_inserted = true;
00682             break;
00683           }
00684       if (already_inserted)
00685         continue;
00686 
00687       std::pair<unsigned short int, boundary_id_type> p(edge,id);
00688       std::pair<const Elem*, std::pair<unsigned short int, boundary_id_type> >
00689         kv (elem, p);
00690 
00691       _boundary_edge_id.insert(kv);
00692       _boundary_ids.insert(id);
00693       _edge_boundary_ids.insert(id); // Also add this ID to the set of edge boundary IDs
00694     }
00695 }
00696 
00697 void BoundaryInfo::add_side(const dof_id_type e,
00698                             const unsigned short int side,
00699                             const boundary_id_type id)
00700 {
00701   this->add_side (_mesh.elem(e), side, id);
00702 }
00703 
00704 
00705 
00706 void BoundaryInfo::add_side(const Elem* elem,
00707                             const unsigned short int side,
00708                             const boundary_id_type id)
00709 {
00710   libmesh_assert(elem);
00711 
00712   // Only add BCs for level-0 elements.
00713   libmesh_assert_equal_to (elem->level(), 0);
00714 
00715   if (id == invalid_id)
00716     libmesh_error_msg("ERROR: You may not set a boundary ID of "        \
00717                       << invalid_id                                     \
00718                       << "\n That is reserved for internal use.");
00719 
00720   // A convenient typedef
00721   typedef std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00722     const_iterator Iter;
00723 
00724   // Don't add the same ID twice
00725   std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(elem);
00726 
00727   for (;pos.first != pos.second; ++pos.first)
00728     if (pos.first->second.first == side &&
00729         pos.first->second.second == id)
00730       return;
00731 
00732   std::pair<unsigned short int, boundary_id_type> p(side,id);
00733   std::pair<const Elem*, std::pair<unsigned short int, boundary_id_type> >
00734     kv (elem, p);
00735 
00736   _boundary_side_id.insert(kv);
00737   _boundary_ids.insert(id);
00738   _side_boundary_ids.insert(id); // Also add this ID to the set of side boundary IDs
00739 }
00740 
00741 
00742 
00743 void BoundaryInfo::add_side(const Elem* elem,
00744                             const unsigned short int side,
00745                             const std::vector<boundary_id_type>& ids)
00746 {
00747   if (ids.empty())
00748     return;
00749 
00750   libmesh_assert(elem);
00751 
00752   // Only add BCs for level-0 elements.
00753   libmesh_assert_equal_to (elem->level(), 0);
00754 
00755   // A convenient typedef
00756   typedef std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::
00757     const_iterator Iter;
00758 
00759   // Don't add the same ID twice
00760   std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(elem);
00761 
00762   for (unsigned int i=0; i!= ids.size(); ++i)
00763     {
00764       boundary_id_type id=ids[i];
00765 
00766       if (id == invalid_id)
00767         libmesh_error_msg("ERROR: You may not set a boundary ID of "    \
00768                           << invalid_id                                 \
00769                           << "\n That is reserved for internal use.");
00770 
00771       bool already_inserted = false;
00772       for (Iter p = pos.first;p != pos.second; ++p)
00773         if (p->second.first == side &&
00774             p->second.second == id)
00775           {
00776             already_inserted = true;
00777             break;
00778           }
00779       if (already_inserted)
00780         continue;
00781 
00782       std::pair<unsigned short int, boundary_id_type> p(side,id);
00783       std::pair<const Elem*, std::pair<unsigned short int, boundary_id_type> >
00784         kv (elem, p);
00785 
00786       _boundary_side_id.insert(kv);
00787       _boundary_ids.insert(id);
00788       _side_boundary_ids.insert(id); // Also add this ID to the set of side boundary IDs
00789     }
00790 }
00791 
00792 
00793 
00794 bool BoundaryInfo::has_boundary_id(const Node* const node,
00795                                    const boundary_id_type id) const
00796 {
00797   // A convenient typedef
00798   typedef std::multimap<const Node*, boundary_id_type>::const_iterator Iter;
00799 
00800   std::pair<Iter, Iter> pos = _boundary_node_id.equal_range(node);
00801 
00802   for (;pos.first != pos.second; ++pos.first)
00803     if (pos.first->second == id)
00804       return true;
00805 
00806   return false;
00807 }
00808 
00809 
00810 
00811 std::vector<boundary_id_type> BoundaryInfo::boundary_ids(const Node* node) const
00812 {
00813   std::vector<boundary_id_type> ids;
00814 
00815   // A convenient typedef
00816   typedef std::multimap<const Node*, boundary_id_type>::const_iterator Iter;
00817 
00818   std::pair<Iter, Iter> pos = _boundary_node_id.equal_range(node);
00819 
00820   for (;pos.first != pos.second; ++pos.first)
00821     ids.push_back(pos.first->second);
00822 
00823   return ids;
00824 }
00825 
00826 
00827 
00828 unsigned int BoundaryInfo::n_boundary_ids(const Node* node) const
00829 {
00830   // A convenient typedef
00831   typedef std::multimap<const Node*, boundary_id_type>::const_iterator Iter;
00832 
00833   std::pair<Iter, Iter> pos = _boundary_node_id.equal_range(node);
00834 
00835   return cast_int<unsigned int>
00836     (std::distance(pos.first, pos.second));
00837 }
00838 
00839 
00840 
00841 std::vector<boundary_id_type> BoundaryInfo::edge_boundary_ids (const Elem* const elem,
00842                                                                const unsigned short int edge) const
00843 {
00844   libmesh_assert(elem);
00845 
00846   std::vector<boundary_id_type> ids;
00847 
00848   // Only level-0 elements store BCs.  If this is not a level-0
00849   // element get its level-0 parent and infer the BCs.
00850   const Elem* searched_elem = elem;
00851 #ifdef LIBMESH_ENABLE_AMR
00852   if (elem->level() != 0)
00853     {
00854       // Find all the sides that contain edge. If one of those is a boundary
00855       // side, then this must be a boundary edge. In that case, we just use the
00856       // top-level parent.
00857       bool found_boundary_edge = false;
00858       for(unsigned int side=0; side<elem->n_sides(); side++)
00859         {
00860           if(elem->is_edge_on_side(edge,side))
00861             {
00862               if (elem->neighbor(side) == NULL)
00863                 {
00864                   searched_elem = elem->top_parent ();
00865                   found_boundary_edge = true;
00866                   break;
00867                 }
00868             }
00869         }
00870 
00871       if(!found_boundary_edge)
00872         {
00873           // Child element is not on external edge, but it may have internal
00874           // "boundary" IDs.  We will walk up the tree, at each level checking that
00875           // the current child is actually on the same edge of the parent that is
00876           // currently being searched for (i.e. that was passed in as "edge").
00877           while (searched_elem->parent() != NULL)
00878             {
00879               const Elem * parent = searched_elem->parent();
00880               if (parent->is_child_on_edge(parent->which_child_am_i(searched_elem), edge) == false)
00881                 return ids;
00882               searched_elem = parent;
00883             }
00884         }
00885     }
00886 #endif
00887 
00888   std::pair<std::multimap<const Elem*,
00889     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
00890     std::multimap<const Elem*,
00891     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
00892     e = _boundary_edge_id.equal_range(searched_elem);
00893 
00894   // elem not in the data structure
00895   if (e.first == e.second)
00896     return ids;
00897 
00898   // elem is there, maybe multiple occurrences
00899   for (; e.first != e.second; ++e.first)
00900     // if this is true we found the requested edge of the element
00901     if (e.first->second.first == edge)
00902       ids.push_back(e.first->second.second);
00903 
00904   // Whether or not we found anything, return "ids".  If it's empty, it
00905   // means no valid bounary IDs were found for "edge"
00906   return ids;
00907 }
00908 
00909 
00910 
00911 unsigned int BoundaryInfo::n_edge_boundary_ids (const Elem* const elem,
00912                                                 const unsigned short int edge) const
00913 {
00914   libmesh_assert(elem);
00915 
00916   // Only level-0 elements store BCs.  If this is not a level-0
00917   // element get its level-0 parent and infer the BCs.
00918   const Elem* searched_elem = elem;
00919 #ifdef LIBMESH_ENABLE_AMR
00920   if (elem->level() != 0)
00921     {
00922       // Find all the sides that contain edge. If one of those is a boundary
00923       // side, then this must be a boundary edge. In that case, we just use the
00924       // top-level parent.
00925       bool found_boundary_edge = false;
00926       for(unsigned int side=0; side<elem->n_sides(); side++)
00927         {
00928           if(elem->is_edge_on_side(edge,side))
00929             {
00930               if (elem->neighbor(side) == NULL)
00931                 {
00932                   searched_elem = elem->top_parent ();
00933                   found_boundary_edge = true;
00934                   break;
00935                 }
00936             }
00937         }
00938 
00939       if(!found_boundary_edge)
00940         {
00941           // Child element is not on external edge, but it may have internal
00942           // "boundary" IDs.  We will walk up the tree, at each level checking that
00943           // the current child is actually on the same edge of the parent that is
00944           // currently being searched for (i.e. that was passed in as "edge").
00945           while (searched_elem->parent() != NULL)
00946             {
00947               const Elem * parent = searched_elem->parent();
00948               if (parent->is_child_on_edge(parent->which_child_am_i(searched_elem), edge) == false)
00949                 return 0;
00950               searched_elem = parent;
00951             }
00952         }
00953     }
00954 #endif
00955 
00956   std::pair<std::multimap<const Elem*,
00957     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
00958     std::multimap<const Elem*,
00959     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
00960     e = _boundary_edge_id.equal_range(searched_elem);
00961 
00962   unsigned int n_ids = 0;
00963 
00964   // elem is there, maybe multiple occurrences
00965   for (; e.first != e.second; ++e.first)
00966     // if this is true we found the requested edge of the element
00967     if (e.first->second.first == edge)
00968       n_ids++;
00969 
00970   return n_ids;
00971 }
00972 
00973 
00974 
00975 std::vector<boundary_id_type> BoundaryInfo::raw_edge_boundary_ids (const Elem* const elem,
00976                                                                    const unsigned short int edge) const
00977 {
00978   libmesh_assert(elem);
00979 
00980   std::vector<boundary_id_type> ids;
00981 
00982   // Only level-0 elements store BCs.
00983   if (elem->parent())
00984     return ids;
00985 
00986   std::pair<std::multimap<const Elem*,
00987     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
00988     std::multimap<const Elem*,
00989     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
00990     e = _boundary_edge_id.equal_range(elem);
00991 
00992   // Check any occurrences
00993   for (; e.first != e.second; ++e.first)
00994     // if this is true we found the requested edge of the element
00995     if (e.first->second.first == edge)
00996       ids.push_back(e.first->second.second);
00997 
00998   // if nothing got pushed back, we didn't find elem in the data
00999   // structure with the requested edge, so return the default empty
01000   // vector
01001   return ids;
01002 }
01003 
01004 
01005 boundary_id_type BoundaryInfo::boundary_id(const Elem* const elem,
01006                                            const unsigned short int side) const
01007 {
01008   // Asking for just one boundary id means your code isn't safe to use
01009   // on meshes with overlapping boundary ids.  Try using
01010   // BoundaryInfo::boundary_ids or BoundaryInfo::has_boundary_id
01011   // instead.
01012   libmesh_deprecated();
01013 
01014   libmesh_assert(elem);
01015 
01016   // Only level-0 elements store BCs.  If this is not a level-0
01017   // element, one of its parent elements may have either internal
01018   // or external boundary IDs.  We find that parent now.
01019   const Elem*  searched_elem = elem;
01020   if (elem->level() != 0)
01021     {
01022       // Child element on external side: the top_parent will have the BCs
01023       if (elem->neighbor(side) == NULL)
01024         searched_elem = elem->top_parent ();
01025 
01026 #ifdef LIBMESH_ENABLE_AMR
01027       // Child element is not on external side, but it may have internal
01028       // "boundary" IDs.  We will walk up the tree, at each level checking that
01029       // the current child is actually on the same side of the parent that is
01030       // currently being searched for (i.e. that was passed in as "side").
01031       else
01032         while (searched_elem->parent() != NULL)
01033           {
01034             const Elem * parent = searched_elem->parent();
01035             if (parent->is_child_on_side(parent->which_child_am_i(searched_elem), side) == false)
01036               return invalid_id;
01037             searched_elem = parent;
01038           }
01039 #endif
01040     }
01041 
01042   std::pair<std::multimap<const Elem*,
01043     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
01044     std::multimap<const Elem*,
01045     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
01046     e = _boundary_side_id.equal_range(searched_elem);
01047 
01048   // elem not in the data structure
01049   if (e.first == e.second)
01050     return invalid_id;
01051 
01052   // elem is there, maybe multiple occurrences
01053   for (; e.first != e.second; ++e.first)
01054     // if this is true we found the requested side
01055     // of the element and want to return the id
01056     if (e.first->second.first == side)
01057       return e.first->second.second;
01058 
01059   // if we get here, we found elem in the data structure but not
01060   // the requested side, so return the default value
01061   return invalid_id;
01062 }
01063 
01064 
01065 
01066 bool BoundaryInfo::has_boundary_id(const Elem* const elem,
01067                                    const unsigned short int side,
01068                                    const boundary_id_type id) const
01069 {
01070   libmesh_assert(elem);
01071 
01072   // Only level-0 elements store BCs.  If this is not a level-0
01073   // element get its level-0 parent and infer the BCs.
01074   const Elem*  searched_elem = elem;
01075   if (elem->level() != 0)
01076     {
01077       if (elem->neighbor(side) == NULL)
01078         searched_elem = elem->top_parent ();
01079 #ifdef LIBMESH_ENABLE_AMR
01080       else
01081         while (searched_elem->parent() != NULL)
01082           {
01083             const Elem * parent = searched_elem->parent();
01084             if (parent->is_child_on_side(parent->which_child_am_i(searched_elem), side) == false)
01085               return false;
01086             searched_elem = parent;
01087           }
01088 #endif
01089     }
01090 
01091   std::pair<std::multimap<const Elem*,
01092     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
01093     std::multimap<const Elem*,
01094     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
01095     e = _boundary_side_id.equal_range(searched_elem);
01096 
01097   // elem is there, maybe multiple occurrences
01098   for (; e.first != e.second; ++e.first)
01099     // if this is true we found the requested id on this side of the element
01100     if (e.first->second.first == side &&
01101         e.first->second.second == id)
01102       return true;
01103 
01104   return false;
01105 }
01106 
01107 
01108 
01109 std::vector<boundary_id_type> BoundaryInfo::boundary_ids (const Elem* const elem,
01110                                                           const unsigned short int side) const
01111 {
01112   libmesh_assert(elem);
01113 
01114   std::vector<boundary_id_type> ids;
01115 
01116   // Only level-0 elements store BCs.  If this is not a level-0
01117   // element get its level-0 parent and infer the BCs.
01118   const Elem*  searched_elem = elem;
01119   if (elem->level() != 0)
01120     {
01121       if (elem->neighbor(side) == NULL)
01122         searched_elem = elem->top_parent ();
01123 #ifdef LIBMESH_ENABLE_AMR
01124       else
01125         while (searched_elem->parent() != NULL)
01126           {
01127             const Elem * parent = searched_elem->parent();
01128             if (parent->is_child_on_side(parent->which_child_am_i(searched_elem), side) == false)
01129               return ids;
01130             searched_elem = parent;
01131           }
01132 #endif
01133     }
01134 
01135   std::pair<std::multimap<const Elem*,
01136     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
01137     std::multimap<const Elem*,
01138     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
01139     e = _boundary_side_id.equal_range(searched_elem);
01140 
01141   // elem not in the data structure
01142   if (e.first == e.second)
01143     return ids;
01144 
01145   // elem is there, maybe multiple occurrences
01146   for (; e.first != e.second; ++e.first)
01147     // if this is true we found the requested side of the element
01148     if (e.first->second.first == side)
01149       ids.push_back(e.first->second.second);
01150 
01151   // Whether or not we found anything, return "ids".  If it's empty, it
01152   // means no valid bounary IDs were found for "side"
01153   return ids;
01154 }
01155 
01156 
01157 
01158 unsigned int BoundaryInfo::n_boundary_ids (const Elem* const elem,
01159                                            const unsigned short int side) const
01160 {
01161   libmesh_assert(elem);
01162 
01163   // Only level-0 elements store BCs.  If this is not a level-0
01164   // element get its level-0 parent and infer the BCs.
01165   const Elem*  searched_elem = elem;
01166   if (elem->level() != 0)
01167     {
01168       if (elem->neighbor(side) == NULL)
01169         searched_elem = elem->top_parent ();
01170 #ifdef LIBMESH_ENABLE_AMR
01171       else
01172         while (searched_elem->parent() != NULL)
01173           {
01174             const Elem * parent = searched_elem->parent();
01175             if (parent->is_child_on_side(parent->which_child_am_i(searched_elem), side) == false)
01176               return 0;
01177             searched_elem = parent;
01178           }
01179 #endif
01180     }
01181 
01182   std::pair<std::multimap<const Elem*,
01183     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
01184     std::multimap<const Elem*,
01185     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
01186     e = _boundary_side_id.equal_range(searched_elem);
01187 
01188   unsigned int n_ids = 0;
01189 
01190   // elem is there, maybe multiple occurrences
01191   for (; e.first != e.second; ++e.first)
01192     // if this is true we found the requested side of the element
01193     if (e.first->second.first == side)
01194       n_ids++;
01195 
01196   return n_ids;
01197 }
01198 
01199 
01200 
01201 std::vector<boundary_id_type> BoundaryInfo::raw_boundary_ids (const Elem* const elem,
01202                                                               const unsigned short int side) const
01203 {
01204   libmesh_assert(elem);
01205 
01206   std::vector<boundary_id_type> ids;
01207 
01208   // Only level-0 elements store BCs.
01209   if (elem->parent())
01210     return ids;
01211 
01212   std::pair<std::multimap<const Elem*,
01213     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
01214     std::multimap<const Elem*,
01215     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
01216     e = _boundary_side_id.equal_range(elem);
01217 
01218   // Check any occurrences
01219   for (; e.first != e.second; ++e.first)
01220     // if this is true we found the requested side of the element
01221     if (e.first->second.first == side)
01222       ids.push_back(e.first->second.second);
01223 
01224   // if nothing got pushed back, we didn't find elem in the data
01225   // structure with the requested side, so return the default empty
01226   // vector
01227   return ids;
01228 }
01229 
01230 
01231 void BoundaryInfo::remove_edge (const Elem* elem,
01232                                 const unsigned short int edge)
01233 {
01234   libmesh_assert(elem);
01235 
01236   // The user shouldn't be trying to remove only one child's boundary
01237   // id
01238   libmesh_assert_equal_to (elem->level(), 0);
01239 
01240   std::pair<std::multimap<const Elem*,
01241     std::pair<unsigned short int, boundary_id_type> >::iterator,
01242     std::multimap<const Elem*,
01243     std::pair<unsigned short int, boundary_id_type> >::iterator >
01244     e = _boundary_edge_id.equal_range(elem);
01245 
01246   // elem may be there, maybe multiple occurrences
01247   while (e.first != e.second)
01248     {
01249       // if this is true we found the requested edge
01250       // of the element and want to erase the id
01251       if (e.first->second.first == edge)
01252         {
01253           // (postfix++ - increment the iterator before it's invalid)
01254           _boundary_edge_id.erase(e.first++);
01255         }
01256       else
01257         ++e.first;
01258     }
01259 }
01260 
01261 
01262 
01263 void BoundaryInfo::remove_edge (const Elem* elem,
01264                                 const unsigned short int edge,
01265                                 const boundary_id_type id)
01266 {
01267   libmesh_assert(elem);
01268 
01269   // The user shouldn't be trying to remove only one child's boundary
01270   // id
01271   libmesh_assert_equal_to (elem->level(), 0);
01272 
01273   std::pair<std::multimap<const Elem*,
01274     std::pair<unsigned short int, boundary_id_type> >::iterator,
01275     std::multimap<const Elem*,
01276     std::pair<unsigned short int, boundary_id_type> >::iterator >
01277     e = _boundary_edge_id.equal_range(elem);
01278 
01279   // elem may be there, maybe multiple occurrences
01280   while (e.first != e.second)
01281     {
01282       // if this is true we found the requested edge
01283       // of the element and want to erase the requested id
01284       if (e.first->second.first == edge &&
01285           e.first->second.second == id)
01286         {
01287           // (postfix++ - increment the iterator before it's invalid)
01288           _boundary_edge_id.erase(e.first++);
01289         }
01290       else
01291         ++e.first;
01292     }
01293 }
01294 
01295 void BoundaryInfo::remove_side (const Elem* elem,
01296                                 const unsigned short int side)
01297 {
01298   libmesh_assert(elem);
01299 
01300   // The user shouldn't be trying to remove only one child's boundary
01301   // id
01302   libmesh_assert_equal_to (elem->level(), 0);
01303 
01304   std::pair<std::multimap<const Elem*,
01305     std::pair<unsigned short int, boundary_id_type> >::iterator,
01306     std::multimap<const Elem*,
01307     std::pair<unsigned short int, boundary_id_type> >::iterator >
01308     e = _boundary_side_id.equal_range(elem);
01309 
01310   // elem may be there, maybe multiple occurrences
01311   while (e.first != e.second)
01312     {
01313       // if this is true we found the requested side
01314       // of the element and want to erase the id
01315       if (e.first->second.first == side)
01316         {
01317           // (postfix++ - increment the iterator before it's invalid)
01318           _boundary_side_id.erase(e.first++);
01319         }
01320       else
01321         ++e.first;
01322     }
01323 }
01324 
01325 
01326 
01327 void BoundaryInfo::remove_side (const Elem* elem,
01328                                 const unsigned short int side,
01329                                 const boundary_id_type id)
01330 {
01331   libmesh_assert(elem);
01332 
01333   // The user shouldn't be trying to remove only one child's boundary
01334   // id
01335   libmesh_assert_equal_to (elem->level(), 0);
01336 
01337   std::pair<std::multimap<const Elem*,
01338     std::pair<unsigned short int, boundary_id_type> >::iterator,
01339     std::multimap<const Elem*,
01340     std::pair<unsigned short int, boundary_id_type> >::iterator >
01341     e = _boundary_side_id.equal_range(elem);
01342 
01343   // elem may be there, maybe multiple occurrences
01344   while (e.first != e.second)
01345     {
01346       // if this is true we found the requested side
01347       // of the element and want to erase the requested id
01348       if (e.first->second.first == side &&
01349           e.first->second.second == id)
01350         {
01351           // (postfix++ - increment the iterator before it's invalid)
01352           _boundary_side_id.erase(e.first++);
01353         }
01354       else
01355         ++e.first;
01356     }
01357 }
01358 
01359 
01360 
01361 unsigned int BoundaryInfo::side_with_boundary_id(const Elem* const elem,
01362                                                  const boundary_id_type boundary_id_in) const
01363 {
01364   const Elem* searched_elem = elem;
01365   if (elem->level() != 0)
01366     searched_elem = elem->top_parent();
01367 
01368   std::pair<std::multimap<const Elem*,
01369     std::pair<unsigned short int, boundary_id_type> >::const_iterator,
01370     std::multimap<const Elem*,
01371     std::pair<unsigned short int, boundary_id_type> >::const_iterator >
01372     e = _boundary_side_id.equal_range(searched_elem);
01373 
01374   // elem may have zero or multiple occurrences
01375   for (; e.first != e.second; ++e.first)
01376     {
01377       // if this is true we found the requested boundary_id
01378       // of the element and want to return the side
01379       if (e.first->second.second == boundary_id_in)
01380         {
01381           unsigned int side = e.first->second.first;
01382 
01383           // If we're on this external boundary then we share this
01384           // external boundary id
01385           if (elem->neighbor(side) == NULL)
01386             return side;
01387 
01388           // If we're on an internal boundary then we need to be sure
01389           // it's the same internal boundary as our top_parent
01390           const Elem *p = elem;
01391 
01392 #ifdef LIBMESH_ENABLE_AMR
01393 
01394           while (p != NULL)
01395             {
01396               const Elem *parent = p->parent();
01397               if (!parent->is_child_on_side(parent->which_child_am_i(p), side))
01398                 break;
01399               p = parent;
01400             }
01401 #endif
01402           // We're on that side of our top_parent; return it
01403           if (!p)
01404             return side;
01405         }
01406     }
01407 
01408   // if we get here, we found elem in the data structure but not
01409   // the requested boundary id, so return the default value
01410   return libMesh::invalid_uint;
01411 }
01412 
01413 void
01414 BoundaryInfo::build_node_boundary_ids(std::vector<boundary_id_type> &b_ids) const
01415 {
01416   b_ids.clear();
01417 
01418   std::multimap<const Node*, boundary_id_type>::const_iterator pos
01419     = _boundary_node_id.begin();
01420 
01421   for (; pos != _boundary_node_id.end(); ++pos)
01422     {
01423       boundary_id_type id = pos->second;
01424 
01425       if(std::find(b_ids.begin(),b_ids.end(),id) == b_ids.end())
01426         b_ids.push_back(id);
01427     }
01428 }
01429 
01430 void
01431 BoundaryInfo::build_side_boundary_ids(std::vector<boundary_id_type> &b_ids) const
01432 {
01433   b_ids.clear();
01434 
01435   std::multimap<const Elem*, std::pair<unsigned short int, boundary_id_type> >::const_iterator pos
01436     = _boundary_side_id.begin();
01437 
01438   for (; pos != _boundary_side_id.end(); ++pos)
01439     {
01440       boundary_id_type id = pos->second.second;
01441 
01442       if(std::find(b_ids.begin(),b_ids.end(),id) == b_ids.end())
01443         b_ids.push_back(id);
01444     }
01445 }
01446 
01447 std::size_t BoundaryInfo::n_boundary_conds () const
01448 {
01449   // in serial we know the number of bcs from the
01450   // size of the container
01451   if (_mesh.is_serial())
01452     return _boundary_side_id.size();
01453 
01454   // in parallel we need to sum the number of local bcs
01455   parallel_object_only();
01456 
01457   std::size_t nbcs=0;
01458 
01459   std::multimap<const Elem*,
01460     std::pair<unsigned short int,
01461     boundary_id_type> >::const_iterator pos;
01462 
01463   for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end(); ++pos)
01464     if (pos->first->processor_id() == this->processor_id())
01465       nbcs++;
01466 
01467   this->comm().sum (nbcs);
01468 
01469   return nbcs;
01470 }
01471 
01472 std::size_t BoundaryInfo::n_edge_conds () const
01473 {
01474   // in serial we know the number of nodesets from the
01475   // size of the container
01476   if (_mesh.is_serial())
01477     return _boundary_edge_id.size();
01478 
01479   // in parallel we need to sum the number of local nodesets
01480   parallel_object_only();
01481 
01482   std::size_t n_edge_bcs=0;
01483 
01484   std::multimap<const Elem*,
01485     std::pair<unsigned short int,
01486     boundary_id_type> >::const_iterator pos;
01487 
01488   for (pos=_boundary_edge_id.begin(); pos != _boundary_edge_id.end(); ++pos)
01489     if (pos->first->processor_id() == this->processor_id())
01490       n_edge_bcs++;
01491 
01492   this->comm().sum (n_edge_bcs);
01493 
01494   return n_edge_bcs;
01495 }
01496 
01497 
01498 std::size_t BoundaryInfo::n_nodeset_conds () const
01499 {
01500   // in serial we know the number of nodesets from the
01501   // size of the container
01502   if (_mesh.is_serial())
01503     return _boundary_node_id.size();
01504 
01505   // in parallel we need to sum the number of local nodesets
01506   parallel_object_only();
01507 
01508   std::size_t n_nodesets=0;
01509 
01510   std::multimap<const Node*, boundary_id_type>::const_iterator pos;
01511 
01512   for (pos=_boundary_node_id.begin(); pos != _boundary_node_id.end(); ++pos)
01513     if (pos->first->processor_id() == this->processor_id())
01514       n_nodesets++;
01515 
01516   this->comm().sum (n_nodesets);
01517 
01518   return n_nodesets;
01519 }
01520 
01521 
01522 
01523 void BoundaryInfo::build_node_list (std::vector<dof_id_type>& nl,
01524                                     std::vector<boundary_id_type>&    il) const
01525 {
01526   // Reserve the size, then use push_back
01527   nl.reserve (_boundary_node_id.size());
01528   il.reserve (_boundary_node_id.size());
01529 
01530   std::multimap<const Node*, boundary_id_type>::const_iterator pos
01531     = _boundary_node_id.begin();
01532 
01533   for (; pos != _boundary_node_id.end(); ++pos)
01534     {
01535       nl.push_back (pos->first->id());
01536       il.push_back (pos->second);
01537     }
01538 }
01539 
01540 
01541 void
01542 BoundaryInfo::build_node_list_from_side_list()
01543 {
01544   std::multimap<const Elem*,
01545     std::pair<unsigned short int,
01546     boundary_id_type> >::const_iterator pos;
01547 
01548   //Loop over the side list
01549   for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end(); ++pos)
01550     {
01551       // Don't add remote sides
01552       if(pos->first->is_remote())
01553         continue;
01554 
01555       //Need to loop over the sides of any possible children
01556       std::vector< const Elem * > family;
01557 #ifdef LIBMESH_ENABLE_AMR
01558       pos->first->active_family_tree_by_side (family, pos->second.first);
01559 #else
01560       family.push_back(pos->first);
01561 #endif
01562 
01563       for(std::size_t elem_it=0; elem_it < family.size(); elem_it++)
01564         {
01565           const Elem * cur_elem = family[elem_it];
01566 
01567           UniquePtr<Elem> side = cur_elem->build_side(pos->second.first);
01568 
01569           //Add each node node on the side with the side's boundary id
01570           for(unsigned int i=0; i<side->n_nodes(); i++)
01571             {
01572               Node * node = side->get_node(i);
01573 
01574               this->add_node(node, pos->second.second);
01575             }
01576         }
01577     }
01578 }
01579 
01580 
01581 
01582 
01583 void BoundaryInfo::build_side_list_from_node_list()
01584 {
01585   // Check for early return
01586   if (_boundary_node_id.empty())
01587     {
01588       libMesh::out << "No boundary node IDs have been added: cannot build side list!" << std::endl;
01589       return;
01590     }
01591 
01592   // typedef for less typing!
01593   typedef std::multimap<const Node*, boundary_id_type>::const_iterator iterator_t;
01594 
01595   // Return value and iterator for equal_range()
01596   iterator_t pos;
01597   std::pair<iterator_t, iterator_t> range;
01598 
01599   MeshBase::const_element_iterator el = _mesh.active_elements_begin();
01600   const MeshBase::const_element_iterator end_el = _mesh.active_elements_end();
01601 
01602   for (; el != end_el; ++el)
01603     {
01604       const Elem* elem = *el;
01605 
01606       for (unsigned short side=0; side<elem->n_sides(); ++side)
01607         {
01608           UniquePtr<Elem> side_elem = elem->build_side(side);
01609 
01610           // map from nodeset_id to count for that ID
01611           std::map<boundary_id_type, unsigned> nodesets_node_count;
01612           for (unsigned node_num=0; node_num < side_elem->n_nodes(); ++node_num)
01613             {
01614               Node* node = side_elem->get_node(node_num);
01615               range = _boundary_node_id.equal_range(node);
01616 
01617               // For each nodeset that this node is a member of, increment the associated
01618               // nodeset ID count
01619               for (pos = range.first; pos != range.second; ++pos)
01620                 nodesets_node_count[pos->second]++;
01621             }
01622 
01623           // Now check to see what nodeset_counts have the correct
01624           // number of nodes in them.  For any that do, add this side to
01625           // the sideset, making sure the sideset inherits the
01626           // nodeset's name, if there is one.
01627           std::map<boundary_id_type, unsigned>::const_iterator nodesets = nodesets_node_count.begin();
01628           for (; nodesets != nodesets_node_count.end(); ++nodesets)
01629             if (nodesets->second == side_elem->n_nodes())
01630               {
01631                 add_side(elem, side, nodesets->first);
01632 
01633                 // Let the sideset inherit any non-empty name from the nodeset
01634                 std::string& nset_name = nodeset_name(nodesets->first);
01635 
01636                 if (nset_name != "")
01637                   sideset_name(nodesets->first) = nset_name;
01638               }
01639         } // end for side
01640     } // end for el
01641 }
01642 
01643 
01644 
01645 
01646 void BoundaryInfo::build_side_list (std::vector<dof_id_type>&        el,
01647                                     std::vector<unsigned short int>& sl,
01648                                     std::vector<boundary_id_type>&   il) const
01649 {
01650   // Reserve the size, then use push_back
01651   el.reserve (_boundary_side_id.size());
01652   sl.reserve (_boundary_side_id.size());
01653   il.reserve (_boundary_side_id.size());
01654 
01655   std::multimap<const Elem*,
01656     std::pair<unsigned short int,
01657     boundary_id_type> >::const_iterator pos;
01658 
01659   for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end();
01660        ++pos)
01661     {
01662       el.push_back (pos->first->id());
01663       sl.push_back (pos->second.first);
01664       il.push_back (pos->second.second);
01665     }
01666 }
01667 
01668 void BoundaryInfo::build_active_side_list (std::vector<dof_id_type>&        el,
01669                                            std::vector<unsigned short int>& sl,
01670                                            std::vector<boundary_id_type>&   il) const
01671 {
01672   std::multimap<const Elem*,
01673     std::pair<unsigned short int,
01674     boundary_id_type> >::const_iterator pos;
01675 
01676   for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end();
01677        ++pos)
01678     {
01679       // Don't add remote sides
01680       if (pos->first->is_remote())
01681         continue;
01682 
01683       // Loop over the sides of possible children
01684       std::vector< const Elem * > family;
01685 #ifdef LIBMESH_ENABLE_AMR
01686       pos->first->active_family_tree_by_side(family, pos->second.first);
01687 #else
01688       family.push_back(pos->first);
01689 #endif
01690 
01691       // Populate the list items
01692       for (std::vector<const Elem *>::iterator elem_it = family.begin(); elem_it != family.end(); elem_it++)
01693         {
01694           el.push_back ((*elem_it)->id());
01695           sl.push_back (pos->second.first);
01696           il.push_back (pos->second.second);
01697         }
01698     }
01699 }
01700 
01701 
01702 void BoundaryInfo::build_edge_list (std::vector<dof_id_type>&        el,
01703                                     std::vector<unsigned short int>& sl,
01704                                     std::vector<boundary_id_type>&   il) const
01705 {
01706   // Reserve the size, then use push_back
01707   el.reserve (_boundary_side_id.size());
01708   sl.reserve (_boundary_side_id.size());
01709   il.reserve (_boundary_side_id.size());
01710 
01711   std::multimap<const Elem*,
01712     std::pair<unsigned short int,
01713     boundary_id_type> >::const_iterator pos;
01714 
01715   for (pos=_boundary_edge_id.begin(); pos != _boundary_edge_id.end();
01716        ++pos)
01717     {
01718       el.push_back (pos->first->id());
01719       sl.push_back (pos->second.first);
01720       il.push_back (pos->second.second);
01721     }
01722 }
01723 
01724 
01725 void BoundaryInfo::print_info(std::ostream& out_stream) const
01726 {
01727   // Print out the nodal BCs
01728   if (!_boundary_node_id.empty())
01729     {
01730       out_stream << "Nodal Boundary conditions:" << std::endl
01731                  << "--------------------------" << std::endl
01732                  << "  (Node No., ID)               " << std::endl;
01733 
01734       //       std::for_each(_boundary_node_id.begin(),
01735       //    _boundary_node_id.end(),
01736       //    PrintNodeInfo());
01737 
01738       std::multimap<const Node*, boundary_id_type>::const_iterator it        = _boundary_node_id.begin();
01739       const std::multimap<const Node*, boundary_id_type>::const_iterator end = _boundary_node_id.end();
01740 
01741       for (; it != end; ++it)
01742         out_stream << "  (" << (*it).first->id()
01743                    << ", "  << (*it).second
01744                    << ")"  << std::endl;
01745     }
01746 
01747   // Print out the element edge BCs
01748   if (!_boundary_edge_id.empty())
01749     {
01750       out_stream << std::endl
01751                  << "Edge Boundary conditions:" << std::endl
01752                  << "-------------------------" << std::endl
01753                  << "  (Elem No., Edge No., ID)      " << std::endl;
01754 
01755       //       std::for_each(_boundary_edge_id.begin(),
01756       //    _boundary_edge_id.end(),
01757       //    PrintSideInfo());
01758 
01759       std::multimap<const Elem*,
01760         std::pair<unsigned short int, boundary_id_type> >::const_iterator it = _boundary_edge_id.begin();
01761       const std::multimap<const Elem*,
01762         std::pair<unsigned short int, boundary_id_type> >::const_iterator end = _boundary_edge_id.end();
01763 
01764       for (; it != end; ++it)
01765         out_stream << "  (" << (*it).first->id()
01766                    << ", "  << (*it).second.first
01767                    << ", "  << (*it).second.second
01768                    << ")"   << std::endl;
01769     }
01770 
01771   // Print out the element side BCs
01772   if (!_boundary_side_id.empty())
01773     {
01774       out_stream << std::endl
01775                  << "Side Boundary conditions:" << std::endl
01776                  << "-------------------------" << std::endl
01777                  << "  (Elem No., Side No., ID)      " << std::endl;
01778 
01779       //       std::for_each(_boundary_side_id.begin(),
01780       //    _boundary_side_id.end(),
01781       //    PrintSideInfo());
01782 
01783       std::multimap<const Elem*,
01784         std::pair<unsigned short int, boundary_id_type> >::const_iterator it = _boundary_side_id.begin();
01785       const std::multimap<const Elem*,
01786         std::pair<unsigned short int, boundary_id_type> >::const_iterator end = _boundary_side_id.end();
01787 
01788       for (; it != end; ++it)
01789         out_stream << "  (" << (*it).first->id()
01790                    << ", "  << (*it).second.first
01791                    << ", "  << (*it).second.second
01792                    << ")"   << std::endl;
01793     }
01794 }
01795 
01796 
01797 
01798 void BoundaryInfo::print_summary(std::ostream& out_stream) const
01799 {
01800   // Print out the nodal BCs
01801   if (!_boundary_node_id.empty())
01802     {
01803       out_stream << "Nodal Boundary conditions:" << std::endl
01804                  << "--------------------------" << std::endl
01805                  << "  (ID, number of nodes)   " << std::endl;
01806 
01807       std::map<boundary_id_type, std::size_t> ID_counts;
01808 
01809       std::multimap<const Node*, boundary_id_type>::const_iterator it        = _boundary_node_id.begin();
01810       const std::multimap<const Node*, boundary_id_type>::const_iterator end = _boundary_node_id.end();
01811 
01812       for (; it != end; ++it)
01813         ID_counts[(*it).second]++;
01814 
01815       std::map<boundary_id_type, std::size_t>::const_iterator ID_it        = ID_counts.begin();
01816       const std::map<boundary_id_type, std::size_t>::const_iterator ID_end = ID_counts.end();
01817 
01818       for (; ID_it != ID_end; ++ID_it)
01819         out_stream << "  (" << (*ID_it).first
01820                    << ", "  << (*ID_it).second
01821                    << ")"  << std::endl;
01822     }
01823 
01824   // Print out the element edge BCs
01825   if (!_boundary_edge_id.empty())
01826     {
01827       out_stream << std::endl
01828                  << "Edge Boundary conditions:" << std::endl
01829                  << "-------------------------" << std::endl
01830                  << "  (ID, number of edges)   " << std::endl;
01831 
01832       std::map<boundary_id_type, std::size_t> ID_counts;
01833 
01834       std::multimap<const Elem*,
01835         std::pair<unsigned short int, boundary_id_type> >::const_iterator it = _boundary_edge_id.begin();
01836       const std::multimap<const Elem*,
01837         std::pair<unsigned short int, boundary_id_type> >::const_iterator end = _boundary_edge_id.end();
01838 
01839       for (; it != end; ++it)
01840         ID_counts[(*it).second.second]++;
01841 
01842       std::map<boundary_id_type, std::size_t>::const_iterator ID_it        = ID_counts.begin();
01843       const std::map<boundary_id_type, std::size_t>::const_iterator ID_end = ID_counts.end();
01844 
01845       for (; ID_it != ID_end; ++ID_it)
01846         out_stream << "  (" << (*ID_it).first
01847                    << ", "  << (*ID_it).second
01848                    << ")"  << std::endl;
01849     }
01850 
01851   // Print out the element side BCs
01852   if (!_boundary_side_id.empty())
01853     {
01854       out_stream << std::endl
01855                  << "Side Boundary conditions:" << std::endl
01856                  << "-------------------------" << std::endl
01857                  << "  (ID, number of sides)   " << std::endl;
01858 
01859       std::map<boundary_id_type, std::size_t> ID_counts;
01860 
01861       std::multimap<const Elem*,
01862         std::pair<unsigned short int, boundary_id_type> >::const_iterator it = _boundary_side_id.begin();
01863       const std::multimap<const Elem*,
01864         std::pair<unsigned short int, boundary_id_type> >::const_iterator end = _boundary_side_id.end();
01865 
01866       for (; it != end; ++it)
01867         ID_counts[(*it).second.second]++;
01868 
01869       std::map<boundary_id_type, std::size_t>::const_iterator ID_it        = ID_counts.begin();
01870       const std::map<boundary_id_type, std::size_t>::const_iterator ID_end = ID_counts.end();
01871 
01872       for (; ID_it != ID_end; ++ID_it)
01873         out_stream << "  (" << (*ID_it).first
01874                    << ", "  << (*ID_it).second
01875                    << ")"  << std::endl;
01876     }
01877 }
01878 
01879 
01880 const std::string& BoundaryInfo::get_sideset_name(boundary_id_type id) const
01881 {
01882   static const std::string empty_string;
01883   std::map<boundary_id_type, std::string>::const_iterator it =
01884     _ss_id_to_name.find(id);
01885   if (it == _ss_id_to_name.end())
01886     return empty_string;
01887   else
01888     return it->second;
01889 }
01890 
01891 
01892 std::string& BoundaryInfo::sideset_name(boundary_id_type id)
01893 {
01894   return _ss_id_to_name[id];
01895 }
01896 
01897 const std::string& BoundaryInfo::get_nodeset_name(boundary_id_type id) const
01898 {
01899   static const std::string empty_string;
01900   std::map<boundary_id_type, std::string>::const_iterator it =
01901     _ns_id_to_name.find(id);
01902   if (it == _ns_id_to_name.end())
01903     return empty_string;
01904   else
01905     return it->second;
01906 }
01907 
01908 std::string& BoundaryInfo::nodeset_name(boundary_id_type id)
01909 {
01910   return _ns_id_to_name[id];
01911 }
01912 
01913 boundary_id_type BoundaryInfo::get_id_by_name(const std::string& name) const
01914 {
01915   // Search sidesets
01916   std::map<boundary_id_type, std::string>::const_iterator
01917     iter = _ss_id_to_name.begin(),
01918     end_iter = _ss_id_to_name.end();
01919 
01920   for (; iter != end_iter; ++iter)
01921     if (iter->second == name)
01922       return iter->first;
01923 
01924   // Search nodesets
01925   iter = _ns_id_to_name.begin();
01926   end_iter = _ns_id_to_name.end();
01927   for (; iter != end_iter; ++iter)
01928     if (iter->second == name)
01929       return iter->first;
01930 
01931   // If we made it here without returning, we don't have a sideset or
01932   // nodeset by the requested name, so return invalid_id
01933   return invalid_id;
01934 }
01935 
01936 } // namespace libMesh