$extrastylesheet
parallel_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/mesh_communication.h"
00025 #include "libmesh/parallel_mesh.h"
00026 #include "libmesh/parallel.h"
00027 #include "libmesh/parmetis_partitioner.h"
00028 
00029 namespace libMesh
00030 {
00031 
00032 // ------------------------------------------------------------
00033 // ParallelMesh class member functions
00034 ParallelMesh::ParallelMesh (const Parallel::Communicator &comm_in,
00035                             unsigned char d) :
00036   UnstructuredMesh (comm_in,d), _is_serial(true),
00037   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
00038   _next_free_local_node_id(this->processor_id()),
00039   _next_free_local_elem_id(this->processor_id()),
00040   _next_free_unpartitioned_node_id(this->n_processors()),
00041   _next_free_unpartitioned_elem_id(this->n_processors())
00042 {
00043 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00044   _next_unique_id = this->processor_id();
00045 #endif
00046 
00047   // FIXME: give parmetis the communicator!
00048   _partitioner = UniquePtr<Partitioner>(new ParmetisPartitioner());
00049 }
00050 
00051 
00052 #ifndef LIBMESH_DISABLE_COMMWORLD
00053 // ------------------------------------------------------------
00054 // ParallelMesh class member functions
00055 ParallelMesh::ParallelMesh (unsigned char d) :
00056   UnstructuredMesh (d), _is_serial(true),
00057   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
00058   _next_free_local_node_id(this->processor_id()),
00059   _next_free_local_elem_id(this->processor_id()),
00060   _next_free_unpartitioned_node_id(this->n_processors()),
00061   _next_free_unpartitioned_elem_id(this->n_processors())
00062 {
00063 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00064   _next_unique_id = this->processor_id();
00065 #endif
00066 
00067   // FIXME: give parmetis the communicator!
00068   _partitioner = UniquePtr<Partitioner>(new ParmetisPartitioner());
00069 }
00070 #endif
00071 
00072 
00073 ParallelMesh::~ParallelMesh ()
00074 {
00075   this->clear();  // Free nodes and elements
00076 }
00077 
00078 
00079 // This might be specialized later, but right now it's just here to
00080 // make sure the compiler doesn't give us a default (non-deep) copy
00081 // constructor instead.
00082 ParallelMesh::ParallelMesh (const ParallelMesh &other_mesh) :
00083   UnstructuredMesh (other_mesh), _is_serial(other_mesh._is_serial),
00084   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
00085   _next_free_local_node_id(this->processor_id()),
00086   _next_free_local_elem_id(this->processor_id()),
00087   _next_free_unpartitioned_node_id(this->n_processors()),
00088   _next_free_unpartitioned_elem_id(this->n_processors())
00089 {
00090   this->copy_nodes_and_elements(other_mesh);
00091   _n_nodes = other_mesh.n_nodes();
00092   _n_elem  = other_mesh.n_elem();
00093   _max_node_id = other_mesh.max_node_id();
00094   _max_elem_id = other_mesh.max_elem_id();
00095   _next_free_local_node_id =
00096     other_mesh._next_free_local_node_id;
00097   _next_free_local_elem_id =
00098     other_mesh._next_free_local_elem_id;
00099   _next_free_unpartitioned_node_id =
00100     other_mesh._next_free_unpartitioned_node_id;
00101   _next_free_unpartitioned_elem_id =
00102     other_mesh._next_free_unpartitioned_elem_id;
00103   this->get_boundary_info() = other_mesh.get_boundary_info();
00104 
00105   // Need to copy extra_ghost_elems
00106   for(std::set<Elem *>::iterator it = other_mesh._extra_ghost_elems.begin();
00107       it != other_mesh._extra_ghost_elems.end();
00108       ++it)
00109     _extra_ghost_elems.insert(elem((*it)->id()));
00110 }
00111 
00112 
00113 
00114 ParallelMesh::ParallelMesh (const UnstructuredMesh &other_mesh) :
00115   UnstructuredMesh (other_mesh), _is_serial(other_mesh.is_serial()),
00116   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
00117   _next_free_local_node_id(this->processor_id()),
00118   _next_free_local_elem_id(this->processor_id()),
00119   _next_free_unpartitioned_node_id(this->n_processors()),
00120   _next_free_unpartitioned_elem_id(this->n_processors())
00121 {
00122   this->copy_nodes_and_elements(other_mesh);
00123   this->get_boundary_info() = other_mesh.get_boundary_info();
00124 
00125   this->update_parallel_id_counts();
00126 }
00127 
00128 
00129 // We use cached values for these so they can be called
00130 // from one processor without bothering the rest, but
00131 // we may need to update those caches before doing a full
00132 // renumbering
00133 void ParallelMesh::update_parallel_id_counts()
00134 {
00135   // This function must be run on all processors at once
00136   parallel_object_only();
00137 
00138   _n_elem  = this->parallel_n_elem();
00139   _n_nodes = this->parallel_n_nodes();
00140   _max_node_id = this->parallel_max_node_id();
00141   _max_elem_id = this->parallel_max_elem_id();
00142 
00143   if (_next_free_unpartitioned_elem_id < _max_elem_id)
00144     _next_free_unpartitioned_elem_id =
00145       ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
00146       (this->n_processors() + 1) + this->n_processors();
00147   if (_next_free_local_elem_id < _max_elem_id)
00148     _next_free_local_elem_id =
00149       ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
00150       (this->n_processors() + 1) + this->processor_id();
00151 
00152   if (_next_free_unpartitioned_node_id < _max_node_id)
00153     _next_free_unpartitioned_node_id =
00154       ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
00155       (this->n_processors() + 1) + this->n_processors();
00156   if (_next_free_local_node_id < _max_node_id)
00157     _next_free_local_node_id =
00158       ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
00159       (this->n_processors() + 1) + this->processor_id();
00160 }
00161 
00162 
00163 // Or in debug mode we may want to test the uncached values without
00164 // changing the cache
00165 dof_id_type ParallelMesh::parallel_n_elem() const
00166 {
00167   // This function must be run on all processors at once
00168   parallel_object_only();
00169 
00170   dof_id_type n_local = this->n_local_elem();
00171   this->comm().sum(n_local);
00172   n_local += this->n_unpartitioned_elem();
00173   return n_local;
00174 }
00175 
00176 
00177 
00178 dof_id_type ParallelMesh::parallel_max_elem_id() const
00179 {
00180   // This function must be run on all processors at once
00181   parallel_object_only();
00182 
00183   dof_id_type max_local = _elements.empty() ?
00184     0 : _elements.rbegin()->first + 1;
00185   this->comm().max(max_local);
00186   return max_local;
00187 }
00188 
00189 
00190 
00191 dof_id_type ParallelMesh::parallel_n_nodes() const
00192 {
00193   // This function must be run on all processors at once
00194   parallel_object_only();
00195 
00196   dof_id_type n_local = this->n_local_nodes();
00197   this->comm().sum(n_local);
00198   n_local += this->n_unpartitioned_nodes();
00199   return n_local;
00200 }
00201 
00202 
00203 
00204 dof_id_type ParallelMesh::parallel_max_node_id() const
00205 {
00206   // This function must be run on all processors at once
00207   parallel_object_only();
00208 
00209   dof_id_type max_local = _nodes.empty() ?
00210     0 : _nodes.rbegin()->first + 1;
00211   this->comm().max(max_local);
00212   return max_local;
00213 }
00214 
00215 
00216 
00217 const Point& ParallelMesh::point (const dof_id_type i) const
00218 {
00219   libmesh_assert(_nodes[i]);
00220   libmesh_assert_equal_to (_nodes[i]->id(), i);
00221 
00222   return (*_nodes[i]);
00223 }
00224 
00225 
00226 
00227 
00228 
00229 const Node& ParallelMesh::node (const dof_id_type i) const
00230 {
00231   libmesh_assert(_nodes[i]);
00232   libmesh_assert_equal_to (_nodes[i]->id(), i);
00233 
00234   return (*_nodes[i]);
00235 }
00236 
00237 
00238 
00239 
00240 
00241 Node& ParallelMesh::node (const dof_id_type i)
00242 {
00243   libmesh_assert(_nodes[i]);
00244   libmesh_assert_equal_to (_nodes[i]->id(), i);
00245 
00246   return (*_nodes[i]);
00247 }
00248 
00249 
00250 
00251 const Node* ParallelMesh::node_ptr (const dof_id_type i) const
00252 {
00253   libmesh_assert(_nodes[i]);
00254   libmesh_assert_equal_to (_nodes[i]->id(), i);
00255 
00256   return _nodes[i];
00257 }
00258 
00259 
00260 
00261 
00262 Node* ParallelMesh::node_ptr (const dof_id_type i)
00263 {
00264   libmesh_assert(_nodes[i]);
00265   libmesh_assert_equal_to (_nodes[i]->id(), i);
00266 
00267   return _nodes[i];
00268 }
00269 
00270 
00271 
00272 
00273 const Node* ParallelMesh::query_node_ptr (const dof_id_type i) const
00274 {
00275   std::map<dof_id_type, Node*>::const_iterator it = _nodes.find(i);
00276   if (it != _nodes.end().it)
00277     {
00278       const Node* n = it->second;
00279       libmesh_assert (!n || n->id() == i);
00280       return n;
00281     }
00282 
00283   return NULL;
00284 }
00285 
00286 
00287 
00288 
00289 Node* ParallelMesh::query_node_ptr (const dof_id_type i)
00290 {
00291   std::map<dof_id_type, Node*>::const_iterator it = _nodes.find(i);
00292   if (it != _nodes.end().it)
00293     {
00294       Node* n = it->second;
00295       libmesh_assert (!n || n->id() == i);
00296       return n;
00297     }
00298 
00299   return NULL;
00300 }
00301 
00302 
00303 
00304 
00305 const Elem* ParallelMesh::elem (const dof_id_type i) const
00306 {
00307   libmesh_assert(_elements[i]);
00308   libmesh_assert_equal_to (_elements[i]->id(), i);
00309 
00310   return _elements[i];
00311 }
00312 
00313 
00314 
00315 
00316 Elem* ParallelMesh::elem (const dof_id_type i)
00317 {
00318   libmesh_assert(_elements[i]);
00319   libmesh_assert_equal_to (_elements[i]->id(), i);
00320 
00321   return _elements[i];
00322 }
00323 
00324 
00325 
00326 
00327 const Elem* ParallelMesh::query_elem (const dof_id_type i) const
00328 {
00329   std::map<dof_id_type, Elem*>::const_iterator it = _elements.find(i);
00330   if (it != _elements.end().it)
00331     {
00332       const Elem* e = it->second;
00333       libmesh_assert (!e || e->id() == i);
00334       return e;
00335     }
00336 
00337   return NULL;
00338 }
00339 
00340 
00341 
00342 
00343 Elem* ParallelMesh::query_elem (const dof_id_type i)
00344 {
00345   std::map<dof_id_type, Elem*>::const_iterator it = _elements.find(i);
00346   if (it != _elements.end().it)
00347     {
00348       Elem* e = _elements[i];
00349       libmesh_assert (!e || e->id() == i);
00350       return e;
00351     }
00352 
00353   return NULL;
00354 }
00355 
00356 
00357 
00358 
00359 Elem* ParallelMesh::add_elem (Elem *e)
00360 {
00361   // Don't try to add NULLs!
00362   libmesh_assert(e);
00363 
00364   // Trying to add an existing element is a no-op
00365   if (e->valid_id() && _elements[e->id()] == e)
00366     return e;
00367 
00368   const processor_id_type elem_procid = e->processor_id();
00369 
00370   if (!e->valid_id())
00371     {
00372       // We should only be creating new ids past the end of the range
00373       // of existing ids
00374       libmesh_assert_greater_equal(_next_free_unpartitioned_elem_id,
00375                                    _max_elem_id);
00376       libmesh_assert_greater_equal(_next_free_local_elem_id, _max_elem_id);
00377 
00378       // Use the unpartitioned ids for unpartitioned elems,
00379       // in serial, and temporarily for ghost elems
00380       dof_id_type *next_id = &_next_free_unpartitioned_elem_id;
00381       if (elem_procid == this->processor_id() &&
00382           !this->is_serial())
00383         next_id = &_next_free_local_elem_id;
00384       e->set_id (*next_id);
00385     }
00386 
00387   {
00388     // Advance next_ids up high enough that each is pointing to an
00389     // unused id and any subsequent increments will still point us
00390     // to unused ids
00391     _max_elem_id = std::max(_max_elem_id,
00392                             static_cast<dof_id_type>(e->id()+1));
00393 
00394     if (_next_free_unpartitioned_elem_id < _max_elem_id)
00395       _next_free_unpartitioned_elem_id =
00396         ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
00397         (this->n_processors() + 1) + this->n_processors();
00398     if (_next_free_local_elem_id < _max_elem_id)
00399       _next_free_local_elem_id =
00400         ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
00401         (this->n_processors() + 1) + this->processor_id();
00402 
00403 #ifndef NDEBUG
00404     // We need a const mapvector so we don't inadvertently create
00405     // NULL entries when testing for non-NULL ones
00406     const mapvector<Elem*,dof_id_type>& const_elements = _elements;
00407 #endif
00408     libmesh_assert(!const_elements[_next_free_unpartitioned_elem_id]);
00409     libmesh_assert(!const_elements[_next_free_local_elem_id]);
00410   }
00411 
00412   // Don't try to overwrite existing elems
00413   libmesh_assert (!_elements[e->id()]);
00414 
00415   _elements[e->id()] = e;
00416 
00417   // Try to make the cached elem data more accurate
00418   if (elem_procid == this->processor_id() ||
00419       elem_procid == DofObject::invalid_processor_id)
00420     _n_elem++;
00421 
00422 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00423   if (!e->valid_unique_id() && processor_id() == e->processor_id())
00424     {
00425       e->set_unique_id() = _next_unique_id;
00426       _next_unique_id += this->n_processors();
00427     }
00428 #endif
00429 
00430   // Unpartitioned elems should be added on every processor
00431   // And shouldn't be added in the same batch as ghost elems
00432   // But we might be just adding on processor 0 to
00433   // broadcast later
00434   // #ifdef DEBUG
00435   //   if (elem_procid == DofObject::invalid_processor_id)
00436   //     {
00437   //       dof_id_type elem_id = e->id();
00438   //       this->comm().max(elem_id);
00439   //       libmesh_assert_equal_to (elem_id, e->id());
00440   //     }
00441   // #endif
00442 
00443   return e;
00444 }
00445 
00446 
00447 
00448 Elem* ParallelMesh::insert_elem (Elem* e)
00449 {
00450   if (_elements[e->id()])
00451     this->delete_elem(_elements[e->id()]);
00452 
00453   // Try to make the cached elem data more accurate
00454   processor_id_type elem_procid = e->processor_id();
00455   if (elem_procid == this->processor_id() ||
00456       elem_procid == DofObject::invalid_processor_id)
00457     _n_elem++;
00458 
00459   _elements[e->id()] = e;
00460 
00461   return e;
00462 }
00463 
00464 
00465 
00466 void ParallelMesh::delete_elem(Elem* e)
00467 {
00468   libmesh_assert (e);
00469 
00470   // Try to make the cached elem data more accurate
00471   processor_id_type elem_procid = e->processor_id();
00472   if (elem_procid == this->processor_id() ||
00473       elem_procid == DofObject::invalid_processor_id)
00474     _n_elem--;
00475 
00476   // Delete the element from the BoundaryInfo object
00477   this->get_boundary_info().remove(e);
00478 
00479   // But not yet from the container; we might invalidate
00480   // an iterator that way!
00481 
00482   //_elements.erase(e->id());
00483 
00484   // Instead, we set it to NULL for now
00485 
00486   _elements[e->id()] = NULL;
00487 
00488   // delete the element
00489   delete e;
00490 }
00491 
00492 
00493 
00494 void ParallelMesh::renumber_elem(const dof_id_type old_id,
00495                                  const dof_id_type new_id)
00496 {
00497   Elem *el = _elements[old_id];
00498   libmesh_assert (el);
00499   libmesh_assert_equal_to (el->id(), old_id);
00500 
00501   el->set_id(new_id);
00502   libmesh_assert (!_elements[new_id]);
00503   _elements[new_id] = el;
00504   _elements.erase(old_id);
00505 }
00506 
00507 
00508 
00509 Node* ParallelMesh::add_point (const Point& p,
00510                                const dof_id_type id,
00511                                const processor_id_type proc_id)
00512 {
00513   if (_nodes.count(id))
00514     {
00515       Node *n = _nodes[id];
00516       libmesh_assert (n);
00517       libmesh_assert_equal_to (n->id(), id);
00518 
00519       *n = p;
00520       n->processor_id() = proc_id;
00521 
00522       return n;
00523     }
00524 
00525   Node* n = Node::build(p, id).release();
00526   n->processor_id() = proc_id;
00527 
00528   return ParallelMesh::add_node(n);
00529 }
00530 
00531 
00532 
00533 Node* ParallelMesh::add_node (Node *n)
00534 {
00535   // Don't try to add NULLs!
00536   libmesh_assert(n);
00537 
00538   // Trying to add an existing node is a no-op
00539   if (n->valid_id() && _nodes[n->id()] == n)
00540     return n;
00541 
00542   const processor_id_type node_procid = n->processor_id();
00543 
00544   if (!n->valid_id())
00545     {
00546       // We should only be creating new ids past the end of the range
00547       // of existing ids
00548       libmesh_assert_greater_equal(_next_free_unpartitioned_node_id,
00549                                    _max_node_id);
00550       libmesh_assert_greater_equal(_next_free_local_node_id, _max_node_id);
00551 
00552       // Use the unpartitioned ids for unpartitioned nodes,
00553       // in serial, and temporarily for ghost nodes
00554       dof_id_type *next_id = &_next_free_unpartitioned_node_id;
00555       if (node_procid == this->processor_id() &&
00556           !this->is_serial())
00557         next_id = &_next_free_local_node_id;
00558       n->set_id (*next_id);
00559     }
00560 
00561   {
00562     // Advance next_ids up high enough that each is pointing to an
00563     // unused id and any subsequent increments will still point us
00564     // to unused ids
00565     _max_node_id = std::max(_max_node_id,
00566                             static_cast<dof_id_type>(n->id()+1));
00567 
00568     if (_next_free_unpartitioned_node_id < _max_node_id)
00569       _next_free_unpartitioned_node_id =
00570         ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
00571         (this->n_processors() + 1) + this->n_processors();
00572     if (_next_free_local_node_id < _max_node_id)
00573       _next_free_local_node_id =
00574         ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
00575         (this->n_processors() + 1) + this->processor_id();
00576 
00577 #ifndef NDEBUG
00578     // We need a const mapvector so we don't inadvertently create
00579     // NULL entries when testing for non-NULL ones
00580     const mapvector<Node*,dof_id_type>& const_nodes = _nodes;
00581 #endif
00582     libmesh_assert(!const_nodes[_next_free_unpartitioned_node_id]);
00583     libmesh_assert(!const_nodes[_next_free_local_node_id]);
00584   }
00585 
00586   // Don't try to overwrite existing nodes
00587   libmesh_assert (!_nodes[n->id()]);
00588 
00589   _nodes[n->id()] = n;
00590 
00591   // Try to make the cached node data more accurate
00592   if (node_procid == this->processor_id() ||
00593       node_procid == DofObject::invalid_processor_id)
00594     _n_nodes++;
00595 
00596 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00597   if (!n->valid_unique_id() && processor_id() == n->processor_id())
00598     {
00599       n->set_unique_id() = _next_unique_id;
00600       _next_unique_id += this->n_processors();
00601     }
00602 #endif
00603 
00604 
00605   // Unpartitioned nodes should be added on every processor
00606   // And shouldn't be added in the same batch as ghost nodes
00607   // But we might be just adding on processor 0 to
00608   // broadcast later
00609   // #ifdef DEBUG
00610   //   if (node_procid == DofObject::invalid_processor_id)
00611   //     {
00612   //       dof_id_type node_id = n->id();
00613   //       this->comm().max(node_id);
00614   //       libmesh_assert_equal_to (node_id, n->id());
00615   //     }
00616   // #endif
00617 
00618   return n;
00619 }
00620 
00621 
00622 
00623 Node* ParallelMesh::insert_node(Node* n)
00624 {
00625   return ParallelMesh::add_node(n);
00626 }
00627 
00628 
00629 
00630 void ParallelMesh::delete_node(Node* n)
00631 {
00632   libmesh_assert(n);
00633   libmesh_assert(_nodes[n->id()]);
00634 
00635   // Try to make the cached elem data more accurate
00636   processor_id_type node_procid = n->processor_id();
00637   if (node_procid == this->processor_id() ||
00638       node_procid == DofObject::invalid_processor_id)
00639     _n_nodes--;
00640 
00641   // Delete the node from the BoundaryInfo object
00642   this->get_boundary_info().remove(n);
00643 
00644   // But not yet from the container; we might invalidate
00645   // an iterator that way!
00646 
00647   //_nodes.erase(n->id());
00648 
00649   // Instead, we set it to NULL for now
00650 
00651   _nodes[n->id()] = NULL;
00652 
00653   // delete the node
00654   delete n;
00655 }
00656 
00657 
00658 
00659 void ParallelMesh::renumber_node(const dof_id_type old_id,
00660                                  const dof_id_type new_id)
00661 {
00662   Node *nd = _nodes[old_id];
00663   libmesh_assert (nd);
00664   libmesh_assert_equal_to (nd->id(), old_id);
00665 
00666   nd->set_id(new_id);
00667   libmesh_assert (!_nodes[new_id]);
00668   _nodes[new_id] = nd;
00669   _nodes.erase(old_id);
00670 }
00671 
00672 
00673 
00674 void ParallelMesh::clear ()
00675 {
00676   // Call parent clear function
00677   MeshBase::clear();
00678 
00679 
00680   // Clear our elements and nodes
00681   {
00682     elem_iterator_imp        it = _elements.begin();
00683     const elem_iterator_imp end = _elements.end();
00684 
00685     // There is no need to remove the elements from
00686     // the BoundaryInfo data structure since we
00687     // already cleared it.
00688     for (; it != end; ++it)
00689       delete *it;
00690 
00691     _elements.clear();
00692   }
00693 
00694   // clear the nodes data structure
00695   {
00696     node_iterator_imp it  = _nodes.begin();
00697     node_iterator_imp end = _nodes.end();
00698 
00699     // There is no need to remove the nodes from
00700     // the BoundaryInfo data structure since we
00701     // already cleared it.
00702     for (; it != end; ++it)
00703       delete *it;
00704 
00705     _nodes.clear();
00706   }
00707 
00708   // We're no longer distributed if we were before
00709   _is_serial = true;
00710 
00711   // Correct our caches
00712   _n_nodes = 0;
00713   _n_elem = 0;
00714   _max_node_id = 0;
00715   _max_elem_id = 0;
00716   _next_free_local_node_id = this->processor_id();
00717   _next_free_local_elem_id = this->processor_id();
00718   _next_free_unpartitioned_node_id = this->n_processors();
00719   _next_free_unpartitioned_elem_id = this->n_processors();
00720 }
00721 
00722 
00723 
00724 void ParallelMesh::redistribute ()
00725 {
00726   // If this is a truly parallel mesh, go through the redistribution/gather/delete remote steps
00727   if (!this->is_serial())
00728     {
00729       // Construct a MeshCommunication object to actually redistribute the nodes
00730       // and elements according to the partitioner, and then to re-gather the neighbors.
00731       MeshCommunication mc;
00732       mc.redistribute(*this);
00733 
00734       this->update_parallel_id_counts();
00735 
00736       // Is this necessary?  If we are called from prepare_for_use(), this will be called
00737       // anyway... but users can always call partition directly, in which case we do need
00738       // to call delete_remote_elements()...
00739       //
00740       // Regardless of whether it's necessary, it isn't safe.  We
00741       // haven't communicated new node processor_ids yet, and we can't
00742       // delete nodes until we do.
00743       // this->delete_remote_elements();
00744     }
00745 }
00746 
00747 
00748 
00749 void ParallelMesh::update_post_partitioning ()
00750 {
00751   // this->recalculate_n_partitions();
00752 
00753   // Partitioning changes our numbers of unpartitioned objects
00754   this->update_parallel_id_counts();
00755 }
00756 
00757 
00758 
00759 template <typename T>
00760 void ParallelMesh::libmesh_assert_valid_parallel_object_ids
00761 (const mapvector<T*,dof_id_type> &objects) const
00762 {
00763   // This function must be run on all processors at once
00764   parallel_object_only();
00765 
00766   const dof_id_type pmax_node_id = this->parallel_max_node_id();
00767   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
00768   const dof_id_type pmax_id = std::max(pmax_node_id, pmax_elem_id);
00769 
00770   for (dof_id_type i=0; i != pmax_id; ++i)
00771     {
00772       T* obj = objects[i]; // Returns NULL if there's no map entry
00773 
00774       dof_id_type dofid = obj && obj->valid_id() ?
00775         obj->id() : DofObject::invalid_id;
00776       // Local lookups by id should return the requested object
00777       libmesh_assert(!obj || obj->id() == i);
00778 
00779       dof_id_type min_dofid = dofid;
00780       this->comm().min(min_dofid);
00781       // All processors with an object should agree on id
00782       libmesh_assert (!obj || dofid == min_dofid);
00783 
00784       dof_id_type procid = obj && obj->valid_processor_id() ?
00785         obj->processor_id() : DofObject::invalid_processor_id;
00786 
00787       dof_id_type min_procid = procid;
00788       this->comm().min(min_procid);
00789 
00790       // All processors with an object should agree on processor id
00791       libmesh_assert (!obj || procid == min_procid);
00792 
00793       // Either:
00794       // 1.) I own this elem (min_procid == this->processor_id()) *and* I have a valid pointer to it (obj != NULL)
00795       // or
00796       // 2.) I don't own this elem (min_procid != this->processor_id()).  (In this case I may or may not have a valid pointer to it.)
00797 
00798       // Original assert logic
00799       // libmesh_assert (min_procid != this->processor_id() || obj);
00800 
00801       // More human-understandable logic...
00802       libmesh_assert (
00803                       ((min_procid == this->processor_id()) && obj)
00804                       ||
00805                       (min_procid != this->processor_id())
00806                       );
00807     }
00808 }
00809 
00810 
00811 
00812 void ParallelMesh::libmesh_assert_valid_parallel_ids () const
00813 {
00814   this->libmesh_assert_valid_parallel_object_ids (this->_elements);
00815   this->libmesh_assert_valid_parallel_object_ids (this->_nodes);
00816 }
00817 
00818 
00819 
00820 void ParallelMesh::libmesh_assert_valid_parallel_flags () const
00821 {
00822 #ifdef LIBMESH_ENABLE_AMR
00823   // This function must be run on all processors at once
00824   parallel_object_only();
00825 
00826   dof_id_type pmax_elem_id = this->parallel_max_elem_id();
00827 
00828   for (dof_id_type i=0; i != pmax_elem_id; ++i)
00829     {
00830       Elem* el = _elements[i]; // Returns NULL if there's no map entry
00831 
00832       unsigned int refinement_flag   = el ?
00833         static_cast<unsigned int> (el->refinement_flag()) : libMesh::invalid_uint;
00834 #ifndef NDEBUG
00835       unsigned int p_refinement_flag = el ?
00836         static_cast<unsigned int> (el->p_refinement_flag()) : libMesh::invalid_uint;
00837 #endif
00838 
00839       unsigned int min_rflag = refinement_flag;
00840       this->comm().min(min_rflag);
00841       // All processors with this element should agree on flag
00842       libmesh_assert (!el || min_rflag == refinement_flag);
00843 
00844 #ifndef NDEBUG
00845       unsigned int min_pflag = p_refinement_flag;
00846 #endif
00847       // All processors with this element should agree on flag
00848       libmesh_assert (!el || min_pflag == p_refinement_flag);
00849     }
00850 #endif // LIBMESH_ENABLE_AMR
00851 }
00852 
00853 
00854 
00855 template <typename T>
00856 dof_id_type ParallelMesh::renumber_dof_objects
00857 (mapvector<T*,dof_id_type> &objects)
00858 {
00859   // This function must be run on all processors at once
00860   parallel_object_only();
00861 
00862   typedef typename mapvector<T*,dof_id_type>::veclike_iterator object_iterator;
00863 
00864   // In parallel we may not know what objects other processors have.
00865   // Start by figuring out how many
00866   dof_id_type unpartitioned_objects = 0;
00867 
00868   std::vector<dof_id_type>
00869     ghost_objects_from_proc(this->n_processors(), 0);
00870 
00871   object_iterator it  = objects.begin();
00872   object_iterator end = objects.end();
00873 
00874   for (; it != end;)
00875     {
00876       T *obj = *it;
00877 
00878       // Remove any NULL container entries while we're here,
00879       // being careful not to invalidate our iterator
00880       if (!*it)
00881         objects.erase(it++);
00882       else
00883         {
00884           processor_id_type obj_procid = obj->processor_id();
00885           if (obj_procid == DofObject::invalid_processor_id)
00886             unpartitioned_objects++;
00887           else
00888             ghost_objects_from_proc[obj_procid]++;
00889           ++it;
00890         }
00891     }
00892 
00893   std::vector<dof_id_type> objects_on_proc(this->n_processors(), 0);
00894   this->comm().allgather(ghost_objects_from_proc[this->processor_id()],
00895                          objects_on_proc);
00896 
00897 #ifndef NDEBUG
00898   libmesh_assert(this->comm().verify(unpartitioned_objects));
00899   for (processor_id_type p=0; p != this->n_processors(); ++p)
00900     libmesh_assert_less_equal (ghost_objects_from_proc[p], objects_on_proc[p]);
00901 #endif
00902 
00903   // We'll renumber objects in blocks by processor id
00904   std::vector<dof_id_type> first_object_on_proc(this->n_processors());
00905   for (processor_id_type i=1; i != this->n_processors(); ++i)
00906     first_object_on_proc[i] = first_object_on_proc[i-1] +
00907       objects_on_proc[i-1];
00908   dof_id_type next_id = first_object_on_proc[this->processor_id()];
00909   dof_id_type first_free_id =
00910     first_object_on_proc[this->n_processors()-1] +
00911     objects_on_proc[this->n_processors()-1] +
00912     unpartitioned_objects;
00913 
00914   // First set new local object ids and build request sets
00915   // for non-local object ids
00916 
00917   // Request sets to send to each processor
00918   std::vector<std::vector<dof_id_type> >
00919     requested_ids(this->n_processors());
00920 
00921 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00922   std::vector<std::vector<unique_id_type> >
00923     requested_unique_ids(this->n_processors());
00924 #endif
00925 
00926   // We know how many objects live on each processor, so reseve() space for
00927   // each.
00928   for (processor_id_type p=0; p != this->n_processors(); ++p)
00929     if (p != this->processor_id())
00930       {
00931         requested_ids[p].reserve(ghost_objects_from_proc[p]);
00932 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00933         requested_unique_ids[p].reserve(ghost_objects_from_proc[p]);
00934 #endif
00935       }
00936 
00937   end = objects.end();
00938   for (it = objects.begin(); it != end; ++it)
00939     {
00940       T *obj = *it;
00941       if (obj->processor_id() == this->processor_id())
00942         obj->set_id(next_id++);
00943       else if (obj->processor_id() != DofObject::invalid_processor_id)
00944         {
00945           requested_ids[obj->processor_id()].push_back(obj->id());
00946 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00947           // It's possible to have an invalid id for dofs not owned by this process.
00948           // We'll assert that they match on the receiving end.
00949           requested_unique_ids[obj->processor_id()].push_back(obj->valid_unique_id() ? obj-> unique_id() : DofObject::invalid_unique_id);
00950 #endif
00951         }
00952     }
00953 
00954   // Next set ghost object ids from other processors
00955   if (this->n_processors() > 1)
00956     {
00957       for (processor_id_type p=1; p != this->n_processors(); ++p)
00958         {
00959           // Trade my requests with processor procup and procdown
00960           processor_id_type procup = cast_int<processor_id_type>
00961             ((this->processor_id() + p) % this->n_processors());
00962           processor_id_type procdown = cast_int<processor_id_type>
00963             ((this->n_processors() + this->processor_id() - p) %
00964              this->n_processors());
00965           std::vector<dof_id_type> request_to_fill;
00966           this->comm().send_receive(procup, requested_ids[procup],
00967                                     procdown, request_to_fill);
00968 
00969 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00970           std::vector<unique_id_type> unique_request_to_fill;
00971           this->comm().send_receive(procup, requested_unique_ids[procup],
00972                                     procdown, unique_request_to_fill);
00973           std::vector<unique_id_type> new_unique_ids(unique_request_to_fill.size());
00974 #endif
00975 
00976           // Fill those requests
00977           std::vector<dof_id_type> new_ids(request_to_fill.size());
00978           for (std::size_t i=0; i != request_to_fill.size(); ++i)
00979             {
00980               T *obj = objects[request_to_fill[i]];
00981               libmesh_assert(obj);
00982               libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
00983               new_ids[i] = obj->id();
00984 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00985               new_unique_ids[i] = obj->valid_unique_id() ? obj->unique_id() : DofObject::invalid_unique_id;
00986 #endif
00987 
00988               libmesh_assert_greater_equal (new_ids[i],
00989                                             first_object_on_proc[this->processor_id()]);
00990               libmesh_assert_less (new_ids[i],
00991                                    first_object_on_proc[this->processor_id()] +
00992                                    objects_on_proc[this->processor_id()]);
00993             }
00994 
00995           // Trade back the results
00996           std::vector<dof_id_type> filled_request;
00997           this->comm().send_receive(procdown, new_ids,
00998                                     procup, filled_request);
00999 
01000 #ifdef LIBMESH_ENABLE_UNIQUE_ID
01001           std::vector<unique_id_type> unique_filled_request;
01002           this->comm().send_receive(procdown, new_unique_ids,
01003                                     procup, unique_filled_request);
01004 #endif
01005 
01006           // And copy the id changes we've now been informed of
01007           for (std::size_t i=0; i != filled_request.size(); ++i)
01008             {
01009               T *obj = objects[requested_ids[procup][i]];
01010               libmesh_assert (obj);
01011               libmesh_assert_equal_to (obj->processor_id(), procup);
01012               libmesh_assert_greater_equal (filled_request[i],
01013                                             first_object_on_proc[procup]);
01014               libmesh_assert_less (filled_request[i],
01015                                    first_object_on_proc[procup] +
01016                                    objects_on_proc[procup]);
01017               obj->set_id(filled_request[i]);
01018 
01019 #ifdef LIBMESH_ENABLE_UNIQUE_ID
01020               if (!obj->valid_unique_id() && unique_filled_request[i] != DofObject::invalid_unique_id)
01021                 obj->set_unique_id() = unique_filled_request[i];
01022 #endif
01023             }
01024         }
01025     }
01026 
01027   // Next set unpartitioned object ids
01028   next_id = 0;
01029   for (processor_id_type i=0; i != this->n_processors(); ++i)
01030     next_id += objects_on_proc[i];
01031   for (it = objects.begin(); it != end; ++it)
01032     {
01033       T *obj = *it;
01034       if (obj->processor_id() == DofObject::invalid_processor_id)
01035         obj->set_id(next_id++);
01036     }
01037 
01038   // Finally shuffle around objects so that container indices
01039   // match ids
01040   end = objects.end();
01041   for (it = objects.begin(); it != end;)
01042     {
01043       T *obj = *it;
01044       if (obj) // don't try shuffling already-NULL entries
01045         {
01046           T *next = objects[obj->id()];
01047           // If we have to move this object
01048           if (next != obj)
01049             {
01050               // NULL out its original position for now
01051               // (our shuffling may put another object there shortly)
01052               *it = NULL;
01053 
01054               // There may already be another object with this id that
01055               // needs to be moved itself
01056               while (next)
01057                 {
01058                   // We shouldn't be trying to give two objects the
01059                   // same id
01060                   libmesh_assert_not_equal_to (next->id(), obj->id());
01061                   objects[obj->id()] = obj;
01062                   obj = next;
01063                   next = objects[obj->id()];
01064                 }
01065               objects[obj->id()] = obj;
01066             }
01067         }
01068       // Remove any container entries that were left as NULL,
01069       // being careful not to invalidate our iterator
01070       if (!*it)
01071         objects.erase(it++);
01072       else
01073         ++it;
01074     }
01075 
01076   return first_free_id;
01077 }
01078 
01079 
01080 void ParallelMesh::renumber_nodes_and_elements ()
01081 {
01082   parallel_object_only();
01083 
01084   if (_skip_renumber_nodes_and_elements)
01085     {
01086       this->update_parallel_id_counts();
01087       return;
01088     }
01089 
01090   START_LOG("renumber_nodes_and_elements()", "ParallelMesh");
01091 
01092 #ifdef DEBUG
01093   // Make sure our ids and flags are consistent
01094   this->libmesh_assert_valid_parallel_ids();
01095   this->libmesh_assert_valid_parallel_flags();
01096 #endif
01097 
01098   std::set<dof_id_type> used_nodes;
01099 
01100   // flag the nodes we need
01101   {
01102     element_iterator  it = elements_begin();
01103     element_iterator end = elements_end();
01104 
01105     for (; it != end; ++it)
01106       {
01107         Elem *el = *it;
01108 
01109         for (unsigned int n=0; n != el->n_nodes(); ++n)
01110           used_nodes.insert(el->node(n));
01111       }
01112   }
01113 
01114   // Nodes not connected to any local elements, and NULL node entries
01115   // in our container, are deleted
01116   {
01117     node_iterator_imp  it = _nodes.begin();
01118     node_iterator_imp end = _nodes.end();
01119 
01120     for (; it != end;)
01121       {
01122         Node *nd = *it;
01123         if (!nd)
01124           _nodes.erase(it++);
01125         else if (!used_nodes.count(nd->id()))
01126           {
01127             // remove any boundary information associated with
01128             // this node
01129             this->get_boundary_info().remove (nd);
01130 
01131             // delete the node
01132             delete nd;
01133 
01134             _nodes.erase(it++);
01135           }
01136         else
01137           ++it;
01138       }
01139   }
01140 
01141   // Finally renumber all the elements
01142   _n_elem = this->renumber_dof_objects (this->_elements);
01143 
01144   // and all the remaining nodes
01145   _n_nodes = this->renumber_dof_objects (this->_nodes);
01146 
01147   // And figure out what IDs we should use when adding new nodes and
01148   // new elements
01149   this->update_parallel_id_counts();
01150 
01151   // Make sure our caches are up to date and our
01152   // DofObjects are well packed
01153 #ifdef DEBUG
01154   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
01155   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
01156   const dof_id_type pmax_node_id = this->parallel_max_node_id();
01157   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
01158   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
01159   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
01160   libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
01161   libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
01162 
01163   // Make sure our ids and flags are consistent
01164   this->libmesh_assert_valid_parallel_ids();
01165   this->libmesh_assert_valid_parallel_flags();
01166 
01167   // And make sure we've made our numbering monotonic
01168   MeshTools::libmesh_assert_valid_elem_ids(*this);
01169 #endif
01170 
01171   STOP_LOG("renumber_nodes_and_elements()", "ParallelMesh");
01172 }
01173 
01174 
01175 
01176 void ParallelMesh::fix_broken_node_and_element_numbering ()
01177 {
01178   // We need access to iterators for the underlying containers,
01179   // not the mapvector<> reimplementations.
01180   mapvector<Node*,dof_id_type>::maptype &nodes = this->_nodes;
01181   mapvector<Elem*,dof_id_type>::maptype &elems = this->_elements;
01182 
01183   // Nodes first
01184   {
01185     mapvector<Node*,dof_id_type>::maptype::iterator
01186       it  = nodes.begin(),
01187       end = nodes.end();
01188 
01189     for (; it != end; ++it)
01190       if (it->second != NULL)
01191         it->second->set_id() = it->first;
01192   }
01193 
01194   // Elements next
01195   {
01196     mapvector<Elem*,dof_id_type>::maptype::iterator
01197       it  = elems.begin(),
01198       end = elems.end();
01199 
01200     for (; it != end; ++it)
01201       if (it->second != NULL)
01202         it->second->set_id() = it->first;
01203   }
01204 }
01205 
01206 
01207 
01208 dof_id_type ParallelMesh::n_active_elem () const
01209 {
01210   parallel_object_only();
01211 
01212   // Get local active elements first
01213   dof_id_type active_elements =
01214     static_cast<dof_id_type>(std::distance (this->active_local_elements_begin(),
01215                                             this->active_local_elements_end()));
01216   this->comm().sum(active_elements);
01217 
01218   // Then add unpartitioned active elements, which should exist on
01219   // every processor
01220   active_elements +=
01221     static_cast<dof_id_type>(std::distance
01222                              (this->active_pid_elements_begin(DofObject::invalid_processor_id),
01223                               this->active_pid_elements_end(DofObject::invalid_processor_id)));
01224   return active_elements;
01225 }
01226 
01227 
01228 
01229 void ParallelMesh::delete_remote_elements()
01230 {
01231 #ifdef DEBUG
01232   // Make sure our neighbor links are all fine
01233   MeshTools::libmesh_assert_valid_neighbors(*this);
01234 
01235   // And our child/parent links, and our flags
01236   MeshTools::libmesh_assert_valid_refinement_tree(*this);
01237 
01238   // Make sure our ids and flags are consistent
01239   this->libmesh_assert_valid_parallel_ids();
01240   this->libmesh_assert_valid_parallel_flags();
01241 
01242   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
01243   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
01244   const dof_id_type pmax_node_id = this->parallel_max_node_id();
01245   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
01246   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
01247   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
01248 #endif
01249 
01250   _is_serial = false;
01251   MeshCommunication().delete_remote_elements(*this, _extra_ghost_elems);
01252 
01253   libmesh_assert_equal_to (this->max_elem_id(), this->parallel_max_elem_id());
01254 
01255   // Now make sure the containers actually shrink - strip
01256   // any newly-created NULL voids out of the element array
01257   mapvector<Elem*,dof_id_type>::veclike_iterator e_it        = _elements.begin();
01258   const mapvector<Elem*,dof_id_type>::veclike_iterator e_end = _elements.end();
01259   for (; e_it != e_end;)
01260     if (!*e_it)
01261       _elements.erase(e_it++);
01262     else
01263       ++e_it;
01264 
01265   mapvector<Node*,dof_id_type>::veclike_iterator n_it        = _nodes.begin();
01266   const mapvector<Node*,dof_id_type>::veclike_iterator n_end = _nodes.end();
01267   for (; n_it != n_end;)
01268     if (!*n_it)
01269       _nodes.erase(n_it++);
01270     else
01271       ++n_it;
01272 
01273   // We may have deleted no-longer-connected nodes or coarsened-away
01274   // elements; let's update our caches.
01275   this->update_parallel_id_counts();
01276 
01277 #ifdef DEBUG
01278   // We might not have well-packed objects if the user didn't allow us
01279   // to renumber
01280   // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
01281   // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
01282 
01283   // Make sure our neighbor links are all fine
01284   MeshTools::libmesh_assert_valid_neighbors(*this);
01285 
01286   // And our child/parent links, and our flags
01287   MeshTools::libmesh_assert_valid_refinement_tree(*this);
01288 
01289   // Make sure our ids and flags are consistent
01290   this->libmesh_assert_valid_parallel_ids();
01291   this->libmesh_assert_valid_parallel_flags();
01292 #endif
01293 }
01294 
01295 
01296 void ParallelMesh::add_extra_ghost_elem(Elem* e)
01297 {
01298   // First add the elem like normal
01299   add_elem(e);
01300 
01301   // Now add it to the set that won't be deleted when we call
01302   // delete_remote_elements()
01303   _extra_ghost_elems.insert(e);
01304 }
01305 
01306 
01307 void ParallelMesh::allgather()
01308 {
01309   if (_is_serial)
01310     return;
01311   _is_serial = true;
01312   MeshCommunication().allgather(*this);
01313 
01314   // Make sure our caches are up to date and our
01315   // DofObjects are well packed
01316 #ifdef DEBUG
01317   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
01318   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
01319   const dof_id_type pmax_node_id = this->parallel_max_node_id();
01320   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
01321   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
01322   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
01323 
01324   // If we've disabled renumbering we can't be sure we're contiguous
01325   // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
01326   // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
01327 
01328   // Make sure our neighbor links are all fine
01329   MeshTools::libmesh_assert_valid_neighbors(*this);
01330 
01331   // Make sure our ids and flags are consistent
01332   this->libmesh_assert_valid_parallel_ids();
01333   this->libmesh_assert_valid_parallel_flags();
01334 #endif
01335 }
01336 
01337 #ifdef LIBMESH_ENABLE_UNIQUE_ID
01338 void ParallelMesh::assign_unique_ids()
01339 {
01340   {
01341     elem_iterator_imp        it = _elements.begin();
01342     const elem_iterator_imp end = _elements.end();
01343 
01344     for (; it != end; ++it)
01345       if ((*it) && ! (*it)->valid_unique_id() && processor_id() == (*it)->processor_id())
01346         {
01347           (*it)->set_unique_id() = _next_unique_id;
01348           _next_unique_id += this->n_processors();
01349         }
01350   }
01351 
01352   {
01353     node_iterator_imp it  = _nodes.begin();
01354     node_iterator_imp end = _nodes.end();
01355 
01356     for (; it != end; ++it)
01357       if ((*it) && ! (*it)->valid_unique_id() && processor_id() == (*it)->processor_id())
01358         {
01359           (*it)->set_unique_id() = _next_unique_id;
01360           _next_unique_id += this->n_processors();
01361         }
01362   }
01363 }
01364 #endif
01365 
01366 
01367 } // namespace libMesh