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