$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 #ifndef LIBMESH_PARALLEL_GHOST_SYNC_H 00021 #define LIBMESH_PARALLEL_GHOST_SYNC_H 00022 00023 // Local Includes ----------------------------------- 00024 #include "libmesh/auto_ptr.h" 00025 #include "libmesh/elem.h" 00026 #include "libmesh/location_maps.h" 00027 #include "libmesh/mesh_base.h" 00028 #include "libmesh/parallel.h" 00029 00030 // C++ Includes ----------------------------------- 00031 #include LIBMESH_INCLUDE_UNORDERED_SET 00032 00033 00034 namespace libMesh 00035 { 00036 00037 00038 00039 //-------------------------------------------------------------------------- 00040 namespace Parallel { 00041 00042 //------------------------------------------------------------------------ 00059 template <typename Iterator, 00060 typename DofObjType, 00061 typename SyncFunctor> 00062 void sync_dofobject_data_by_xyz(const Communicator& comm, 00063 const Iterator& range_begin, 00064 const Iterator& range_end, 00065 LocationMap<DofObjType>* location_map, 00066 SyncFunctor& sync); 00067 00068 //------------------------------------------------------------------------ 00081 template <typename Iterator, 00082 typename SyncFunctor> 00083 void sync_dofobject_data_by_id(const Communicator& comm, 00084 const Iterator& range_begin, 00085 const Iterator& range_end, 00086 SyncFunctor& sync); 00087 00088 //------------------------------------------------------------------------ 00102 template <typename Iterator, 00103 typename SyncFunctor> 00104 void sync_element_data_by_parent_id(MeshBase& mesh, 00105 const Iterator& range_begin, 00106 const Iterator& range_end, 00107 SyncFunctor& sync); 00108 00109 //------------------------------------------------------------------------ 00125 template <typename SyncFunctor> 00126 void sync_node_data_by_element_id(MeshBase& mesh, 00127 const MeshBase::const_element_iterator& range_begin, 00128 const MeshBase::const_element_iterator& range_end, 00129 SyncFunctor& sync); 00130 00131 00132 //------------------------------------------------------------------------ 00133 // Parallel members 00134 00135 template <typename Iterator, 00136 typename DofObjType, 00137 typename SyncFunctor> 00138 void sync_dofobject_data_by_xyz(const Communicator& comm, 00139 const Iterator& range_begin, 00140 const Iterator& range_end, 00141 LocationMap<DofObjType>& location_map, 00142 SyncFunctor& sync) 00143 { 00144 // This function must be run on all processors at once 00145 libmesh_parallel_only(comm); 00146 00147 // We need a valid location_map 00148 #ifdef DEBUG 00149 bool need_map_update = (range_begin != range_end && location_map.empty()); 00150 comm.max(need_map_update); 00151 libmesh_assert(!need_map_update); 00152 #endif 00153 00154 // Count the objectss to ask each processor about 00155 std::vector<dof_id_type> 00156 ghost_objects_from_proc(comm.size(), 0); 00157 00158 for (Iterator it = range_begin; it != range_end; ++it) 00159 { 00160 DofObjType *obj = *it; 00161 libmesh_assert (obj); 00162 processor_id_type obj_procid = obj->processor_id(); 00163 if (obj_procid != DofObject::invalid_processor_id) 00164 ghost_objects_from_proc[obj_procid]++; 00165 } 00166 00167 // Request sets to send to each processor 00168 std::vector<std::vector<Real> > 00169 requested_objs_x(comm.size()), 00170 requested_objs_y(comm.size()), 00171 requested_objs_z(comm.size()); 00172 // Corresponding ids to keep track of 00173 std::vector<std::vector<dof_id_type> > 00174 requested_objs_id(comm.size()); 00175 00176 // We know how many objects live on each processor, so reserve() 00177 // space for each. 00178 for (processor_id_type p=0; p != comm.size(); ++p) 00179 if (p != comm.rank()) 00180 { 00181 requested_objs_x[p].reserve(ghost_objects_from_proc[p]); 00182 requested_objs_y[p].reserve(ghost_objects_from_proc[p]); 00183 requested_objs_z[p].reserve(ghost_objects_from_proc[p]); 00184 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00185 } 00186 for (Iterator it = range_begin; it != range_end; ++it) 00187 { 00188 DofObjType *obj = *it; 00189 processor_id_type obj_procid = obj->processor_id(); 00190 if (obj_procid == comm.rank() || 00191 obj_procid == DofObject::invalid_processor_id) 00192 continue; 00193 00194 Point p = location_map.point_of(*obj); 00195 requested_objs_x[obj_procid].push_back(p(0)); 00196 requested_objs_y[obj_procid].push_back(p(1)); 00197 requested_objs_z[obj_procid].push_back(p(2)); 00198 requested_objs_id[obj_procid].push_back(obj->id()); 00199 } 00200 00201 // Trade requests with other processors 00202 for (processor_id_type p=1; p != comm.size(); ++p) 00203 { 00204 // Trade my requests with processor procup and procdown 00205 const processor_id_type procup = 00206 cast_int<processor_id_type> 00207 ((comm.rank() + p) % comm.size()); 00208 const processor_id_type procdown = 00209 cast_int<processor_id_type> 00210 ((comm.size() + comm.rank() - p) % 00211 comm.size()); 00212 std::vector<Real> request_to_fill_x, 00213 request_to_fill_y, 00214 request_to_fill_z; 00215 comm.send_receive(procup, requested_objs_x[procup], 00216 procdown, request_to_fill_x); 00217 comm.send_receive(procup, requested_objs_y[procup], 00218 procdown, request_to_fill_y); 00219 comm.send_receive(procup, requested_objs_z[procup], 00220 procdown, request_to_fill_z); 00221 00222 // Find the local id of each requested object 00223 std::vector<dof_id_type> request_to_fill_id(request_to_fill_x.size()); 00224 for (std::size_t i=0; i != request_to_fill_x.size(); ++i) 00225 { 00226 Point pt(request_to_fill_x[i], 00227 request_to_fill_y[i], 00228 request_to_fill_z[i]); 00229 00230 // Look for this object in the multimap 00231 DofObjType *obj = location_map.find(pt); 00232 00233 // We'd better find every object we're asked for 00234 libmesh_assert (obj); 00235 00236 // Return the object's correct processor id, 00237 // and our (correct if it's local) id for it. 00238 request_to_fill_id[i] = obj->id(); 00239 } 00240 00241 // Gather whatever data the user wants 00242 std::vector<typename SyncFunctor::datum> data; 00243 sync.gather_data(request_to_fill_id, data); 00244 00245 // Trade back the results 00246 std::vector<typename SyncFunctor::datum> received_data; 00247 comm.send_receive(procdown, data, 00248 procup, received_data); 00249 libmesh_assert_equal_to (requested_objs_x[procup].size(), 00250 received_data.size()); 00251 00252 // Let the user process the results 00253 sync.act_on_data(requested_objs_id[procup], received_data); 00254 } 00255 } 00256 00257 00258 00259 template <typename Iterator, 00260 typename SyncFunctor> 00261 void sync_dofobject_data_by_id(const Communicator& comm, 00262 const Iterator& range_begin, 00263 const Iterator& range_end, 00264 SyncFunctor& sync) 00265 { 00266 // This function must be run on all processors at once 00267 libmesh_parallel_only(comm); 00268 00269 // Count the objects to ask each processor about 00270 std::vector<dof_id_type> 00271 ghost_objects_from_proc(comm.size(), 0); 00272 00273 for (Iterator it = range_begin; it != range_end; ++it) 00274 { 00275 DofObject *obj = *it; 00276 libmesh_assert (obj); 00277 processor_id_type obj_procid = obj->processor_id(); 00278 if (obj_procid != DofObject::invalid_processor_id) 00279 ghost_objects_from_proc[obj_procid]++; 00280 } 00281 00282 // Request sets to send to each processor 00283 std::vector<std::vector<dof_id_type> > 00284 requested_objs_id(comm.size()); 00285 00286 // We know how many objects live on each processor, so reserve() 00287 // space for each. 00288 for (processor_id_type p=0; p != comm.size(); ++p) 00289 if (p != comm.rank()) 00290 { 00291 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00292 } 00293 for (Iterator it = range_begin; it != range_end; ++it) 00294 { 00295 DofObject *obj = *it; 00296 processor_id_type obj_procid = obj->processor_id(); 00297 if (obj_procid == comm.rank() || 00298 obj_procid == DofObject::invalid_processor_id) 00299 continue; 00300 00301 requested_objs_id[obj_procid].push_back(obj->id()); 00302 } 00303 00304 // Trade requests with other processors 00305 for (processor_id_type p=1; p != comm.size(); ++p) 00306 { 00307 // Trade my requests with processor procup and procdown 00308 const processor_id_type procup = 00309 cast_int<processor_id_type> 00310 ((comm.rank() + p) % comm.size()); 00311 const processor_id_type procdown = 00312 cast_int<processor_id_type> 00313 ((comm.size() + comm.rank() - p) % 00314 comm.size()); 00315 std::vector<dof_id_type> request_to_fill_id; 00316 comm.send_receive(procup, requested_objs_id[procup], 00317 procdown, request_to_fill_id); 00318 00319 // Gather whatever data the user wants 00320 std::vector<typename SyncFunctor::datum> data; 00321 sync.gather_data(request_to_fill_id, data); 00322 00323 // Trade back the results 00324 std::vector<typename SyncFunctor::datum> received_data; 00325 comm.send_receive(procdown, data, 00326 procup, received_data); 00327 libmesh_assert_equal_to (requested_objs_id[procup].size(), 00328 received_data.size()); 00329 00330 // Let the user process the results 00331 sync.act_on_data(requested_objs_id[procup], received_data); 00332 } 00333 } 00334 00335 00336 00337 // If there's no refined elements, there's nothing to sync 00338 #ifdef LIBMESH_ENABLE_AMR 00339 template <typename Iterator, 00340 typename SyncFunctor> 00341 void sync_element_data_by_parent_id(MeshBase& mesh, 00342 const Iterator& range_begin, 00343 const Iterator& range_end, 00344 SyncFunctor& sync) 00345 { 00346 const Communicator &comm (mesh.comm()); 00347 00348 // This function must be run on all processors at once 00349 libmesh_parallel_only(comm); 00350 00351 // Count the objects to ask each processor about 00352 std::vector<dof_id_type> 00353 ghost_objects_from_proc(comm.size(), 0); 00354 00355 for (Iterator it = range_begin; it != range_end; ++it) 00356 { 00357 DofObject *obj = *it; 00358 libmesh_assert (obj); 00359 processor_id_type obj_procid = obj->processor_id(); 00360 if (obj_procid != DofObject::invalid_processor_id) 00361 ghost_objects_from_proc[obj_procid]++; 00362 } 00363 00364 // Request sets to send to each processor 00365 std::vector<std::vector<dof_id_type> > 00366 requested_objs_id(comm.size()), 00367 requested_objs_parent_id(comm.size()); 00368 std::vector<std::vector<unsigned char> > 00369 requested_objs_child_num(comm.size()); 00370 00371 // We know how many objects live on each processor, so reserve() 00372 // space for each. 00373 for (processor_id_type p=0; p != comm.size(); ++p) 00374 if (p != comm.rank()) 00375 { 00376 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00377 requested_objs_parent_id[p].reserve(ghost_objects_from_proc[p]); 00378 requested_objs_child_num[p].reserve(ghost_objects_from_proc[p]); 00379 } 00380 00381 for (Iterator it = range_begin; it != range_end; ++it) 00382 { 00383 Elem *elem = *it; 00384 processor_id_type obj_procid = elem->processor_id(); 00385 if (obj_procid == comm.rank() || 00386 obj_procid == DofObject::invalid_processor_id) 00387 continue; 00388 const Elem *parent = elem->parent(); 00389 if (!parent || !elem->active()) 00390 continue; 00391 00392 requested_objs_id[obj_procid].push_back(elem->id()); 00393 requested_objs_parent_id[obj_procid].push_back(parent->id()); 00394 requested_objs_child_num[obj_procid].push_back 00395 (cast_int<unsigned char> 00396 (parent->which_child_am_i(elem))); 00397 } 00398 00399 // Trade requests with other processors 00400 for (processor_id_type p=1; p != comm.size(); ++p) 00401 { 00402 // Trade my requests with processor procup and procdown 00403 const processor_id_type procup = 00404 cast_int<processor_id_type> 00405 ((comm.rank() + p) % comm.size()); 00406 const processor_id_type procdown = 00407 cast_int<processor_id_type> 00408 ((comm.size() + comm.rank() - p) % 00409 comm.size()); 00410 std::vector<dof_id_type> request_to_fill_parent_id; 00411 std::vector<unsigned char> request_to_fill_child_num; 00412 comm.send_receive(procup, requested_objs_parent_id[procup], 00413 procdown, request_to_fill_parent_id); 00414 comm.send_receive(procup, requested_objs_child_num[procup], 00415 procdown, request_to_fill_child_num); 00416 00417 // Find the id of each requested element 00418 std::size_t request_size = request_to_fill_parent_id.size(); 00419 std::vector<dof_id_type> request_to_fill_id(request_size); 00420 for (std::size_t i=0; i != request_size; ++i) 00421 { 00422 Elem *parent = mesh.elem(request_to_fill_parent_id[i]); 00423 libmesh_assert(parent); 00424 libmesh_assert(parent->has_children()); 00425 Elem *child = parent->child(request_to_fill_child_num[i]); 00426 libmesh_assert(child); 00427 libmesh_assert(child->active()); 00428 request_to_fill_id[i] = child->id(); 00429 } 00430 00431 // Gather whatever data the user wants 00432 std::vector<typename SyncFunctor::datum> data; 00433 sync.gather_data(request_to_fill_id, data); 00434 00435 // Trade back the results 00436 std::vector<typename SyncFunctor::datum> received_data; 00437 comm.send_receive(procdown, data, 00438 procup, received_data); 00439 libmesh_assert_equal_to (requested_objs_id[procup].size(), 00440 received_data.size()); 00441 00442 // Let the user process the results 00443 sync.act_on_data(requested_objs_id[procup], received_data); 00444 } 00445 } 00446 #else 00447 template <typename Iterator, 00448 typename SyncFunctor> 00449 void sync_element_data_by_parent_id(MeshBase&, 00450 const Iterator&, 00451 const Iterator&, 00452 SyncFunctor&) 00453 { 00454 } 00455 #endif // LIBMESH_ENABLE_AMR 00456 00457 00458 template <typename SyncFunctor> 00459 void sync_node_data_by_element_id(MeshBase& mesh, 00460 const MeshBase::const_element_iterator& range_begin, 00461 const MeshBase::const_element_iterator& range_end, 00462 SyncFunctor& sync) 00463 { 00464 const Communicator &comm (mesh.comm()); 00465 00466 // This function must be run on all processors at once 00467 libmesh_parallel_only(comm); 00468 00469 // Keep track of which nodes we've asked about, so we only hit each 00470 // once. 00471 LIBMESH_BEST_UNORDERED_SET<dof_id_type> queried_nodes; 00472 00473 // Count the objects to ask each processor about 00474 std::vector<dof_id_type> 00475 ghost_objects_from_proc(comm.size(), 0); 00476 00477 for (MeshBase::const_element_iterator it = range_begin; 00478 it != range_end; ++it) 00479 { 00480 const Elem *elem = *it; 00481 libmesh_assert (elem); 00482 00483 for (unsigned int n=0; n != elem->n_nodes(); ++n) 00484 { 00485 const Node *node = elem->get_node(n); 00486 00487 const processor_id_type proc_id = node->processor_id(); 00488 if (proc_id == comm.rank() || 00489 proc_id == DofObject::invalid_processor_id) 00490 continue; 00491 00492 dof_id_type node_id = node->id(); 00493 if (!queried_nodes.count(node_id)) 00494 { 00495 ghost_objects_from_proc[proc_id]++; 00496 queried_nodes.insert(node_id); 00497 } 00498 } 00499 } 00500 00501 // Now repeat that iteration, filling request sets this time. 00502 queried_nodes.clear(); 00503 00504 // Request sets to send to each processor 00505 std::vector<std::vector<dof_id_type> > 00506 requested_objs_elem_id(comm.size()); 00507 std::vector<std::vector<unsigned char> > 00508 requested_objs_node_num(comm.size()); 00509 00510 // Keep track of current local ids for each too 00511 std::vector<std::vector<dof_id_type> > 00512 requested_objs_id(comm.size()); 00513 00514 // We know how many objects live on each processor, so reserve() 00515 // space for each. 00516 for (processor_id_type p=0; p != comm.size(); ++p) 00517 if (p != comm.rank()) 00518 { 00519 requested_objs_elem_id[p].reserve(ghost_objects_from_proc[p]); 00520 requested_objs_node_num[p].reserve(ghost_objects_from_proc[p]); 00521 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00522 } 00523 00524 for (MeshBase::const_element_iterator it = range_begin; 00525 it != range_end; ++it) 00526 { 00527 const Elem *elem = *it; 00528 libmesh_assert (elem); 00529 00530 const dof_id_type elem_id = elem->id(); 00531 00532 for (unsigned int n=0; n != elem->n_nodes(); ++n) 00533 { 00534 const Node *node = elem->get_node(n); 00535 const dof_id_type node_id = node->id(); 00536 00537 const processor_id_type proc_id = node->processor_id(); 00538 if (proc_id == comm.rank() || 00539 proc_id == DofObject::invalid_processor_id) 00540 continue; 00541 00542 if (!queried_nodes.count(node_id)) 00543 { 00544 requested_objs_elem_id[proc_id].push_back(elem_id); 00545 requested_objs_node_num[proc_id].push_back 00546 (cast_int<unsigned char>(n)); 00547 requested_objs_id[proc_id].push_back(node_id); 00548 queried_nodes.insert(node_id); 00549 } 00550 } 00551 } 00552 00553 // Trade requests with other processors 00554 for (processor_id_type p=1; p != comm.size(); ++p) 00555 { 00556 // Trade my requests with processor procup and procdown 00557 const processor_id_type procup = 00558 cast_int<processor_id_type> 00559 ((comm.rank() + p) % comm.size()); 00560 const processor_id_type procdown = 00561 cast_int<processor_id_type> 00562 ((comm.size() + comm.rank() - p) % 00563 comm.size()); 00564 00565 libmesh_assert_equal_to (requested_objs_id[procup].size(), 00566 ghost_objects_from_proc[procup]); 00567 libmesh_assert_equal_to (requested_objs_elem_id[procup].size(), 00568 ghost_objects_from_proc[procup]); 00569 libmesh_assert_equal_to (requested_objs_node_num[procup].size(), 00570 ghost_objects_from_proc[procup]); 00571 00572 std::vector<dof_id_type> request_to_fill_elem_id; 00573 std::vector<unsigned char> request_to_fill_node_num; 00574 comm.send_receive(procup, requested_objs_elem_id[procup], 00575 procdown, request_to_fill_elem_id); 00576 comm.send_receive(procup, requested_objs_node_num[procup], 00577 procdown, request_to_fill_node_num); 00578 00579 // Find the id of each requested element 00580 std::size_t request_size = request_to_fill_elem_id.size(); 00581 std::vector<dof_id_type> request_to_fill_id(request_size); 00582 for (std::size_t i=0; i != request_size; ++i) 00583 { 00584 const Elem *elem = mesh.elem(request_to_fill_elem_id[i]); 00585 libmesh_assert(elem); 00586 00587 const unsigned int n = request_to_fill_node_num[i]; 00588 libmesh_assert_less (n, elem->n_nodes()); 00589 00590 Node *node = elem->get_node(n); 00591 libmesh_assert(node); 00592 00593 // This isn't a safe assertion in the case where we're 00594 // synching processor ids 00595 // libmesh_assert_equal_to (node->processor_id(), comm.rank()); 00596 00597 request_to_fill_id[i] = node->id(); 00598 } 00599 00600 // Gather whatever data the user wants 00601 std::vector<typename SyncFunctor::datum> data; 00602 sync.gather_data(request_to_fill_id, data); 00603 00604 // Trade back the results 00605 std::vector<typename SyncFunctor::datum> received_data; 00606 comm.send_receive(procdown, data, 00607 procup, received_data); 00608 libmesh_assert_equal_to (requested_objs_elem_id[procup].size(), 00609 received_data.size()); 00610 00611 // Let the user process the results 00612 sync.act_on_data(requested_objs_id[procup], received_data); 00613 } 00614 } 00615 00616 00617 } 00618 00619 00620 00621 // This struct can be created and passed to the 00622 // Parallel::sync_dofobject_data_by_id() function. 00623 struct SyncNodalPositions 00624 { 00625 // The constructor. You need a reference to the mesh where you will 00626 // be setting/getting nodal positions. 00627 explicit 00628 SyncNodalPositions(MeshBase& m); 00629 00630 // The datum typedef is required of this functor, so that the 00631 // Parallel::sync_dofobject_data_by_id() function can create e.g. 00632 // std::vector<datum>. 00633 typedef Point datum; 00634 00635 // First required interface. This function must fill up the data vector for the 00636 // ids specified in the ids vector. 00637 void gather_data (const std::vector<dof_id_type>& ids, std::vector<datum>& data); 00638 00639 // Second required interface. This function must do something with the data in 00640 // the data vector for the ids in the ids vector. 00641 void act_on_data (const std::vector<dof_id_type>& ids, std::vector<datum>& data); 00642 00643 MeshBase &mesh; 00644 }; 00645 00646 00647 } // namespace libMesh 00648 00649 #endif // LIBMESH_PARALLEL_GHOST_SYNC_H