$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // C++ Includes ----------------------------------- 00021 #include <numeric> 00022 00023 // Local Includes ----------------------------------- 00024 #include "libmesh/boundary_info.h" 00025 #include "libmesh/elem.h" 00026 #include "libmesh/libmesh_config.h" 00027 #include "libmesh/libmesh_common.h" 00028 #include "libmesh/libmesh_logging.h" 00029 #include "libmesh/mesh_base.h" 00030 #include "libmesh/mesh_communication.h" 00031 #include "libmesh/mesh_inserter_iterator.h" 00032 #include "libmesh/mesh_tools.h" 00033 #include "libmesh/parallel.h" 00034 #include "libmesh/parallel_elem.h" 00035 #include "libmesh/parallel_mesh.h" 00036 #include "libmesh/parallel_node.h" 00037 #include "libmesh/parallel_ghost_sync.h" 00038 #include "libmesh/utility.h" 00039 #include "libmesh/remote_elem.h" 00040 00041 00042 00043 //----------------------------------------------- 00044 // anonymous namespace for implementation details 00045 namespace { 00046 00047 using namespace libMesh; 00048 00055 struct CompareElemIdsByLevel 00056 { 00057 bool operator()(const Elem *a, 00058 const Elem *b) const 00059 { 00060 libmesh_assert (a); 00061 libmesh_assert (b); 00062 const unsigned int 00063 al = a->level(), bl = b->level(); 00064 const dof_id_type 00065 aid = a->id(), bid = b->id(); 00066 00067 return (al == bl) ? aid < bid : al < bl; 00068 } 00069 }; 00070 } 00071 00072 00073 namespace libMesh 00074 { 00075 00076 00077 // ------------------------------------------------------------ 00078 // MeshCommunication class members 00079 void MeshCommunication::clear () 00080 { 00081 // _neighboring_processors.clear(); 00082 } 00083 00084 00085 00086 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings 00087 // ------------------------------------------------------------ 00088 void MeshCommunication::redistribute (ParallelMesh &) const 00089 { 00090 // no MPI == one processor, no redistribution 00091 return; 00092 } 00093 #else 00094 // ------------------------------------------------------------ 00095 void MeshCommunication::redistribute (ParallelMesh &mesh) const 00096 { 00097 // This method will be called after a new partitioning has been 00098 // assigned to the elements. This partitioning was defined in 00099 // terms of the active elements, and "trickled down" to the 00100 // parents and nodes as to be consistent. 00101 // 00102 // The point is that the entire concept of local elements is 00103 // kinda shaky in this method. Elements which were previously 00104 // local may now be assigned to other processors, so we need to 00105 // send those off. Similarly, we need to accept elements from 00106 // other processors. 00107 // 00108 // The approach is as follows: 00109 // (1) send all elements we have stored to their proper homes 00110 // (2) receive elements from all processors, watching for duplicates 00111 // (3) deleting all nonlocal elements elements 00112 // (4) obtaining required ghost elements from neighboring processors 00113 libmesh_parallel_only(mesh.comm()); 00114 libmesh_assert (!mesh.is_serial()); 00115 libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(), 00116 mesh.unpartitioned_elements_end()) == 0); 00117 00118 START_LOG("redistribute()","MeshCommunication"); 00119 00120 // Get a few unique message tags to use in communications; we'll 00121 // default to some numbers around pi*1000 00122 Parallel::MessageTag 00123 nodestag = mesh.comm().get_unique_tag(3141), 00124 elemstag = mesh.comm().get_unique_tag(3142); 00125 00126 // Figure out how many nodes and elements we have which are assigned to each 00127 // processor. send_n_nodes_and_elem_per_proc contains the number of nodes/elements 00128 // we will be sending to each processor, recv_n_nodes_and_elem_per_proc contains 00129 // the number of nodes/elements we will be receiving from each processor. 00130 // Format: 00131 // send_n_nodes_and_elem_per_proc[2*pid+0] = number of nodes to send to pid 00132 // send_n_nodes_and_elem_per_proc[2*pid+1] = number of elements to send to pid 00133 std::vector<dof_id_type> send_n_nodes_and_elem_per_proc(2*mesh.n_processors(), 0); 00134 00135 std::vector<Parallel::Request> 00136 node_send_requests, element_send_requests; 00137 00138 for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) 00139 if (pid != mesh.processor_id()) // don't send to ourselves!! 00140 { 00141 // Build up a list of nodes and elements to send to processor pid. 00142 // We will certainly send all the elements assigned to this processor, 00143 // but we will also ship off any other elements which touch 00144 // their nodes. 00145 std::set<const Node*> connected_nodes; 00146 { 00147 MeshBase::const_element_iterator elem_it = mesh.pid_elements_begin(pid); 00148 const MeshBase::const_element_iterator elem_end = mesh.pid_elements_end(pid); 00149 00150 for (; elem_it!=elem_end; ++elem_it) 00151 { 00152 const Elem* elem = *elem_it; 00153 00154 for (unsigned int n=0; n<elem->n_nodes(); n++) 00155 connected_nodes.insert (elem->get_node(n)); 00156 } 00157 } 00158 00159 std::set<const Elem*, CompareElemIdsByLevel> elements_to_send; 00160 { 00161 MeshBase::const_element_iterator elem_it = mesh.elements_begin(); 00162 const MeshBase::const_element_iterator elem_end = mesh.elements_end(); 00163 00164 for (; elem_it!=elem_end; ++elem_it) 00165 { 00166 const Elem* elem = *elem_it; 00167 00168 for (unsigned int n=0; n<elem->n_nodes(); n++) 00169 if (connected_nodes.count(elem->get_node(n))) 00170 elements_to_send.insert (elem); 00171 } 00172 } 00173 00174 connected_nodes.clear(); 00175 { 00176 std::set<const Elem*, CompareElemIdsByLevel>::iterator 00177 elem_it = elements_to_send.begin(), 00178 elem_end = elements_to_send.end(); 00179 00180 for (; elem_it!=elem_end; ++elem_it) 00181 { 00182 const Elem* elem = *elem_it; 00183 00184 for (unsigned int n=0; n<elem->n_nodes(); n++) 00185 connected_nodes.insert(elem->get_node(n)); 00186 } 00187 } 00188 00189 // the number of nodes we will ship to pid 00190 send_n_nodes_and_elem_per_proc[2*pid+0] = 00191 cast_int<dof_id_type>(connected_nodes.size()); 00192 00193 // send any nodes off to the destination processor 00194 if (!connected_nodes.empty()) 00195 { 00196 node_send_requests.push_back(Parallel::request()); 00197 00198 mesh.comm().send_packed_range (pid, 00199 &mesh, 00200 connected_nodes.begin(), 00201 connected_nodes.end(), 00202 node_send_requests.back(), 00203 nodestag); 00204 } 00205 00206 // the number of elements we will send to this processor 00207 send_n_nodes_and_elem_per_proc[2*pid+1] = 00208 cast_int<dof_id_type>(elements_to_send.size()); 00209 00210 if (!elements_to_send.empty()) 00211 { 00212 // send the elements off to the destination processor 00213 element_send_requests.push_back(Parallel::request()); 00214 00215 mesh.comm().send_packed_range (pid, 00216 &mesh, 00217 elements_to_send.begin(), 00218 elements_to_send.end(), 00219 element_send_requests.back(), 00220 elemstag); 00221 } 00222 } 00223 00224 std::vector<dof_id_type> recv_n_nodes_and_elem_per_proc(send_n_nodes_and_elem_per_proc); 00225 00226 mesh.comm().alltoall (recv_n_nodes_and_elem_per_proc); 00227 00228 // In general we will only need to communicate with a subset of the other processors. 00229 // I can't immediately think of a case where we will send elements but not nodes, but 00230 // these are only bools and we have the information anyway... 00231 std::vector<bool> 00232 send_node_pair(mesh.n_processors(),false), send_elem_pair(mesh.n_processors(),false), 00233 recv_node_pair(mesh.n_processors(),false), recv_elem_pair(mesh.n_processors(),false); 00234 00235 unsigned int 00236 n_send_node_pairs=0, n_send_elem_pairs=0, 00237 n_recv_node_pairs=0, n_recv_elem_pairs=0; 00238 00239 for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) 00240 { 00241 if (send_n_nodes_and_elem_per_proc[2*pid+0]) // we have nodes to send 00242 { 00243 send_node_pair[pid] = true; 00244 n_send_node_pairs++; 00245 } 00246 00247 if (send_n_nodes_and_elem_per_proc[2*pid+1]) // we have elements to send 00248 { 00249 send_elem_pair[pid] = true; 00250 n_send_elem_pairs++; 00251 } 00252 00253 if (recv_n_nodes_and_elem_per_proc[2*pid+0]) // we have nodes to receive 00254 { 00255 recv_node_pair[pid] = true; 00256 n_recv_node_pairs++; 00257 } 00258 00259 if (recv_n_nodes_and_elem_per_proc[2*pid+1]) // we have elements to receive 00260 { 00261 recv_elem_pair[pid] = true; 00262 n_recv_elem_pairs++; 00263 } 00264 } 00265 libmesh_assert_equal_to (n_send_node_pairs, node_send_requests.size()); 00266 libmesh_assert_equal_to (n_send_elem_pairs, element_send_requests.size()); 00267 00268 // Receive nodes. 00269 // We now know how many processors will be sending us nodes. 00270 for (unsigned int node_comm_step=0; node_comm_step<n_recv_node_pairs; node_comm_step++) 00271 // but we don't necessarily want to impose an ordering, so 00272 // just process whatever message is available next. 00273 mesh.comm().receive_packed_range (Parallel::any_source, 00274 &mesh, 00275 mesh_inserter_iterator<Node>(mesh), 00276 nodestag); 00277 00278 // Receive elements. 00279 // Similarly we know how many processors are sending us elements, 00280 // but we don't really care in what order we receive them. 00281 for (unsigned int elem_comm_step=0; elem_comm_step<n_recv_elem_pairs; elem_comm_step++) 00282 mesh.comm().receive_packed_range (Parallel::any_source, 00283 &mesh, 00284 mesh_inserter_iterator<Elem>(mesh), 00285 elemstag); 00286 00287 // Wait for all sends to complete 00288 Parallel::wait (node_send_requests); 00289 Parallel::wait (element_send_requests); 00290 00291 // Check on the redistribution consistency 00292 #ifdef DEBUG 00293 MeshTools::libmesh_assert_equal_n_systems(mesh); 00294 00295 MeshTools::libmesh_assert_valid_refinement_tree(mesh); 00296 #endif 00297 00298 STOP_LOG("redistribute()","MeshCommunication"); 00299 } 00300 #endif // LIBMESH_HAVE_MPI 00301 00302 00303 00304 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings 00305 // ------------------------------------------------------------ 00306 void MeshCommunication::gather_neighboring_elements (ParallelMesh &) const 00307 { 00308 // no MPI == one processor, no need for this method... 00309 return; 00310 } 00311 #else 00312 // ------------------------------------------------------------ 00313 void MeshCommunication::gather_neighboring_elements (ParallelMesh &mesh) const 00314 { 00315 // Don't need to do anything if there is 00316 // only one processor. 00317 if (mesh.n_processors() == 1) 00318 return; 00319 00320 // This function must be run on all processors at once 00321 libmesh_parallel_only(mesh.comm()); 00322 00323 START_LOG("gather_neighboring_elements()","MeshCommunication"); 00324 00325 //------------------------------------------------------------------ 00326 // The purpose of this function is to provide neighbor data structure 00327 // consistency for a parallel, distributed mesh. In libMesh we require 00328 // that each local element have access to a full set of valid face 00329 // neighbors. In some cases this requires us to store "ghost elements" - 00330 // elements that belong to other processors but we store to provide 00331 // data structure consistency. Also, it is assumed that any element 00332 // with a NULL neighbor resides on a physical domain boundary. So, 00333 // even our "ghost elements" must have non-NULL neighbors. To handle 00334 // this the concept of "RemoteElem" is used - a special construct which 00335 // is used to denote that an element has a face neighbor, but we do 00336 // not actually store detailed information about that neighbor. This 00337 // is required to prevent data structure explosion. 00338 // 00339 // So when this method is called we should have only local elements. 00340 // These local elements will then find neighbors among the local 00341 // element set. After this is completed, any element with a NULL 00342 // neighbor has either (i) a face on the physical boundary of the mesh, 00343 // or (ii) a neighboring element which lives on a remote processor. 00344 // To handle case (ii), we communicate the global node indices connected 00345 // to all such faces to our neighboring processors. They then send us 00346 // all their elements with a NULL neighbor that are connected to any 00347 // of the nodes in our list. 00348 //------------------------------------------------------------------ 00349 00350 // Let's begin with finding consistent neighbor data information 00351 // for all the elements we currently have. We'll use a clean 00352 // slate here - clear any existing information, including RemoteElem's. 00353 // mesh.find_neighbors (/* reset_remote_elements = */ true, 00354 // /* reset_current_list = */ true); 00355 00356 // Get a unique message tag to use in communications; we'll default 00357 // to some numbers around pi*10000 00358 Parallel::MessageTag 00359 element_neighbors_tag = mesh.comm().get_unique_tag(31416); 00360 00361 // Now any element with a NULL neighbor either 00362 // (i) lives on the physical domain boundary, or 00363 // (ii) lives on an inter-processor boundary. 00364 // We will now gather all the elements from adjacent processors 00365 // which are of the same state, which should address all the type (ii) 00366 // elements. 00367 00368 // A list of all the processors which *may* contain neighboring elements. 00369 // (for development simplicity, just make this the identity map) 00370 std::vector<processor_id_type> adjacent_processors; 00371 for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) 00372 if (pid != mesh.processor_id()) 00373 adjacent_processors.push_back (pid); 00374 00375 00376 const processor_id_type n_adjacent_processors = 00377 cast_int<processor_id_type>(adjacent_processors.size()); 00378 00379 //------------------------------------------------------------------------- 00380 // Let's build a list of all nodes which live on NULL-neighbor sides. 00381 // For simplicity, we will use a set to build the list, then transfer 00382 // it to a vector for communication. 00383 std::vector<dof_id_type> my_interface_node_list; 00384 std::vector<const Elem*> my_interface_elements; 00385 { 00386 std::set<dof_id_type> my_interface_node_set; 00387 00388 // since parent nodes are a subset of children nodes, this should be sufficient 00389 MeshBase::const_element_iterator it = mesh.active_local_elements_begin(); 00390 const MeshBase::const_element_iterator it_end = mesh.active_local_elements_end(); 00391 00392 for (; it != it_end; ++it) 00393 { 00394 const Elem * const elem = *it; 00395 libmesh_assert(elem); 00396 00397 if (elem->on_boundary()) // denotes *any* side has a NULL neighbor 00398 { 00399 my_interface_elements.push_back(elem); // add the element, but only once, even 00400 // if there are multiple NULL neighbors 00401 for (unsigned int s=0; s<elem->n_sides(); s++) 00402 if (elem->neighbor(s) == NULL) 00403 { 00404 UniquePtr<Elem> side(elem->build_side(s)); 00405 00406 for (unsigned int n=0; n<side->n_vertices(); n++) 00407 my_interface_node_set.insert (side->node(n)); 00408 } 00409 } 00410 } 00411 00412 my_interface_node_list.reserve (my_interface_node_set.size()); 00413 my_interface_node_list.insert (my_interface_node_list.end(), 00414 my_interface_node_set.begin(), 00415 my_interface_node_set.end()); 00416 } 00417 00418 // we will now send my_interface_node_list to all of the adjacent processors. 00419 // note that for the time being we will copy the list to a unique buffer for 00420 // each processor so that we can use a nonblocking send and not access the 00421 // buffer again until the send completes. it is my understanding that the 00422 // MPI 2.1 standard seeks to remove this restriction as unnecessary, so in 00423 // the future we should change this to send the same buffer to each of the 00424 // adjacent processors. - BSK 11/17/2008 00425 std::vector<std::vector<dof_id_type> > 00426 my_interface_node_xfer_buffers (n_adjacent_processors, my_interface_node_list); 00427 std::map<processor_id_type, unsigned char> n_comm_steps; 00428 00429 std::vector<Parallel::Request> send_requests (3*n_adjacent_processors); 00430 unsigned int current_request = 0; 00431 00432 for (unsigned int comm_step=0; comm_step<n_adjacent_processors; comm_step++) 00433 { 00434 n_comm_steps[adjacent_processors[comm_step]]=1; 00435 mesh.comm().send (adjacent_processors[comm_step], 00436 my_interface_node_xfer_buffers[comm_step], 00437 send_requests[current_request++], 00438 element_neighbors_tag); 00439 } 00440 00441 //------------------------------------------------------------------------- 00442 // processor pairings are symmetric - I expect to receive an interface node 00443 // list from each processor in adjacent_processors as well! 00444 // now we will catch an incoming node list for each of our adjacent processors. 00445 // 00446 // we are done with the adjacent_processors list - note that it is in general 00447 // a superset of the processors we truly share elements with. so let's 00448 // clear the superset list, and we will fill it with the true list. 00449 adjacent_processors.clear(); 00450 00451 std::vector<dof_id_type> common_interface_node_list; 00452 00453 // we expect two classess of messages - 00454 // (1) incoming interface node lists, to which we will reply with our elements 00455 // touching nodes in the list, and 00456 // (2) replies from the requests we sent off previously. 00457 // (2.a) - nodes 00458 // (2.b) - elements 00459 // so we expect 3 communications from each adjacent processor. 00460 // by structuring the communication in this way we hopefully impose no 00461 // order on the handling of the arriving messages. in particular, we 00462 // should be able to handle the case where we receive a request and 00463 // all replies from processor A before even receiving a request from 00464 // processor B. 00465 00466 for (unsigned int comm_step=0; comm_step<3*n_adjacent_processors; comm_step++) 00467 { 00468 //------------------------------------------------------------------ 00469 // catch incoming node list 00470 Parallel::Status 00471 status(mesh.comm().probe (Parallel::any_source, 00472 element_neighbors_tag)); 00473 const processor_id_type 00474 source_pid_idx = cast_int<processor_id_type>(status.source()), 00475 dest_pid_idx = source_pid_idx; 00476 00477 //------------------------------------------------------------------ 00478 // first time - incoming request 00479 if (n_comm_steps[source_pid_idx] == 1) 00480 { 00481 n_comm_steps[source_pid_idx]++; 00482 00483 mesh.comm().receive (source_pid_idx, 00484 common_interface_node_list, 00485 element_neighbors_tag); 00486 const std::size_t 00487 their_interface_node_list_size = common_interface_node_list.size(); 00488 00489 // we now have the interface node list from processor source_pid_idx. 00490 // now we can find all of our elements which touch any of these nodes 00491 // and send copies back to this processor. however, we can make our 00492 // search more efficient by first excluding all the nodes in 00493 // their list which are not also contained in 00494 // my_interface_node_list. we can do this in place as a set 00495 // intersection. 00496 common_interface_node_list.erase 00497 (std::set_intersection (my_interface_node_list.begin(), 00498 my_interface_node_list.end(), 00499 common_interface_node_list.begin(), 00500 common_interface_node_list.end(), 00501 common_interface_node_list.begin()), 00502 common_interface_node_list.end()); 00503 00504 if (false) 00505 libMesh::out << "[" << mesh.processor_id() << "] " 00506 << "my_interface_node_list.size()=" << my_interface_node_list.size() 00507 << ", [" << source_pid_idx << "] " 00508 << "their_interface_node_list.size()=" << their_interface_node_list_size 00509 << ", common_interface_node_list.size()=" << common_interface_node_list.size() 00510 << std::endl; 00511 00512 // Now we need to see which of our elements touch the nodes in the list. 00513 // We will certainly send all the active elements which intersect source_pid_idx, 00514 // but we will also ship off the other elements in the same family tree 00515 // as the active ones for data structure consistency. 00516 // 00517 // FIXME - shipping full family trees is unnecessary and inefficient. 00518 // 00519 // We also ship any nodes connected to these elements. Note 00520 // some of these nodes and elements may be replicated from 00521 // other processors, but that is OK. 00522 std::set<const Elem*, CompareElemIdsByLevel> elements_to_send; 00523 std::set<const Node*> connected_nodes; 00524 00525 // Check for quick return? 00526 if (common_interface_node_list.empty()) 00527 { 00528 // let's try to be smart here - if we have no nodes in common, 00529 // we cannot share elements. so post the messages expected 00530 // from us here and go on about our business. 00531 // note that even though these are nonblocking sends 00532 // they should complete essentially instantly, because 00533 // in all cases the send buffers are empty 00534 mesh.comm().send_packed_range (dest_pid_idx, 00535 &mesh, 00536 connected_nodes.begin(), 00537 connected_nodes.end(), 00538 send_requests[current_request++], 00539 element_neighbors_tag); 00540 00541 mesh.comm().send_packed_range (dest_pid_idx, 00542 &mesh, 00543 elements_to_send.begin(), 00544 elements_to_send.end(), 00545 send_requests[current_request++], 00546 element_neighbors_tag); 00547 00548 continue; 00549 } 00550 // otherwise, this really *is* an adjacent processor. 00551 adjacent_processors.push_back(source_pid_idx); 00552 00553 std::vector<const Elem*> family_tree; 00554 00555 for (dof_id_type e=0, n_shared_nodes=0; e<my_interface_elements.size(); e++, n_shared_nodes=0) 00556 { 00557 const Elem * elem = my_interface_elements[e]; 00558 00559 for (unsigned int n=0; n<elem->n_vertices(); n++) 00560 if (std::binary_search (common_interface_node_list.begin(), 00561 common_interface_node_list.end(), 00562 elem->node(n))) 00563 { 00564 n_shared_nodes++; 00565 00566 // TBD - how many nodes do we need to share 00567 // before we care? certainly 2, but 1? not 00568 // sure, so let's play it safe... 00569 if (n_shared_nodes > 0) break; 00570 } 00571 00572 if (n_shared_nodes) // share at least one node? 00573 { 00574 elem = elem->top_parent(); 00575 00576 // avoid a lot of duplicated effort -- if we already have elem 00577 // in the set its entire family tree is already in the set. 00578 if (!elements_to_send.count(elem)) 00579 { 00580 #ifdef LIBMESH_ENABLE_AMR 00581 elem->family_tree(family_tree); 00582 #else 00583 family_tree.clear(); 00584 family_tree.push_back(elem); 00585 #endif 00586 for (unsigned int leaf=0; leaf<family_tree.size(); leaf++) 00587 { 00588 elem = family_tree[leaf]; 00589 elements_to_send.insert (elem); 00590 00591 for (unsigned int n=0; n<elem->n_nodes(); n++) 00592 connected_nodes.insert (elem->get_node(n)); 00593 } 00594 } 00595 } 00596 } 00597 00598 // The elements_to_send and connected_nodes sets now contain all 00599 // the elements and nodes we need to send to this processor. 00600 // All that remains is to pack up the objects (along with 00601 // any boundary conditions) and send the messages off. 00602 { 00603 libmesh_assert (connected_nodes.empty() || !elements_to_send.empty()); 00604 libmesh_assert (!connected_nodes.empty() || elements_to_send.empty()); 00605 00606 // send the nodes off to the destination processor 00607 mesh.comm().send_packed_range (dest_pid_idx, 00608 &mesh, 00609 connected_nodes.begin(), 00610 connected_nodes.end(), 00611 send_requests[current_request++], 00612 element_neighbors_tag); 00613 00614 // send the elements off to the destination processor 00615 mesh.comm().send_packed_range (dest_pid_idx, 00616 &mesh, 00617 elements_to_send.begin(), 00618 elements_to_send.end(), 00619 send_requests[current_request++], 00620 element_neighbors_tag); 00621 } 00622 } 00623 //------------------------------------------------------------------ 00624 // second time - reply of nodes 00625 else if (n_comm_steps[source_pid_idx] == 2) 00626 { 00627 n_comm_steps[source_pid_idx]++; 00628 00629 mesh.comm().receive_packed_range (source_pid_idx, 00630 &mesh, 00631 mesh_inserter_iterator<Node>(mesh), 00632 element_neighbors_tag); 00633 } 00634 //------------------------------------------------------------------ 00635 // third time - reply of elements 00636 else if (n_comm_steps[source_pid_idx] == 3) 00637 { 00638 n_comm_steps[source_pid_idx]++; 00639 00640 mesh.comm().receive_packed_range (source_pid_idx, 00641 &mesh, 00642 mesh_inserter_iterator<Elem>(mesh), 00643 element_neighbors_tag); 00644 } 00645 //------------------------------------------------------------------ 00646 // fourth time - shouldn't happen 00647 else 00648 { 00649 libMesh::err << "ERROR: unexpected number of replies: " 00650 << n_comm_steps[source_pid_idx] 00651 << std::endl; 00652 } 00653 } // done catching & processing replies associated with tag ~ 100,000pi 00654 00655 // allow any pending requests to complete 00656 Parallel::wait (send_requests); 00657 00658 STOP_LOG("gather_neighboring_elements()","MeshCommunication"); 00659 } 00660 #endif // LIBMESH_HAVE_MPI 00661 00662 00663 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings 00664 // ------------------------------------------------------------ 00665 void MeshCommunication::broadcast (MeshBase&) const 00666 { 00667 // no MPI == one processor, no need for this method... 00668 return; 00669 } 00670 #else 00671 // ------------------------------------------------------------ 00672 void MeshCommunication::broadcast (MeshBase& mesh) const 00673 { 00674 // Don't need to do anything if there is 00675 // only one processor. 00676 if (mesh.n_processors() == 1) 00677 return; 00678 00679 // This function must be run on all processors at once 00680 libmesh_parallel_only(mesh.comm()); 00681 00682 START_LOG("broadcast()","MeshCommunication"); 00683 00684 // Explicitly clear the mesh on all but processor 0. 00685 if (mesh.processor_id() != 0) 00686 mesh.clear(); 00687 00688 // Broadcast nodes 00689 mesh.comm().broadcast_packed_range(&mesh, 00690 mesh.nodes_begin(), 00691 mesh.nodes_end(), 00692 &mesh, 00693 mesh_inserter_iterator<Node>(mesh)); 00694 00695 // Broadcast elements from coarsest to finest, so that child 00696 // elements will see their parents already in place. 00697 unsigned int n_levels = MeshTools::n_levels(mesh); 00698 mesh.comm().broadcast(n_levels); 00699 00700 for (unsigned int l=0; l != n_levels; ++l) 00701 mesh.comm().broadcast_packed_range(&mesh, 00702 mesh.level_elements_begin(l), 00703 mesh.level_elements_end(l), 00704 &mesh, 00705 mesh_inserter_iterator<Elem>(mesh)); 00706 00707 // Make sure mesh_dimension and elem_dimensions are consistent. 00708 mesh.cache_elem_dims(); 00709 00710 // Broadcast all of the named entity information 00711 mesh.comm().broadcast(mesh.set_subdomain_name_map()); 00712 mesh.comm().broadcast(mesh.get_boundary_info().set_sideset_name_map()); 00713 mesh.comm().broadcast(mesh.get_boundary_info().set_nodeset_name_map()); 00714 00715 libmesh_assert (mesh.comm().verify(mesh.n_elem())); 00716 libmesh_assert (mesh.comm().verify(mesh.n_nodes())); 00717 00718 #ifdef DEBUG 00719 MeshTools::libmesh_assert_valid_procids<Elem>(mesh); 00720 MeshTools::libmesh_assert_valid_procids<Node>(mesh); 00721 #endif 00722 00723 STOP_LOG("broadcast()","MeshCommunication"); 00724 } 00725 #endif // LIBMESH_HAVE_MPI 00726 00727 00728 00729 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings 00730 // ------------------------------------------------------------ 00731 void MeshCommunication::gather (const processor_id_type, ParallelMesh&) const 00732 { 00733 // no MPI == one processor, no need for this method... 00734 return; 00735 } 00736 #else 00737 // ------------------------------------------------------------ 00738 void MeshCommunication::gather (const processor_id_type root_id, ParallelMesh& mesh) const 00739 { 00740 // The mesh should know it's about to be serialized 00741 libmesh_assert (mesh.is_serial()); 00742 00743 // Check for quick return 00744 if (mesh.n_processors() == 1) 00745 return; 00746 00747 // This function must be run on all processors at once 00748 libmesh_parallel_only(mesh.comm()); 00749 00750 START_LOG("(all)gather()","MeshCommunication"); 00751 00752 (root_id == DofObject::invalid_processor_id) ? 00753 00754 mesh.comm().allgather_packed_range (&mesh, 00755 mesh.nodes_begin(), 00756 mesh.nodes_end(), 00757 mesh_inserter_iterator<Node>(mesh)) : 00758 00759 mesh.comm().gather_packed_range (root_id, 00760 &mesh, 00761 mesh.nodes_begin(), 00762 mesh.nodes_end(), 00763 mesh_inserter_iterator<Node>(mesh)); 00764 00765 // Gather elements from coarsest to finest, so that child 00766 // elements will see their parents already in place. 00767 // rank 0 should know n_levels regardless, so this is 00768 // safe independent of root_id 00769 unsigned int n_levels = MeshTools::n_levels(mesh); 00770 mesh.comm().broadcast(n_levels); 00771 00772 for (unsigned int l=0; l != n_levels; ++l) 00773 (root_id == DofObject::invalid_processor_id) ? 00774 00775 mesh.comm().allgather_packed_range (&mesh, 00776 mesh.level_elements_begin(l), 00777 mesh.level_elements_end(l), 00778 mesh_inserter_iterator<Elem>(mesh)) : 00779 00780 mesh.comm().gather_packed_range (root_id, 00781 &mesh, 00782 mesh.level_elements_begin(l), 00783 mesh.level_elements_end(l), 00784 mesh_inserter_iterator<Elem>(mesh)); 00785 00786 00787 // If we are doing an allgather(), perform sanity check on the result. 00788 if (root_id == DofObject::invalid_processor_id) 00789 { 00790 libmesh_assert (mesh.comm().verify(mesh.n_elem())); 00791 libmesh_assert (mesh.comm().verify(mesh.n_nodes())); 00792 } 00793 00794 // Inform new elements of their neighbors, 00795 // while resetting all remote_elem links on 00796 // the appropriate ranks. 00797 if ((root_id == DofObject::invalid_processor_id) || 00798 (mesh.comm().rank() == root_id)) 00799 mesh.find_neighbors(true); 00800 00801 // All done! 00802 STOP_LOG("(all)gather()","MeshCommunication"); 00803 } 00804 #endif // LIBMESH_HAVE_MPI 00805 00806 00807 00808 // Functor for make_elems_parallel_consistent and 00809 // make_node_ids_parallel_consistent 00810 namespace { 00811 00812 struct SyncIds 00813 { 00814 typedef dof_id_type datum; 00815 typedef void (MeshBase::*renumber_obj)(dof_id_type, dof_id_type); 00816 00817 SyncIds(MeshBase &_mesh, renumber_obj _renumberer) : 00818 mesh(_mesh), 00819 renumber(_renumberer) {} 00820 00821 MeshBase &mesh; 00822 renumber_obj renumber; 00823 // renumber_obj &renumber; 00824 00825 // Find the id of each requested DofObject - 00826 // Parallel::sync_* already did the work for us 00827 void gather_data (const std::vector<dof_id_type>& ids, 00828 std::vector<datum>& ids_out) 00829 { 00830 ids_out = ids; 00831 } 00832 00833 void act_on_data (const std::vector<dof_id_type>& old_ids, 00834 std::vector<datum>& new_ids) 00835 { 00836 for (unsigned int i=0; i != old_ids.size(); ++i) 00837 if (old_ids[i] != new_ids[i]) 00838 (mesh.*renumber)(old_ids[i], new_ids[i]); 00839 } 00840 }; 00841 } 00842 00843 00844 00845 // ------------------------------------------------------------ 00846 void MeshCommunication::make_node_ids_parallel_consistent 00847 (MeshBase &mesh) 00848 { 00849 // This function must be run on all processors at once 00850 libmesh_parallel_only(mesh.comm()); 00851 00852 START_LOG ("make_node_ids_parallel_consistent()", "MeshCommunication"); 00853 00854 SyncIds syncids(mesh, &MeshBase::renumber_node); 00855 Parallel::sync_node_data_by_element_id 00856 (mesh, mesh.elements_begin(), mesh.elements_end(), syncids); 00857 00858 STOP_LOG ("make_node_ids_parallel_consistent()", "MeshCommunication"); 00859 } 00860 00861 00862 00863 // ------------------------------------------------------------ 00864 void MeshCommunication::make_elems_parallel_consistent(MeshBase &mesh) 00865 { 00866 // This function must be run on all processors at once 00867 libmesh_parallel_only(mesh.comm()); 00868 00869 START_LOG ("make_elems_parallel_consistent()", "MeshCommunication"); 00870 00871 SyncIds syncids(mesh, &MeshBase::renumber_elem); 00872 Parallel::sync_element_data_by_parent_id 00873 (mesh, mesh.active_elements_begin(), 00874 mesh.active_elements_end(), syncids); 00875 00876 STOP_LOG ("make_elems_parallel_consistent()", "MeshCommunication"); 00877 } 00878 00879 00880 00881 // Functors for make_node_proc_ids_parallel_consistent 00882 namespace { 00883 00884 struct SyncProcIds 00885 { 00886 typedef processor_id_type datum; 00887 00888 SyncProcIds(MeshBase &_mesh) : mesh(_mesh) {} 00889 00890 MeshBase &mesh; 00891 00892 // ------------------------------------------------------------ 00893 void gather_data (const std::vector<dof_id_type>& ids, 00894 std::vector<datum>& data) 00895 { 00896 // Find the processor id of each requested node 00897 data.resize(ids.size()); 00898 00899 for (std::size_t i=0; i != ids.size(); ++i) 00900 { 00901 // Look for this point in the mesh 00902 // We'd better find every node we're asked for 00903 Node *node = mesh.node_ptr(ids[i]); 00904 00905 // Return the node's correct processor id, 00906 data[i] = node->processor_id(); 00907 } 00908 } 00909 00910 // ------------------------------------------------------------ 00911 void act_on_data (const std::vector<dof_id_type>& ids, 00912 std::vector<datum> proc_ids) 00913 { 00914 // Set the ghost node processor ids we've now been informed of 00915 for (std::size_t i=0; i != ids.size(); ++i) 00916 { 00917 Node *node = mesh.node_ptr(ids[i]); 00918 node->processor_id() = proc_ids[i]; 00919 } 00920 } 00921 }; 00922 } 00923 00924 00925 00926 // ------------------------------------------------------------ 00927 void MeshCommunication::make_node_proc_ids_parallel_consistent 00928 (MeshBase& mesh) 00929 { 00930 START_LOG ("make_node_proc_ids_parallel_consistent()", "MeshCommunication"); 00931 00932 // This function must be run on all processors at once 00933 libmesh_parallel_only(mesh.comm()); 00934 00935 // When this function is called, each section of a parallelized mesh 00936 // should be in the following state: 00937 // 00938 // All nodes should have the exact same physical location on every 00939 // processor where they exist. 00940 // 00941 // Local nodes should have unique authoritative ids, 00942 // and processor ids consistent with all processors which own 00943 // an element touching them. 00944 // 00945 // Ghost nodes touching local elements should have processor ids 00946 // consistent with all processors which own an element touching 00947 // them. 00948 00949 SyncProcIds sync(mesh); 00950 Parallel::sync_node_data_by_element_id 00951 (mesh, mesh.elements_begin(), mesh.elements_end(), sync); 00952 00953 STOP_LOG ("make_node_proc_ids_parallel_consistent()", "MeshCommunication"); 00954 } 00955 00956 00957 00958 // ------------------------------------------------------------ 00959 void MeshCommunication::make_nodes_parallel_consistent 00960 (MeshBase &mesh) 00961 { 00962 // This function must be run on all processors at once 00963 libmesh_parallel_only(mesh.comm()); 00964 00965 // When this function is called, each section of a parallelized mesh 00966 // should be in the following state: 00967 // 00968 // All nodes should have the exact same physical location on every 00969 // processor where they exist. 00970 // 00971 // Local nodes should have unique authoritative ids, 00972 // and processor ids consistent with all processors which own 00973 // an element touching them. 00974 // 00975 // Ghost nodes touching local elements should have processor ids 00976 // consistent with all processors which own an element touching 00977 // them. 00978 // 00979 // Ghost nodes should have ids which are either already correct 00980 // or which are in the "unpartitioned" id space. 00981 00982 // First, let's sync up processor ids. Some of these processor ids 00983 // may be "wrong" from coarsening, but they're right in the sense 00984 // that they'll tell us who has the authoritative dofobject ids for 00985 // each node. 00986 this->make_node_proc_ids_parallel_consistent(mesh); 00987 00988 // Second, sync up dofobject ids. 00989 this->make_node_ids_parallel_consistent(mesh); 00990 00991 // Finally, correct the processor ids to make DofMap happy 00992 MeshTools::correct_node_proc_ids(mesh); 00993 } 00994 00995 00996 00997 // ------------------------------------------------------------ 00998 void MeshCommunication::delete_remote_elements(ParallelMesh& mesh, const std::set<Elem *> & extra_ghost_elem_ids) const 00999 { 01000 // The mesh should know it's about to be parallelized 01001 libmesh_assert (!mesh.is_serial()); 01002 01003 START_LOG("delete_remote_elements()", "MeshCommunication"); 01004 01005 #ifdef DEBUG 01006 // We expect maximum ids to be in sync so we can use them to size 01007 // vectors 01008 mesh.comm().verify(mesh.max_node_id()); 01009 mesh.comm().verify(mesh.max_elem_id()); 01010 const dof_id_type par_max_node_id = mesh.parallel_max_node_id(); 01011 const dof_id_type par_max_elem_id = mesh.parallel_max_elem_id(); 01012 libmesh_assert_equal_to (par_max_node_id, mesh.max_node_id()); 01013 libmesh_assert_equal_to (par_max_elem_id, mesh.max_elem_id()); 01014 #endif 01015 01016 // FIXME - should these be "unsorted_set"s? O(N) is O(N)... 01017 std::vector<bool> local_nodes(mesh.max_node_id(), false); 01018 std::vector<bool> semilocal_nodes(mesh.max_node_id(), false); 01019 std::vector<bool> semilocal_elems(mesh.max_elem_id(), false); 01020 01021 // We don't want to delete any element that shares a node 01022 // with or is an ancestor of a local element. 01023 MeshBase::const_element_iterator l_elem_it = mesh.local_elements_begin(), 01024 l_end = mesh.local_elements_end(); 01025 for (; l_elem_it != l_end; ++l_elem_it) 01026 { 01027 const Elem *elem = *l_elem_it; 01028 for (unsigned int n=0; n != elem->n_nodes(); ++n) 01029 { 01030 dof_id_type nodeid = elem->node(n); 01031 libmesh_assert_less (nodeid, local_nodes.size()); 01032 local_nodes[nodeid] = true; 01033 } 01034 while (elem) 01035 { 01036 dof_id_type elemid = elem->id(); 01037 libmesh_assert_less (elemid, semilocal_elems.size()); 01038 semilocal_elems[elemid] = true; 01039 01040 for (unsigned int n=0; n != elem->n_nodes(); ++n) 01041 semilocal_nodes[elem->node(n)] = true; 01042 01043 const Elem *parent = elem->parent(); 01044 // Don't proceed from a boundary mesh to an interior mesh 01045 if (parent && parent->dim() != elem->dim()) 01046 break; 01047 01048 elem = parent; 01049 } 01050 } 01051 01052 // We don't want to delete any element that shares a node 01053 // with or is an ancestor of an unpartitioned element either. 01054 MeshBase::const_element_iterator 01055 u_elem_it = mesh.unpartitioned_elements_begin(), 01056 u_end = mesh.unpartitioned_elements_end(); 01057 01058 for (; u_elem_it != u_end; ++u_elem_it) 01059 { 01060 const Elem *elem = *u_elem_it; 01061 for (unsigned int n=0; n != elem->n_nodes(); ++n) 01062 local_nodes[elem->node(n)] = true; 01063 while (elem) 01064 { 01065 semilocal_elems[elem->id()] = true; 01066 01067 for (unsigned int n=0; n != elem->n_nodes(); ++n) 01068 semilocal_nodes[elem->node(n)] = true; 01069 01070 const Elem *parent = elem->parent(); 01071 // Don't proceed from a boundary mesh to an interior mesh 01072 if (parent && parent->dim() != elem->dim()) 01073 break; 01074 01075 elem = parent; 01076 } 01077 } 01078 01079 // Flag all the elements that share nodes with 01080 // local and unpartitioned elements, along with their ancestors 01081 MeshBase::element_iterator nl_elem_it = mesh.not_local_elements_begin(), 01082 nl_end = mesh.not_local_elements_end(); 01083 for (; nl_elem_it != nl_end; ++nl_elem_it) 01084 { 01085 const Elem *elem = *nl_elem_it; 01086 for (unsigned int n=0; n != elem->n_nodes(); ++n) 01087 if (local_nodes[elem->node(n)]) 01088 { 01089 while (elem) 01090 { 01091 semilocal_elems[elem->id()] = true; 01092 01093 for (unsigned int nn=0; nn != elem->n_nodes(); ++nn) 01094 semilocal_nodes[elem->node(nn)] = true; 01095 01096 const Elem *parent = elem->parent(); 01097 // Don't proceed from a boundary mesh to an interior mesh 01098 if (parent && parent->dim() != elem->dim()) 01099 break; 01100 01101 elem = parent; 01102 } 01103 break; 01104 } 01105 } 01106 01107 // Don't delete elements that we were explicitly told not to 01108 for(std::set<Elem *>::iterator it = extra_ghost_elem_ids.begin(); 01109 it != extra_ghost_elem_ids.end(); 01110 ++it) 01111 { 01112 const Elem *elem = *it; 01113 semilocal_elems[elem->id()] = true; 01114 for (unsigned int n=0; n != elem->n_nodes(); ++n) 01115 semilocal_nodes[elem->node(n)] = true; 01116 } 01117 01118 // Delete all the elements we have no reason to save, 01119 // starting with the most refined so that the mesh 01120 // is valid at all intermediate steps 01121 unsigned int n_levels = MeshTools::n_levels(mesh); 01122 01123 for (int l = n_levels - 1; l >= 0; --l) 01124 { 01125 MeshBase::element_iterator lev_elem_it = mesh.level_elements_begin(l), 01126 lev_end = mesh.level_elements_end(l); 01127 for (; lev_elem_it != lev_end; ++lev_elem_it) 01128 { 01129 Elem *elem = *lev_elem_it; 01130 libmesh_assert (elem); 01131 // Make sure we don't leave any invalid pointers 01132 if (!semilocal_elems[elem->id()]) 01133 elem->make_links_to_me_remote(); 01134 01135 // Subactive neighbor pointers aren't preservable here 01136 if (elem->subactive()) 01137 for (unsigned int s=0; s != elem->n_sides(); ++s) 01138 elem->set_neighbor(s, NULL); 01139 01140 // delete_elem doesn't currently invalidate element 01141 // iterators... that had better not change 01142 if (!semilocal_elems[elem->id()]) 01143 mesh.delete_elem(elem); 01144 } 01145 } 01146 01147 // Delete all the nodes we have no reason to save 01148 MeshBase::node_iterator node_it = mesh.nodes_begin(), 01149 node_end = mesh.nodes_end(); 01150 for (node_it = mesh.nodes_begin(); node_it != node_end; ++node_it) 01151 { 01152 Node *node = *node_it; 01153 libmesh_assert(node); 01154 if (!semilocal_nodes[node->id()]) 01155 mesh.delete_node(node); 01156 } 01157 01158 #ifdef DEBUG 01159 MeshTools::libmesh_assert_valid_refinement_tree(mesh); 01160 #endif 01161 01162 STOP_LOG("delete_remote_elements()", "MeshCommunication"); 01163 } 01164 01165 } // namespace libMesh