$extrastylesheet
serial_mesh.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 // Local includes
00021 #include "libmesh/boundary_info.h"
00022 #include "libmesh/elem.h"
00023 #include "libmesh/libmesh_logging.h"
00024 #include "libmesh/metis_partitioner.h"
00025 #include "libmesh/serial_mesh.h"
00026 #include "libmesh/utility.h"
00027 
00028 #include LIBMESH_INCLUDE_UNORDERED_MAP
00029 #include LIBMESH_INCLUDE_UNORDERED_SET
00030 LIBMESH_DEFINE_HASH_POINTERS
00031 
00032 
00033 namespace
00034 {
00035 using namespace libMesh;
00036 
00037 // A custom comparison function, based on Point::operator<,
00038 // that tries to ignore floating point differences in components
00039 // of the point
00040 class FuzzyPointCompare
00041 {
00042 private:
00043   Real _tol;
00044 
00045 public:
00046   // Constructor takes the tolerance to be used in fuzzy comparisons
00047   FuzzyPointCompare(Real tol) : _tol(tol) {}
00048 
00049   // This is inspired directly by Point::operator<
00050   bool operator()(const Point& lhs, const Point& rhs)
00051   {
00052     for (unsigned i=0; i<LIBMESH_DIM; ++i)
00053       {
00054         // If the current components are within some tolerance
00055         // of one another, then don't attempt the less-than comparison.
00056         // Note that this may cause something strange to happen, as Roy
00057         // believes he can prove it is not a total ordering...
00058         Real rel_size = std::max(std::abs(lhs(i)), std::abs(rhs(i)));
00059 
00060         // Don't use relative tolerance if both numbers are already small.
00061         // How small?  Some possible options are:
00062         // * std::numeric_limits<Real>::epsilon()
00063         // * TOLERANCE
00064         // * 1.0
00065         // If we use std::numeric_limits<Real>::epsilon(), we'll
00066         // do more relative comparisons for small numbers, but
00067         // increase the chance for false positives?  If we pick 1.0,
00068         // we'll never "increase" the difference between small numbers
00069         // in the test below.
00070         if (rel_size < 1.)
00071           rel_size = 1.;
00072 
00073         // Don't attempt the comparison if lhs(i) and rhs(i) are too close
00074         // together.
00075         if ( std::abs(lhs(i) - rhs(i)) / rel_size < _tol)
00076           continue;
00077 
00078         if (lhs(i) < rhs(i))
00079           return true;
00080         if (lhs(i) > rhs(i))
00081           return false;
00082       }
00083 
00084     // We compared all the components without returning yet, so
00085     // each component was neither greater than nor less than they other.
00086     // They might be equal, so return false.
00087     return false;
00088   }
00089 
00090   // Needed by std::sort on vector< pair<Point,id> >
00091   bool operator()(const std::pair<Point, dof_id_type>& lhs,
00092                   const std::pair<Point, dof_id_type>& rhs)
00093   {
00094     return (*this)(lhs.first, rhs.first);
00095   }
00096 
00097   // Comparsion function where lhs is a Point and rhs is a pair<Point,dof_id_type>.
00098   // This is used in routines like lower_bound, where a specific value is being
00099   // searched for.
00100   bool operator()(const Point& lhs, std::pair<Point, dof_id_type>& rhs)
00101   {
00102     return (*this)(lhs, rhs.first);
00103   }
00104 
00105   // And the other way around...
00106   bool operator()(std::pair<Point, dof_id_type>& lhs, const Point& rhs)
00107   {
00108     return (*this)(lhs.first, rhs);
00109   }
00110 };
00111 }
00112 
00113 
00114 
00115 namespace libMesh
00116 {
00117 
00118 // ------------------------------------------------------------
00119 // SerialMesh class member functions
00120 SerialMesh::SerialMesh (const Parallel::Communicator &comm_in,
00121                         unsigned char d) :
00122   UnstructuredMesh (comm_in,d)
00123 {
00124 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00125   // In serial we just need to reset the next unique id to zero
00126   // here in the constructor.
00127   _next_unique_id = 0;
00128 #endif
00129   _partitioner = UniquePtr<Partitioner>(new MetisPartitioner());
00130 }
00131 
00132 
00133 
00134 #ifndef LIBMESH_DISABLE_COMMWORLD
00135 SerialMesh::SerialMesh (unsigned char d) :
00136   UnstructuredMesh (d)
00137 {
00138 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00139   // In serial we just need to reset the next unique id to zero
00140   // here in the constructor.
00141   _next_unique_id = 0;
00142 #endif
00143   _partitioner = UniquePtr<Partitioner>(new MetisPartitioner());
00144 }
00145 #endif
00146 
00147 
00148 SerialMesh::~SerialMesh ()
00149 {
00150   this->clear();  // Free nodes and elements
00151 }
00152 
00153 
00154 // This might be specialized later, but right now it's just here to
00155 // make sure the compiler doesn't give us a default (non-deep) copy
00156 // constructor instead.
00157 SerialMesh::SerialMesh (const SerialMesh &other_mesh) :
00158   UnstructuredMesh (other_mesh)
00159 {
00160   this->copy_nodes_and_elements(other_mesh);
00161   this->get_boundary_info() = other_mesh.get_boundary_info();
00162 }
00163 
00164 
00165 SerialMesh::SerialMesh (const UnstructuredMesh &other_mesh) :
00166   UnstructuredMesh (other_mesh)
00167 {
00168   this->copy_nodes_and_elements(other_mesh);
00169   this->get_boundary_info() = other_mesh.get_boundary_info();
00170 }
00171 
00172 
00173 const Point& SerialMesh::point (const dof_id_type i) const
00174 {
00175   libmesh_assert_less (i, this->n_nodes());
00176   libmesh_assert(_nodes[i]);
00177   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
00178 
00179   return (*_nodes[i]);
00180 }
00181 
00182 
00183 
00184 
00185 
00186 const Node& SerialMesh::node (const dof_id_type i) const
00187 {
00188   libmesh_assert_less (i, this->n_nodes());
00189   libmesh_assert(_nodes[i]);
00190   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
00191 
00192   return (*_nodes[i]);
00193 }
00194 
00195 
00196 
00197 
00198 
00199 Node& SerialMesh::node (const dof_id_type i)
00200 {
00201   if (i >= this->n_nodes())
00202     libmesh_error_msg(" i=" << i << ", n_nodes()=" << this->n_nodes());
00203 
00204   libmesh_assert_less (i, this->n_nodes());
00205   libmesh_assert(_nodes[i]);
00206   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
00207 
00208   return (*_nodes[i]);
00209 }
00210 
00211 
00212 
00213 const Node* SerialMesh::node_ptr (const dof_id_type i) const
00214 {
00215   libmesh_assert_less (i, this->n_nodes());
00216   libmesh_assert(_nodes[i]);
00217   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
00218 
00219   return _nodes[i];
00220 }
00221 
00222 
00223 
00224 
00225 Node* SerialMesh::node_ptr (const dof_id_type i)
00226 {
00227   libmesh_assert_less (i, this->n_nodes());
00228   libmesh_assert(_nodes[i]);
00229   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
00230 
00231   return _nodes[i];
00232 }
00233 
00234 
00235 
00236 
00237 const Node* SerialMesh::query_node_ptr (const dof_id_type i) const
00238 {
00239   if (i >= this->n_nodes())
00240     return NULL;
00241   libmesh_assert (_nodes[i] == NULL ||
00242                   _nodes[i]->id() == i); // This will change soon
00243 
00244   return _nodes[i];
00245 }
00246 
00247 
00248 
00249 
00250 Node* SerialMesh::query_node_ptr (const dof_id_type i)
00251 {
00252   if (i >= this->n_nodes())
00253     return NULL;
00254   libmesh_assert (_nodes[i] == NULL ||
00255                   _nodes[i]->id() == i); // This will change soon
00256 
00257   return _nodes[i];
00258 }
00259 
00260 
00261 
00262 
00263 const Elem* SerialMesh::elem (const dof_id_type i) const
00264 {
00265   libmesh_assert_less (i, this->n_elem());
00266   libmesh_assert(_elements[i]);
00267   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
00268 
00269   return _elements[i];
00270 }
00271 
00272 
00273 
00274 
00275 Elem* SerialMesh::elem (const dof_id_type i)
00276 {
00277   libmesh_assert_less (i, this->n_elem());
00278   libmesh_assert(_elements[i]);
00279   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
00280 
00281   return _elements[i];
00282 }
00283 
00284 
00285 
00286 
00287 const Elem* SerialMesh::query_elem (const dof_id_type i) const
00288 {
00289   if (i >= this->n_elem())
00290     return NULL;
00291   libmesh_assert (_elements[i] == NULL ||
00292                   _elements[i]->id() == i); // This will change soon
00293 
00294   return _elements[i];
00295 }
00296 
00297 
00298 
00299 
00300 Elem* SerialMesh::query_elem (const dof_id_type i)
00301 {
00302   if (i >= this->n_elem())
00303     return NULL;
00304   libmesh_assert (_elements[i] == NULL ||
00305                   _elements[i]->id() == i); // This will change soon
00306 
00307   return _elements[i];
00308 }
00309 
00310 
00311 
00312 
00313 Elem* SerialMesh::add_elem (Elem* e)
00314 {
00315   libmesh_assert(e);
00316 
00317   // We no longer merely append elements with SerialMesh
00318 
00319   // If the user requests a valid id that doesn't correspond to an
00320   // existing element, let's give them that id, resizing the elements
00321   // container if necessary.
00322   if (!e->valid_id())
00323     e->set_id (cast_int<dof_id_type>(_elements.size()));
00324 
00325 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00326   if (!e->valid_unique_id())
00327     e->set_unique_id() = _next_unique_id++;
00328 #endif
00329 
00330   const dof_id_type id = e->id();
00331 
00332   if (id < _elements.size())
00333     {
00334       // Overwriting existing elements is still probably a mistake.
00335       libmesh_assert(!_elements[id]);
00336     }
00337   else
00338     {
00339       _elements.resize(id+1, NULL);
00340     }
00341 
00342   _elements[id] = e;
00343 
00344   return e;
00345 }
00346 
00347 
00348 
00349 Elem* SerialMesh::insert_elem (Elem* e)
00350 {
00351   dof_id_type eid = e->id();
00352   libmesh_assert_less (eid, _elements.size());
00353   Elem *oldelem = _elements[eid];
00354 
00355   if (oldelem)
00356     {
00357       libmesh_assert_equal_to (oldelem->id(), eid);
00358       this->delete_elem(oldelem);
00359     }
00360 
00361   _elements[e->id()] = e;
00362 
00363   return e;
00364 }
00365 
00366 
00367 
00368 void SerialMesh::delete_elem(Elem* e)
00369 {
00370   libmesh_assert(e);
00371 
00372   // Initialize an iterator to eventually point to the element we want to delete
00373   std::vector<Elem*>::iterator pos = _elements.end();
00374 
00375   // In many cases, e->id() gives us a clue as to where e
00376   // is located in the _elements vector.  Try that first
00377   // before trying the O(n_elem) search.
00378   libmesh_assert_less (e->id(), _elements.size());
00379 
00380   if (_elements[e->id()] == e)
00381     {
00382       // We found it!
00383       pos = _elements.begin();
00384       std::advance(pos, e->id());
00385     }
00386 
00387   else
00388     {
00389       // This search is O(n_elem)
00390       pos = std::find (_elements.begin(),
00391                        _elements.end(),
00392                        e);
00393     }
00394 
00395   // Huh? Element not in the vector?
00396   libmesh_assert (pos != _elements.end());
00397 
00398   // Remove the element from the BoundaryInfo object
00399   this->get_boundary_info().remove(e);
00400 
00401   // delete the element
00402   delete e;
00403 
00404   // explicitly NULL the pointer
00405   *pos = NULL;
00406 }
00407 
00408 
00409 
00410 void SerialMesh::renumber_elem(const dof_id_type old_id,
00411                                const dof_id_type new_id)
00412 {
00413   // This doesn't get used in serial yet
00414   Elem *el = _elements[old_id];
00415   libmesh_assert (el);
00416 
00417   el->set_id(new_id);
00418   libmesh_assert (!_elements[new_id]);
00419   _elements[new_id] = el;
00420   _elements[old_id] = NULL;
00421 }
00422 
00423 
00424 
00425 Node* SerialMesh::add_point (const Point& p,
00426                              const dof_id_type id,
00427                              const processor_id_type proc_id)
00428 {
00429   //   // We only append points with SerialMesh
00430   //   libmesh_assert(id == DofObject::invalid_id || id == _nodes.size());
00431   //   Node *n = Node::build(p, _nodes.size()).release();
00432   //   n->processor_id() = proc_id;
00433   //   _nodes.push_back (n);
00434 
00435   Node *n = NULL;
00436 
00437   // If the user requests a valid id, either
00438   // provide the existing node or resize the container
00439   // to fit the new node.
00440   if (id != DofObject::invalid_id)
00441     if (id < _nodes.size())
00442       n = _nodes[id];
00443     else
00444       _nodes.resize(id+1);
00445   else
00446     _nodes.push_back (static_cast<Node*>(NULL));
00447 
00448   // if the node already exists, then assign new (x,y,z) values
00449   if (n)
00450     *n = p;
00451   // otherwise build a new node, put it in the right spot, and return
00452   // a valid pointer.
00453   else
00454     {
00455       n = Node::build(p, (id == DofObject::invalid_id) ?
00456                       cast_int<dof_id_type>(_nodes.size()-1) : id).release();
00457       n->processor_id() = proc_id;
00458 
00459       if (id == DofObject::invalid_id)
00460         _nodes.back() = n;
00461       else
00462         _nodes[id] = n;
00463     }
00464 
00465   // better not pass back a NULL pointer.
00466   libmesh_assert (n);
00467 
00468   return n;
00469 }
00470 
00471 
00472 
00473 Node* SerialMesh::add_node (Node* n)
00474 {
00475   libmesh_assert(n);
00476   // We only append points with SerialMesh
00477   libmesh_assert(!n->valid_id() || n->id() == _nodes.size());
00478 
00479   n->set_id (cast_int<dof_id_type>(_nodes.size()));
00480 
00481 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00482   if (!n->valid_unique_id())
00483     n->set_unique_id() = _next_unique_id++;
00484 #endif
00485 
00486   _nodes.push_back(n);
00487 
00488   return n;
00489 }
00490 
00491 
00492 
00493 Node* SerialMesh::insert_node(Node* n)
00494 {
00495   if (!n)
00496     libmesh_error_msg("Error, attempting to insert NULL node.");
00497 
00498   if (n->id() == DofObject::invalid_id)
00499     libmesh_error_msg("Error, cannot insert node with invalid id.");
00500 
00501   if (n->id() < _nodes.size())
00502     {
00503       // Don't allow inserting on top of an existing Node.
00504 
00505       // Doing so doesn't have to be *error*, in the case where a
00506       // redundant insert is done, but when that happens we ought to
00507       // always be able to make the code more efficient by avoiding
00508       // the redundant insert, so let's keep screaming "Error" here.
00509       if (_nodes[ n->id() ] != NULL)
00510         libmesh_error_msg("Error, cannot insert node on top of existing node.");
00511     }
00512   else
00513     {
00514       // Allocate just enough space to store the new node.  This will
00515       // cause highly non-ideal memory allocation behavior if called
00516       // repeatedly...
00517       _nodes.resize(n->id() + 1);
00518     }
00519 
00520 
00521   // We have enough space and this spot isn't already occupied by
00522   // another node, so go ahead and add it.
00523   _nodes[ n->id() ] = n;
00524 
00525   // If we made it this far, we just inserted the node the user handed
00526   // us, so we can give it right back.
00527   return n;
00528 }
00529 
00530 
00531 
00532 void SerialMesh::delete_node(Node* n)
00533 {
00534   libmesh_assert(n);
00535   libmesh_assert_less (n->id(), _nodes.size());
00536 
00537   // Initialize an iterator to eventually point to the element we want
00538   // to delete
00539   std::vector<Node*>::iterator pos;
00540 
00541   // In many cases, e->id() gives us a clue as to where e
00542   // is located in the _elements vector.  Try that first
00543   // before trying the O(n_elem) search.
00544   if (_nodes[n->id()] == n)
00545     {
00546       pos = _nodes.begin();
00547       std::advance(pos, n->id());
00548     }
00549   else
00550     {
00551       pos = std::find (_nodes.begin(),
00552                        _nodes.end(),
00553                        n);
00554     }
00555 
00556   // Huh? Node not in the vector?
00557   libmesh_assert (pos != _nodes.end());
00558 
00559   // Delete the node from the BoundaryInfo object
00560   this->get_boundary_info().remove(n);
00561 
00562   // delete the node
00563   delete n;
00564 
00565   // explicitly NULL the pointer
00566   *pos = NULL;
00567 }
00568 
00569 
00570 
00571 void SerialMesh::renumber_node(const dof_id_type old_id,
00572                                const dof_id_type new_id)
00573 {
00574   // This doesn't get used in serial yet
00575   Node *nd = _nodes[old_id];
00576   libmesh_assert (nd);
00577 
00578   nd->set_id(new_id);
00579   libmesh_assert (!_nodes[new_id]);
00580   _nodes[new_id] = nd;
00581   _nodes[old_id] = NULL;
00582 }
00583 
00584 
00585 
00586 void SerialMesh::clear ()
00587 {
00588   // Call parent clear function
00589   MeshBase::clear();
00590 
00591 
00592   // Clear our elements and nodes
00593   {
00594     std::vector<Elem*>::iterator       it  = _elements.begin();
00595     const std::vector<Elem*>::iterator end = _elements.end();
00596 
00597     // There is no need to remove the elements from
00598     // the BoundaryInfo data structure since we
00599     // already cleared it.
00600     for (; it != end; ++it)
00601       delete *it;
00602 
00603     _elements.clear();
00604   }
00605 
00606   // clear the nodes data structure
00607   {
00608     std::vector<Node*>::iterator       it  = _nodes.begin();
00609     const std::vector<Node*>::iterator end = _nodes.end();
00610 
00611     // There is no need to remove the nodes from
00612     // the BoundaryInfo data structure since we
00613     // already cleared it.
00614     for (; it != end; ++it)
00615       delete *it;
00616 
00617     _nodes.clear();
00618   }
00619 }
00620 
00621 
00622 
00623 void SerialMesh::renumber_nodes_and_elements ()
00624 {
00625 
00626   START_LOG("renumber_nodes_and_elem()", "Mesh");
00627 
00628   // node and element id counters
00629   dof_id_type next_free_elem = 0;
00630   dof_id_type next_free_node = 0;
00631 
00632   // Will hold the set of nodes that are currently connected to elements
00633   LIBMESH_BEST_UNORDERED_SET<Node*> connected_nodes;
00634 
00635   // Loop over the elements.  Note that there may
00636   // be NULLs in the _elements vector from the coarsening
00637   // process.  Pack the elements in to a contiguous array
00638   // and then trim any excess.
00639   {
00640     std::vector<Elem*>::iterator in        = _elements.begin();
00641     std::vector<Elem*>::iterator out_iter  = _elements.begin();
00642     const std::vector<Elem*>::iterator end = _elements.end();
00643 
00644     for (; in != end; ++in)
00645       if (*in != NULL)
00646         {
00647           Elem* el = *in;
00648 
00649           *out_iter = *in;
00650           ++out_iter;
00651 
00652           // Increment the element counter
00653           el->set_id (next_free_elem++);
00654 
00655           if(_skip_renumber_nodes_and_elements)
00656             {
00657               // Add this elements nodes to the connected list
00658               for (unsigned int n=0; n<el->n_nodes(); n++)
00659                 connected_nodes.insert(el->get_node(n));
00660             }
00661           else  // We DO want node renumbering
00662             {
00663               // Loop over this element's nodes.  Number them,
00664               // if they have not been numbered already.  Also,
00665               // position them in the _nodes vector so that they
00666               // are packed contiguously from the beginning.
00667               for (unsigned int n=0; n<el->n_nodes(); n++)
00668                 if (el->node(n) == next_free_node)     // don't need to process
00669                   next_free_node++;                      // [(src == dst) below]
00670 
00671                 else if (el->node(n) > next_free_node) // need to process
00672                   {
00673                     // The source and destination indices
00674                     // for this node
00675                     const dof_id_type src_idx = el->node(n);
00676                     const dof_id_type dst_idx = next_free_node++;
00677 
00678                     // ensure we want to swap a valid nodes
00679                     libmesh_assert(_nodes[src_idx]);
00680 
00681                     // Swap the source and destination nodes
00682                     std::swap(_nodes[src_idx],
00683                               _nodes[dst_idx] );
00684 
00685                     // Set proper indices where that makes sense
00686                     if (_nodes[src_idx] != NULL)
00687                       _nodes[src_idx]->set_id (src_idx);
00688                     _nodes[dst_idx]->set_id (dst_idx);
00689                   }
00690             }
00691         }
00692 
00693     // Erase any additional storage. These elements have been
00694     // copied into NULL voids by the procedure above, and are
00695     // thus repeated and unnecessary.
00696     _elements.erase (out_iter, end);
00697   }
00698 
00699 
00700   if(_skip_renumber_nodes_and_elements)
00701     {
00702       // Loop over the nodes.  Note that there may
00703       // be NULLs in the _nodes vector from the coarsening
00704       // process.  Pack the nodes in to a contiguous array
00705       // and then trim any excess.
00706 
00707       std::vector<Node*>::iterator in        = _nodes.begin();
00708       std::vector<Node*>::iterator out_iter  = _nodes.begin();
00709       const std::vector<Node*>::iterator end = _nodes.end();
00710 
00711       for (; in != end; ++in)
00712         if (*in != NULL)
00713           {
00714             // This is a reference so that if we change the pointer it will change in the vector
00715             Node* & nd = *in;
00716 
00717             // If this node is still connected to an elem, put it in the list
00718             if(connected_nodes.find(nd) != connected_nodes.end())
00719               {
00720                 *out_iter = nd;
00721                 ++out_iter;
00722 
00723                 // Increment the node counter
00724                 nd->set_id (next_free_node++);
00725               }
00726             else // This node is orphaned, delete it!
00727               {
00728                 this->get_boundary_info().remove (nd);
00729 
00730                 // delete the node
00731                 delete nd;
00732                 nd = NULL;
00733               }
00734           }
00735 
00736       // Erase any additional storage.  Whatever was
00737       _nodes.erase (out_iter, end);
00738     }
00739   else // We really DO want node renumbering
00740     {
00741       // Any nodes in the vector >= _nodes[next_free_node]
00742       // are not connected to any elements and may be deleted
00743       // if desired.
00744 
00745       // (This code block will erase the unused nodes)
00746       // Now, delete the unused nodes
00747       {
00748         std::vector<Node*>::iterator nd        = _nodes.begin();
00749         const std::vector<Node*>::iterator end = _nodes.end();
00750 
00751         std::advance (nd, next_free_node);
00752 
00753         for (std::vector<Node*>::iterator it=nd;
00754              it != end; ++it)
00755           {
00756             // Mesh modification code might have already deleted some
00757             // nodes
00758             if (*it == NULL)
00759               continue;
00760 
00761             // remove any boundary information associated with
00762             // this node
00763             this->get_boundary_info().remove (*it);
00764 
00765             // delete the node
00766             delete *it;
00767             *it = NULL;
00768           }
00769 
00770         _nodes.erase (nd, end);
00771       }
00772     }
00773 
00774   libmesh_assert_equal_to (next_free_elem, _elements.size());
00775   libmesh_assert_equal_to (next_free_node, _nodes.size());
00776 
00777   STOP_LOG("renumber_nodes_and_elem()", "Mesh");
00778 }
00779 
00780 
00781 
00782 void SerialMesh::fix_broken_node_and_element_numbering ()
00783 {
00784   // Nodes first
00785   for (dof_id_type n=0; n<this->_nodes.size(); n++)
00786     if (this->_nodes[n] != NULL)
00787       this->_nodes[n]->set_id() = n;
00788 
00789   // Elements next
00790   for (dof_id_type e=0; e<this->_elements.size(); e++)
00791     if (this->_elements[e] != NULL)
00792       this->_elements[e]->set_id() = e;
00793 }
00794 
00795 
00796 void SerialMesh::stitch_meshes (SerialMesh& other_mesh,
00797                                 boundary_id_type this_mesh_boundary_id,
00798                                 boundary_id_type other_mesh_boundary_id,
00799                                 Real tol,
00800                                 bool clear_stitched_boundary_ids,
00801                                 bool verbose,
00802                                 bool use_binary_search,
00803                                 bool enforce_all_nodes_match_on_boundaries)
00804 {
00805   START_LOG("stitch_meshes()", "SerialMesh");
00806   stitching_helper(&other_mesh,
00807                    this_mesh_boundary_id,
00808                    other_mesh_boundary_id,
00809                    tol,
00810                    clear_stitched_boundary_ids,
00811                    verbose,
00812                    use_binary_search,
00813                    enforce_all_nodes_match_on_boundaries,
00814                    true);
00815   STOP_LOG("stitch_meshes()", "SerialMesh");
00816 }
00817 
00818 void SerialMesh::stitch_surfaces (boundary_id_type boundary_id_1,
00819                                   boundary_id_type boundary_id_2,
00820                                   Real tol,
00821                                   bool clear_stitched_boundary_ids,
00822                                   bool verbose,
00823                                   bool use_binary_search,
00824                                   bool enforce_all_nodes_match_on_boundaries)
00825 {
00826   stitching_helper(NULL,
00827                    boundary_id_1,
00828                    boundary_id_2,
00829                    tol,
00830                    clear_stitched_boundary_ids,
00831                    verbose,
00832                    use_binary_search,
00833                    enforce_all_nodes_match_on_boundaries,
00834                    true);
00835 }
00836 
00837 void SerialMesh::stitching_helper (SerialMesh* other_mesh,
00838                                    boundary_id_type this_mesh_boundary_id,
00839                                    boundary_id_type other_mesh_boundary_id,
00840                                    Real tol,
00841                                    bool clear_stitched_boundary_ids,
00842                                    bool verbose,
00843                                    bool use_binary_search,
00844                                    bool enforce_all_nodes_match_on_boundaries,
00845                                    bool skip_find_neighbors)
00846 {
00847   std::map<dof_id_type, dof_id_type> node_to_node_map, other_to_this_node_map; // The second is the inverse map of the first
00848   std::map<dof_id_type, std::vector<dof_id_type> > node_to_elems_map;
00849 
00850   typedef dof_id_type                     key_type;
00851   typedef std::pair<Elem*, unsigned char> val_type;
00852   typedef std::pair<key_type, val_type>   key_val_pair;
00853   typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type;
00854   // Mapping between all side keys in this mesh and elements+side numbers relevant to the boundary in this mesh as well.
00855   map_type side_to_elem_map;
00856 
00857   // If there is only one mesh (i.e. other_mesh==NULL), then loop over this mesh twice
00858   if(!other_mesh)
00859     {
00860       other_mesh = this;
00861     }
00862 
00863   if( (this_mesh_boundary_id  != BoundaryInfo::invalid_id) &&
00864       (other_mesh_boundary_id != BoundaryInfo::invalid_id) )
00865     {
00866       // While finding nodes on the boundary, also find the minimum edge length
00867       // of all faces on both boundaries.  This will later be used in relative
00868       // distance checks when stitching nodes.
00869       Real h_min = std::numeric_limits<Real>::max();
00870       bool h_min_updated = false;
00871 
00872       // Loop below fills in these sets for the two meshes.
00873       std::set<dof_id_type> this_boundary_node_ids, other_boundary_node_ids;
00874       {
00875         // Make temporary fixed-size arrays for loop
00876         boundary_id_type id_array[2]        = {this_mesh_boundary_id, other_mesh_boundary_id};
00877         std::set<dof_id_type>* set_array[2] = {&this_boundary_node_ids, &other_boundary_node_ids};
00878         SerialMesh* mesh_array[2]           = {this, other_mesh};
00879 
00880         for (unsigned i=0; i<2; ++i)
00881           {
00882             // First we deal with node boundary IDs.
00883             // We only enter this loop if we have at least one
00884             // nodeset.
00885             if(mesh_array[i]->get_boundary_info().n_nodeset_conds() > 0)
00886               {
00887                 // We need to find an element that contains boundary nodes in order
00888                 // to update hmin.
00889                 UniquePtr<PointLocatorBase> my_locator = mesh_array[i]->sub_point_locator();
00890 
00891                 std::vector<numeric_index_type> node_id_list;
00892                 std::vector<boundary_id_type> bc_id_list;
00893 
00894                 // Get the list of nodes with associated boundary IDs
00895                 mesh_array[i]->get_boundary_info().build_node_list(node_id_list, bc_id_list);
00896 
00897                 for(unsigned int node_index=0; node_index<bc_id_list.size(); node_index++)
00898                   {
00899                     boundary_id_type node_bc_id = bc_id_list[node_index];
00900                     if (node_bc_id == id_array[i])
00901                       {
00902                         dof_id_type node_id = node_id_list[node_index];
00903                         set_array[i]->insert( node_id );
00904 
00905                         const Elem* near_elem = (*my_locator)( mesh_array[i]->node(node_id) );
00906                         if (near_elem == NULL)
00907                           libmesh_error_msg("Error: PointLocator failed to find a valid element");
00908 
00909                         h_min = std::min(h_min, near_elem->hmin());
00910                         h_min_updated = true;
00911                       }
00912                   }
00913               }
00914 
00915             MeshBase::element_iterator elem_it  = mesh_array[i]->elements_begin();
00916             MeshBase::element_iterator elem_end = mesh_array[i]->elements_end();
00917             for ( ; elem_it != elem_end; ++elem_it)
00918               {
00919                 Elem *el = *elem_it;
00920 
00921                 // Now check whether elem has a face on the specified boundary
00922                 for (unsigned char side_id=0; side_id<el->n_sides(); ++side_id)
00923                   if (el->neighbor(side_id) == NULL)
00924                     {
00925                       // Get *all* boundary IDs on this side, not just the first one!
00926                       std::vector<boundary_id_type> bc_ids =
00927                         mesh_array[i]->get_boundary_info().boundary_ids (el, side_id);
00928 
00929                       if (std::count(bc_ids.begin(), bc_ids.end(), id_array[i]))
00930                         {
00931                           UniquePtr<Elem> side (el->build_side(side_id));
00932                           for (unsigned int node_id=0; node_id<side->n_nodes(); ++node_id)
00933                             set_array[i]->insert( side->node(node_id) );
00934 
00935                           h_min = std::min(h_min, side->hmin());
00936                           h_min_updated = true;
00937 
00938                           // This side is on the boundary, add its information to side_to_elem
00939                           if(skip_find_neighbors && (i==0))
00940                             {
00941                               key_type key = el->key(side_id);
00942                               val_type val;
00943                               val.first = el;
00944                               val.second = side_id;
00945 
00946                               key_val_pair kvp;
00947                               kvp.first = key;
00948                               kvp.second = val;
00949                               // side_to_elem_map[key] = val;
00950 #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP)
00951                               side_to_elem_map.insert (kvp);
00952 #else
00953                               side_to_elem_map.insert (side_to_elem_map.begin(),kvp);
00954 #endif
00955                             }
00956                         }
00957 
00958                       // Also, check the edges on this side. We don't have to worry about
00959                       // updating neighbor info in this case since elements don't store
00960                       // neighbor info on edges.
00961                       for (unsigned short edge_id=0; edge_id<el->n_edges(); ++edge_id)
00962                         {
00963                           if(el->is_edge_on_side(edge_id, side_id))
00964                             {
00965                               // Get *all* boundary IDs on this edge, not just the first one!
00966                               std::vector<boundary_id_type> edge_bc_ids =
00967                                 mesh_array[i]->get_boundary_info().edge_boundary_ids (el, edge_id);
00968 
00969                               if (std::count(edge_bc_ids.begin(), edge_bc_ids.end(), id_array[i]))
00970                                 {
00971                                   UniquePtr<Elem> edge (el->build_edge(edge_id));
00972                                   for (unsigned int node_id=0; node_id<edge->n_nodes(); ++node_id)
00973                                     set_array[i]->insert( edge->node(node_id) );
00974 
00975                                   h_min = std::min(h_min, edge->hmin());
00976                                   h_min_updated = true;
00977                                 }
00978                             }
00979                         }
00980                     }
00981               }
00982           }
00983       }
00984 
00985       if (verbose)
00986         {
00987           libMesh::out << "In SerialMesh::stitch_meshes:\n"
00988                        << "This mesh has "  << this_boundary_node_ids.size()
00989                        << " nodes on boundary " << this_mesh_boundary_id  << ".\n"
00990                        << "Other mesh has " << other_boundary_node_ids.size()
00991                        << " nodes on boundary " << other_mesh_boundary_id << ".\n";
00992 
00993           if(h_min_updated)
00994             {
00995               libMesh::out << "Minimum edge length on both surfaces is " << h_min << ".\n";
00996             }
00997           else
00998             {
00999               libMesh::out << "No elements on specified surfaces." << std::endl;
01000             }
01001         }
01002 
01003 
01004       if(use_binary_search)
01005         {
01006           // Store points from both stitched faces in sorted vectors for faster
01007           // searching later.
01008           typedef std::vector< std::pair<Point, dof_id_type> > PointVector;
01009           PointVector
01010             this_sorted_bndry_nodes(this_boundary_node_ids.size()),
01011             other_sorted_bndry_nodes(other_boundary_node_ids.size());
01012 
01013           // Comparison object that will be used later. So far, I've had reasonable success
01014           // with TOLERANCE...
01015           FuzzyPointCompare mein_comp(TOLERANCE);
01016 
01017           // Create and sort the vectors we will use to do the geometric searching
01018           {
01019             std::set<dof_id_type>* set_array[2] = {&this_boundary_node_ids, &other_boundary_node_ids};
01020             SerialMesh* mesh_array[2]           = {this, other_mesh};
01021             PointVector* vec_array[2]           = {&this_sorted_bndry_nodes, &other_sorted_bndry_nodes};
01022 
01023             for (unsigned i=0; i<2; ++i)
01024               {
01025                 std::set<dof_id_type>::iterator
01026                   set_it     = set_array[i]->begin(),
01027                   set_it_end = set_array[i]->end();
01028 
01029                 // Fill up the vector with the contents of the set...
01030                 for (unsigned ctr=0; set_it != set_it_end; ++set_it, ++ctr)
01031                   {
01032                     (*vec_array[i])[ctr] = std::make_pair( mesh_array[i]->point(*set_it), // The geometric point
01033                                                            *set_it );                     // Its ID
01034                   }
01035 
01036                 // Sort the vectors based on the FuzzyPointCompare struct op()
01037                 std::sort(vec_array[i]->begin(), vec_array[i]->end(), mein_comp);
01038               }
01039           }
01040 
01041           // Build up the node_to_node_map and node_to_elems_map using the sorted vectors of Points.
01042           for (unsigned i=0; i<this_sorted_bndry_nodes.size(); ++i)
01043             {
01044               // Current point we're working on
01045               Point this_point = this_sorted_bndry_nodes[i].first;
01046 
01047               // FuzzyPointCompare does a fuzzy equality comparison internally to handle
01048               // slight differences between the list of nodes on each mesh.
01049               PointVector::iterator other_iter = Utility::binary_find(other_sorted_bndry_nodes.begin(),
01050                                                                       other_sorted_bndry_nodes.end(),
01051                                                                       this_point,
01052                                                                       mein_comp);
01053 
01054               // Not every node on this_sorted_bndry_nodes will necessarily be stitched, so
01055               // if its pair is not found on other_mesh, just continue.
01056               if (other_iter != other_sorted_bndry_nodes.end())
01057                 {
01058                   // Check that the points do indeed match - should not be necessary unless something
01059                   // is wrong with binary_find.  To be on the safe side, we'll check.
01060                   {
01061                     // Grab the other point from the iterator
01062                     Point other_point = other_iter->first;
01063 
01064                     if (!this_point.absolute_fuzzy_equals(other_point, tol*h_min))
01065                       libmesh_error_msg("Error: mismatched points: " << this_point << " and " << other_point);
01066                   }
01067 
01068 
01069                   // Associate these two nodes in both the node_to_node_map and the other_to_this_node_map
01070                   dof_id_type
01071                     this_node_id = this_sorted_bndry_nodes[i].second,
01072                     other_node_id = other_iter->second;
01073                   node_to_node_map[this_node_id] = other_node_id;
01074                   other_to_this_node_map[other_node_id] = this_node_id;
01075                 }
01076 
01077             }
01078         }
01079       else
01080         {
01081           // Otherwise, use a simple N^2 search to find the closest matching points. This can be helpful
01082           // in the case that we have tolerance issues which cause mismatch between the two surfaces
01083           // that are being stitched.
01084 
01085           std::set<dof_id_type>::iterator set_it     = this_boundary_node_ids.begin();
01086           std::set<dof_id_type>::iterator set_it_end = this_boundary_node_ids.end();
01087           for( ; set_it != set_it_end; ++set_it)
01088             {
01089               dof_id_type this_node_id = *set_it;
01090               Node& this_node = this->node(this_node_id);
01091 
01092               bool found_matching_nodes = false;
01093 
01094               std::set<dof_id_type>::iterator other_set_it     = other_boundary_node_ids.begin();
01095               std::set<dof_id_type>::iterator other_set_it_end = other_boundary_node_ids.end();
01096               for( ; other_set_it != other_set_it_end; ++other_set_it)
01097                 {
01098                   dof_id_type other_node_id = *other_set_it;
01099                   Node& other_node = other_mesh->node(other_node_id);
01100 
01101                   Real node_distance = (this_node - other_node).size();
01102 
01103                   if(node_distance < tol*h_min)
01104                     {
01105                       // Make sure we didn't already find a matching node!
01106                       if(found_matching_nodes)
01107                         libmesh_error_msg("Error: Found multiple matching nodes in stitch_meshes");
01108 
01109                       node_to_node_map[this_node_id] = other_node_id;
01110                       other_to_this_node_map[other_node_id] = this_node_id;
01111 
01112                       found_matching_nodes = true;
01113                     }
01114                 }
01115             }
01116         }
01117 
01118       // Build up the node_to_elems_map, using only one loop over other_mesh
01119       {
01120         MeshBase::element_iterator other_elem_it  = other_mesh->elements_begin();
01121         MeshBase::element_iterator other_elem_end = other_mesh->elements_end();
01122         for (; other_elem_it != other_elem_end; ++other_elem_it)
01123           {
01124             Elem *el = *other_elem_it;
01125 
01126             // For each node on the element, find the corresponding node
01127             // on "this" Mesh, 'this_node_id', if it exists, and push
01128             // the current element ID back onto node_to_elems_map[this_node_id].
01129             // For that we will use the reverse mapping we created at
01130             // the same time as the forward mapping.
01131             for (unsigned n=0; n<el->n_nodes(); ++n)
01132               {
01133                 dof_id_type other_node_id = el->node(n);
01134                 std::map<dof_id_type, dof_id_type>::iterator it =
01135                   other_to_this_node_map.find(other_node_id);
01136 
01137                 if (it != other_to_this_node_map.end())
01138                   {
01139                     dof_id_type this_node_id = it->second;
01140                     node_to_elems_map[this_node_id].push_back( el->id() );
01141                   }
01142               }
01143           }
01144       }
01145 
01146       if(verbose)
01147         {
01148           libMesh::out << "In SerialMesh::stitch_meshes:\n"
01149                        << "Found " << node_to_node_map.size()
01150                        << " matching nodes.\n"
01151                        << std::endl;
01152         }
01153 
01154       if(enforce_all_nodes_match_on_boundaries)
01155         {
01156           std::size_t n_matching_nodes = node_to_node_map.size();
01157           std::size_t this_mesh_n_nodes = this_boundary_node_ids.size();
01158           std::size_t other_mesh_n_nodes = other_boundary_node_ids.size();
01159           if( (n_matching_nodes != this_mesh_n_nodes) ||
01160               (n_matching_nodes != other_mesh_n_nodes) )
01161             libmesh_error_msg("Error: We expected the number of nodes to match.");
01162         }
01163     }
01164   else
01165     {
01166       if(verbose)
01167         {
01168           libMesh::out << "Skip node merging in SerialMesh::stitch_meshes:" << std::endl;
01169         }
01170     }
01171 
01172 
01173 
01174   dof_id_type node_delta = this->n_nodes();
01175   dof_id_type elem_delta = this->n_elem();
01176 
01177   // If other_mesh!=NULL, then we have to do a bunch of work
01178   // in order to copy it to this mesh
01179   if(this!=other_mesh)
01180     {
01181       // need to increment node and element IDs of other_mesh before copying to this mesh
01182       MeshBase::node_iterator node_it  = other_mesh->nodes_begin();
01183       MeshBase::node_iterator node_end = other_mesh->nodes_end();
01184       for (; node_it != node_end; ++node_it)
01185         {
01186           Node *nd = *node_it;
01187           dof_id_type new_id = nd->id() + node_delta;
01188           nd->set_id(new_id);
01189         }
01190 
01191       MeshBase::element_iterator elem_it  = other_mesh->elements_begin();
01192       MeshBase::element_iterator elem_end = other_mesh->elements_end();
01193       for (; elem_it != elem_end; ++elem_it)
01194         {
01195           Elem *el = *elem_it;
01196           dof_id_type new_id = el->id() + elem_delta;
01197           el->set_id(new_id);
01198         }
01199 
01200       // Also, increment the node_to_node_map and node_to_elems_map
01201       std::map<dof_id_type, dof_id_type>::iterator node_map_it     = node_to_node_map.begin();
01202       std::map<dof_id_type, dof_id_type>::iterator node_map_it_end = node_to_node_map.end();
01203       for( ; node_map_it != node_map_it_end; ++node_map_it)
01204         {
01205           node_map_it->second += node_delta;
01206         }
01207       std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it     = node_to_elems_map.begin();
01208       std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it_end = node_to_elems_map.end();
01209       for( ; elem_map_it != elem_map_it_end; ++elem_map_it)
01210         {
01211           std::size_t n_elems = elem_map_it->second.size();
01212           for(std::size_t i=0; i<n_elems; i++)
01213             {
01214               (elem_map_it->second)[i] += elem_delta;
01215             }
01216         }
01217 
01218       // Copy mesh data. If we skip the call to find_neighbors(), the lists
01219       // of neighbors will be copied verbatim from the other mesh
01220       this->copy_nodes_and_elements(*other_mesh, skip_find_neighbors);
01221 
01222       // Decrement node IDs of mesh to return to original state
01223       node_it  = other_mesh->nodes_begin();
01224       node_end = other_mesh->nodes_end();
01225       for (; node_it != node_end; ++node_it)
01226         {
01227           Node *nd = *node_it;
01228           dof_id_type new_id = nd->id() - node_delta;
01229           nd->set_id(new_id);
01230         }
01231 
01232       elem_it  = other_mesh->elements_begin();
01233       elem_end = other_mesh->elements_end();
01234       for (; elem_it != elem_end; ++elem_it)
01235         {
01236           Elem *other_elem = *elem_it;
01237 
01238           // Find the corresponding element on this mesh
01239           Elem* this_elem = this->elem(other_elem->id());
01240 
01241           // Decrement elem IDs of other_mesh to return it to original state
01242           dof_id_type new_id = other_elem->id() - elem_delta;
01243           other_elem->set_id(new_id);
01244 
01245           unsigned int other_n_nodes = other_elem->n_nodes();
01246           for (unsigned int n=0; n != other_n_nodes; ++n)
01247             {
01248               const std::vector<boundary_id_type>& ids =
01249                 other_mesh->get_boundary_info().boundary_ids(other_elem->get_node(n));
01250               if (!ids.empty())
01251                 {
01252                   this->get_boundary_info().add_node(this_elem->get_node(n), ids);
01253                 }
01254             }
01255 
01256           // Copy edge boundary info
01257           unsigned int n_edges = other_elem->n_edges();
01258           for (unsigned short edge=0; edge != n_edges; ++edge)
01259             {
01260               const std::vector<boundary_id_type>& ids =
01261                 other_mesh->get_boundary_info().edge_boundary_ids(other_elem, edge);
01262               if (!ids.empty())
01263                 {
01264                   this->get_boundary_info().add_edge( this_elem, edge, ids);
01265                 }
01266             }
01267 
01268           unsigned int n_sides = other_elem->n_sides();
01269           for (unsigned short s=0; s != n_sides; ++s)
01270             {
01271               const std::vector<boundary_id_type>& ids =
01272                 other_mesh->get_boundary_info().boundary_ids(other_elem, s);
01273               if (!ids.empty())
01274                 {
01275                   this->get_boundary_info().add_side( this_elem, s, ids);
01276                 }
01277             }
01278 
01279         }
01280 
01281     } // end if(other_mesh)
01282 
01283   // Finally, we need to "merge" the overlapping nodes
01284   // We do this by iterating over node_to_elems_map and updating
01285   // the elements so that they "point" to the nodes that came
01286   // from this mesh, rather than from other_mesh.
01287   // Then we iterate over node_to_node_map and delete the
01288   // duplicate nodes that came from other_mesh.
01289   std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it     = node_to_elems_map.begin();
01290   std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it_end = node_to_elems_map.end();
01291   for( ; elem_map_it != elem_map_it_end; ++elem_map_it)
01292     {
01293       dof_id_type target_node_id = elem_map_it->first;
01294       dof_id_type other_node_id = node_to_node_map[target_node_id];
01295       Node& target_node = this->node(target_node_id);
01296 
01297       std::size_t n_elems = elem_map_it->second.size();
01298       for(std::size_t i=0; i<n_elems; i++)
01299         {
01300           dof_id_type elem_id = elem_map_it->second[i];
01301           Elem* el = this->elem(elem_id);
01302 
01303           // find the local node index that we want to update
01304           unsigned int local_node_index = el->local_node(other_node_id);
01305 
01306           // We also need to copy over the nodeset info here,
01307           // because the node will get deleted below
01308           const std::vector<boundary_id_type>& ids =
01309             this->get_boundary_info().boundary_ids(el->get_node(local_node_index));
01310 
01311           el->set_node(local_node_index) = &target_node;
01312 
01313           this->get_boundary_info().add_node(&target_node, ids);
01314         }
01315     }
01316 
01317   std::map<dof_id_type, dof_id_type>::iterator node_map_it     = node_to_node_map.begin();
01318   std::map<dof_id_type, dof_id_type>::iterator node_map_it_end = node_to_node_map.end();
01319   for( ; node_map_it != node_map_it_end; ++node_map_it)
01320     {
01321       // In the case that this==other_mesh, the two nodes might be the same (e.g. if
01322       // we're stitching a "sliver"), hence we need to skip node deletion in that case.
01323       if ((this == other_mesh) && (node_map_it->second == node_map_it->first))
01324         continue;
01325 
01326       dof_id_type node_id = node_map_it->second;
01327       this->delete_node( this->node_ptr(node_id) );
01328     }
01329 
01330   // If find_neighbors() wasn't called in prepare_for_use(), we need to
01331   // manually loop once more over all elements adjacent to the stitched boundary
01332   // and fix their lists of neighbors.
01333   // This is done according to the following steps:
01334   //   1. Loop over all copied elements adjacent to the boundary using node_to_elems_map (trying to avoid duplicates)
01335   //   2. Look at all their sides with a NULL neighbor and update them using side_to_elem_map if necessary
01336   //   3. Update the corresponding side in side_to_elem_map as well
01337   if(skip_find_neighbors)
01338     {
01339       elem_map_it     = node_to_elems_map.begin();
01340       elem_map_it_end = node_to_elems_map.end();
01341       std::set<dof_id_type> fixed_elems;
01342       for( ; elem_map_it != elem_map_it_end; ++elem_map_it)
01343         {
01344           std::size_t n_elems = elem_map_it->second.size();
01345           for(std::size_t i=0; i<n_elems; i++)
01346             {
01347               dof_id_type elem_id = elem_map_it->second[i];
01348               if(fixed_elems.find(elem_id) == fixed_elems.end())
01349                 {
01350                   Elem* el = this->elem(elem_id);
01351                   fixed_elems.insert(elem_id);
01352                   for(unsigned int s = 0; s < el->n_neighbors(); ++s)
01353                     {
01354                       if(el->neighbor(s) == NULL)
01355                         {
01356                           key_type key = el->key(s);
01357                           typedef
01358                             map_type::iterator key_val_it_type;
01359                           std::pair<key_val_it_type, key_val_it_type>
01360                             bounds = side_to_elem_map.equal_range(key);
01361 
01362                           if(bounds.first != bounds.second)
01363                             {
01364                               // Get the side for this element
01365                               const UniquePtr<Elem> my_side(el->side(s));
01366 
01367                               // Look at all the entries with an equivalent key
01368                               while (bounds.first != bounds.second)
01369                                 {
01370                                   // Get the potential element
01371                                   Elem* neighbor = bounds.first->second.first;
01372 
01373                                   // Get the side for the neighboring element
01374                                   const unsigned int ns = bounds.first->second.second;
01375                                   const UniquePtr<Elem> their_side(neighbor->side(ns));
01376                                   //libmesh_assert(my_side.get());
01377                                   //libmesh_assert(their_side.get());
01378 
01379                                   // If found a match with my side
01380                                   //
01381                                   // We need special tests here for 1D:
01382                                   // since parents and children have an equal
01383                                   // side (i.e. a node), we need to check
01384                                   // ns != ms, and we also check level() to
01385                                   // avoid setting our neighbor pointer to
01386                                   // any of our neighbor's descendants
01387                                   if( (*my_side == *their_side) &&
01388                                       (el->level() == neighbor->level()) &&
01389                                       ((el->dim() != 1) || (ns != s)) )
01390                                     {
01391                                       // So share a side.  Is this a mixed pair
01392                                       // of subactive and active/ancestor
01393                                       // elements?
01394                                       // If not, then we're neighbors.
01395                                       // If so, then the subactive's neighbor is
01396 
01397                                       if (el->subactive() ==
01398                                           neighbor->subactive())
01399                                         {
01400                                           // an element is only subactive if it has
01401                                           // been coarsened but not deleted
01402                                           el->set_neighbor (s,neighbor);
01403                                           neighbor->set_neighbor(ns,el);
01404                                         }
01405                                       else if (el->subactive())
01406                                         {
01407                                           el->set_neighbor(s,neighbor);
01408                                         }
01409                                       else if (neighbor->subactive())
01410                                         {
01411                                           neighbor->set_neighbor(ns,el);
01412                                         }
01413                                       side_to_elem_map.erase (bounds.first);
01414                                       break;
01415                                     }
01416 
01417                                   ++bounds.first;
01418                                 }
01419                             }
01420                         }
01421                     }
01422                 }
01423             }
01424         }
01425     }
01426 
01427   this->prepare_for_use( /*skip_renumber_nodes_and_elements= */ false, skip_find_neighbors);
01428 
01429   // After the stitching, we may want to clear boundary IDs from element
01430   // faces that are now internal to the mesh
01431   if(clear_stitched_boundary_ids)
01432     {
01433       MeshBase::element_iterator elem_it  = this->elements_begin();
01434       MeshBase::element_iterator elem_end = this->elements_end();
01435       for (; elem_it != elem_end; ++elem_it)
01436         {
01437           Elem *el = *elem_it;
01438 
01439           for (unsigned short side_id=0; side_id<el->n_sides(); side_id++)
01440             {
01441               if (el->neighbor(side_id) != NULL)
01442                 {
01443                   // Completely remove the side from the boundary_info object if it has either
01444                   // this_mesh_boundary_id or other_mesh_boundary_id.
01445                   std::vector<boundary_id_type> bc_ids =
01446                     this->get_boundary_info().boundary_ids (el, side_id);
01447 
01448                   if (std::count(bc_ids.begin(), bc_ids.end(), this_mesh_boundary_id) ||
01449                       std::count(bc_ids.begin(), bc_ids.end(), other_mesh_boundary_id))
01450                     this->get_boundary_info().remove_side(el, side_id);
01451                 }
01452             }
01453         }
01454     }
01455 
01456 }
01457 
01458 
01459 dof_id_type SerialMesh::n_active_elem () const
01460 {
01461   return static_cast<dof_id_type>(std::distance (this->active_elements_begin(),
01462                                                  this->active_elements_end()));
01463 }
01464 
01465 
01466 #ifdef LIBMESH_ENABLE_UNIQUE_ID
01467 void SerialMesh::assign_unique_ids()
01468 {
01469   for (dof_id_type i=0; i<_elements.size(); ++i)
01470     if (_elements[i] && ! _elements[i]->valid_unique_id())
01471       _elements[i]->set_unique_id() = _next_unique_id++;
01472 
01473   for (dof_id_type i=0; i<_nodes.size(); ++i)
01474     if (_nodes[i] && ! _nodes[i]->valid_unique_id())
01475       _nodes[i]->set_unique_id() = _next_unique_id++;
01476 }
01477 #endif
01478 
01479 
01480 } // namespace libMesh