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