parallel_ghost_sync.h
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 #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 00032 namespace libMesh 00033 { 00034 00035 00036 00037 //-------------------------------------------------------------------------- 00038 namespace Parallel { 00039 00040 //------------------------------------------------------------------------ 00057 template <typename Iterator, 00058 typename DofObjType, 00059 typename SyncFunctor> 00060 void sync_dofobject_data_by_xyz(const Iterator& range_begin, 00061 const Iterator& range_end, 00062 LocationMap<DofObjType>* location_map, 00063 SyncFunctor& sync); 00064 00065 //------------------------------------------------------------------------ 00078 template <typename Iterator, 00079 typename SyncFunctor> 00080 void sync_dofobject_data_by_id(const Iterator& range_begin, 00081 const Iterator& range_end, 00082 SyncFunctor& sync); 00083 00084 //------------------------------------------------------------------------ 00098 template <typename Iterator, 00099 typename SyncFunctor> 00100 void sync_element_data_by_parent_id(MeshBase& mesh, 00101 const Iterator& range_begin, 00102 const Iterator& range_end, 00103 SyncFunctor& sync); 00104 00105 //------------------------------------------------------------------------ 00106 // Parallel members 00107 00108 template <typename Iterator, 00109 typename DofObjType, 00110 typename SyncFunctor> 00111 void sync_dofobject_data_by_xyz(const Iterator& range_begin, 00112 const Iterator& range_end, 00113 LocationMap<DofObjType>& location_map, 00114 SyncFunctor& sync) 00115 { 00116 // This function must be run on all processors at once 00117 parallel_only(); 00118 00119 // We need a valid location_map 00120 #ifdef DEBUG 00121 bool need_map_update = (range_begin != range_end && location_map.empty()); 00122 CommWorld.max(need_map_update); 00123 libmesh_assert(!need_map_update); 00124 #endif 00125 00126 // Count the objectss to ask each processor about 00127 std::vector<dof_id_type> 00128 ghost_objects_from_proc(libMesh::n_processors(), 0); 00129 00130 for (Iterator it = range_begin; it != range_end; ++it) 00131 { 00132 DofObjType *obj = *it; 00133 libmesh_assert (obj); 00134 processor_id_type obj_procid = obj->processor_id(); 00135 if (obj_procid != DofObject::invalid_processor_id) 00136 ghost_objects_from_proc[obj_procid]++; 00137 } 00138 00139 // Request sets to send to each processor 00140 std::vector<std::vector<Real> > 00141 requested_objs_x(libMesh::n_processors()), 00142 requested_objs_y(libMesh::n_processors()), 00143 requested_objs_z(libMesh::n_processors()); 00144 // Corresponding ids to keep track of 00145 std::vector<std::vector<dof_id_type> > 00146 requested_objs_id(libMesh::n_processors()); 00147 00148 // We know how many objects live on each processor, so reserve() 00149 // space for each. 00150 for (processor_id_type p=0; p != libMesh::n_processors(); ++p) 00151 if (p != libMesh::processor_id()) 00152 { 00153 requested_objs_x[p].reserve(ghost_objects_from_proc[p]); 00154 requested_objs_y[p].reserve(ghost_objects_from_proc[p]); 00155 requested_objs_z[p].reserve(ghost_objects_from_proc[p]); 00156 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00157 } 00158 for (Iterator it = range_begin; it != range_end; ++it) 00159 { 00160 DofObjType *obj = *it; 00161 processor_id_type obj_procid = obj->processor_id(); 00162 if (obj_procid == libMesh::processor_id() || 00163 obj_procid == DofObject::invalid_processor_id) 00164 continue; 00165 00166 Point p = location_map.point_of(*obj); 00167 requested_objs_x[obj_procid].push_back(p(0)); 00168 requested_objs_y[obj_procid].push_back(p(1)); 00169 requested_objs_z[obj_procid].push_back(p(2)); 00170 requested_objs_id[obj_procid].push_back(obj->id()); 00171 } 00172 00173 // Trade requests with other processors 00174 for (processor_id_type p=1; p != libMesh::n_processors(); ++p) 00175 { 00176 // Trade my requests with processor procup and procdown 00177 const processor_id_type procup = 00178 libmesh_cast_int<processor_id_type> 00179 ((libMesh::processor_id() + p) % libMesh::n_processors()); 00180 const processor_id_type procdown = 00181 libmesh_cast_int<processor_id_type> 00182 ((libMesh::n_processors() + libMesh::processor_id() - p) % 00183 libMesh::n_processors()); 00184 std::vector<Real> request_to_fill_x, 00185 request_to_fill_y, 00186 request_to_fill_z; 00187 CommWorld.send_receive(procup, requested_objs_x[procup], 00188 procdown, request_to_fill_x); 00189 CommWorld.send_receive(procup, requested_objs_y[procup], 00190 procdown, request_to_fill_y); 00191 CommWorld.send_receive(procup, requested_objs_z[procup], 00192 procdown, request_to_fill_z); 00193 00194 // Find the local id of each requested object 00195 std::vector<dof_id_type> request_to_fill_id(request_to_fill_x.size()); 00196 for (std::size_t i=0; i != request_to_fill_x.size(); ++i) 00197 { 00198 Point pt(request_to_fill_x[i], 00199 request_to_fill_y[i], 00200 request_to_fill_z[i]); 00201 00202 // Look for this object in the multimap 00203 DofObjType *obj = location_map.find(pt); 00204 00205 // We'd better find every object we're asked for 00206 libmesh_assert (obj); 00207 00208 // Return the object's correct processor id, 00209 // and our (correct if it's local) id for it. 00210 request_to_fill_id[i] = obj->id(); 00211 } 00212 00213 // Gather whatever data the user wants 00214 std::vector<typename SyncFunctor::datum> data; 00215 sync.gather_data(request_to_fill_id, data); 00216 00217 // Trade back the results 00218 std::vector<typename SyncFunctor::datum> received_data; 00219 CommWorld.send_receive(procdown, data, 00220 procup, received_data); 00221 libmesh_assert_equal_to (requested_objs_x[procup].size(), 00222 received_data.size()); 00223 00224 // Let the user process the results 00225 sync.act_on_data(requested_objs_id[procup], received_data); 00226 } 00227 } 00228 00229 00230 00231 template <typename Iterator, 00232 typename SyncFunctor> 00233 void sync_dofobject_data_by_id(const Iterator& range_begin, 00234 const Iterator& range_end, 00235 SyncFunctor& sync) 00236 { 00237 // This function must be run on all processors at once 00238 parallel_only(); 00239 00240 // Count the objects to ask each processor about 00241 std::vector<dof_id_type> 00242 ghost_objects_from_proc(libMesh::n_processors(), 0); 00243 00244 for (Iterator it = range_begin; it != range_end; ++it) 00245 { 00246 DofObject *obj = *it; 00247 libmesh_assert (obj); 00248 processor_id_type obj_procid = obj->processor_id(); 00249 if (obj_procid != DofObject::invalid_processor_id) 00250 ghost_objects_from_proc[obj_procid]++; 00251 } 00252 00253 // Request sets to send to each processor 00254 std::vector<std::vector<dof_id_type> > 00255 requested_objs_id(libMesh::n_processors()); 00256 00257 // We know how many objects live on each processor, so reserve() 00258 // space for each. 00259 for (processor_id_type p=0; p != libMesh::n_processors(); ++p) 00260 if (p != libMesh::processor_id()) 00261 { 00262 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00263 } 00264 for (Iterator it = range_begin; it != range_end; ++it) 00265 { 00266 DofObject *obj = *it; 00267 processor_id_type obj_procid = obj->processor_id(); 00268 if (obj_procid == libMesh::processor_id() || 00269 obj_procid == DofObject::invalid_processor_id) 00270 continue; 00271 00272 requested_objs_id[obj_procid].push_back(obj->id()); 00273 } 00274 00275 // Trade requests with other processors 00276 for (processor_id_type p=1; p != libMesh::n_processors(); ++p) 00277 { 00278 // Trade my requests with processor procup and procdown 00279 const processor_id_type procup = 00280 libmesh_cast_int<processor_id_type> 00281 (libMesh::processor_id() + p) % libMesh::n_processors(); 00282 const processor_id_type procdown = 00283 libmesh_cast_int<processor_id_type> 00284 ((libMesh::n_processors() + libMesh::processor_id() - p) % 00285 libMesh::n_processors()); 00286 std::vector<dof_id_type> request_to_fill_id; 00287 CommWorld.send_receive(procup, requested_objs_id[procup], 00288 procdown, request_to_fill_id); 00289 00290 // Gather whatever data the user wants 00291 std::vector<typename SyncFunctor::datum> data; 00292 sync.gather_data(request_to_fill_id, data); 00293 00294 // Trade back the results 00295 std::vector<typename SyncFunctor::datum> received_data; 00296 CommWorld.send_receive(procdown, data, 00297 procup, received_data); 00298 libmesh_assert_equal_to (requested_objs_id[procup].size(), 00299 received_data.size()); 00300 00301 // Let the user process the results 00302 sync.act_on_data(requested_objs_id[procup], received_data); 00303 } 00304 } 00305 00306 00307 00308 // If there's no refined elements, there's nothing to sync 00309 #ifdef LIBMESH_ENABLE_AMR 00310 template <typename Iterator, 00311 typename SyncFunctor> 00312 void sync_element_data_by_parent_id(MeshBase& mesh, 00313 const Iterator& range_begin, 00314 const Iterator& range_end, 00315 SyncFunctor& sync) 00316 { 00317 // This function must be run on all processors at once 00318 parallel_only(); 00319 00320 // Count the objects to ask each processor about 00321 std::vector<dof_id_type> 00322 ghost_objects_from_proc(libMesh::n_processors(), 0); 00323 00324 for (Iterator it = range_begin; it != range_end; ++it) 00325 { 00326 DofObject *obj = *it; 00327 libmesh_assert (obj); 00328 processor_id_type obj_procid = obj->processor_id(); 00329 if (obj_procid != DofObject::invalid_processor_id) 00330 ghost_objects_from_proc[obj_procid]++; 00331 } 00332 00333 // Request sets to send to each processor 00334 std::vector<std::vector<dof_id_type> > 00335 requested_objs_id(libMesh::n_processors()), 00336 requested_objs_parent_id(libMesh::n_processors()); 00337 std::vector<std::vector<unsigned char> > 00338 requested_objs_child_num(libMesh::n_processors()); 00339 00340 // We know how many objects live on each processor, so reserve() 00341 // space for each. 00342 for (processor_id_type p=0; p != libMesh::n_processors(); ++p) 00343 if (p != libMesh::processor_id()) 00344 { 00345 requested_objs_id[p].reserve(ghost_objects_from_proc[p]); 00346 requested_objs_parent_id[p].reserve(ghost_objects_from_proc[p]); 00347 requested_objs_child_num[p].reserve(ghost_objects_from_proc[p]); 00348 } 00349 00350 for (Iterator it = range_begin; it != range_end; ++it) 00351 { 00352 Elem *elem = *it; 00353 processor_id_type obj_procid = elem->processor_id(); 00354 if (obj_procid == libMesh::processor_id() || 00355 obj_procid == DofObject::invalid_processor_id) 00356 continue; 00357 const Elem *parent = elem->parent(); 00358 if (!parent || !elem->active()) 00359 continue; 00360 00361 requested_objs_id[obj_procid].push_back(elem->id()); 00362 requested_objs_parent_id[obj_procid].push_back(parent->id()); 00363 requested_objs_child_num[obj_procid].push_back 00364 (libmesh_cast_int<unsigned char> 00365 (parent->which_child_am_i(elem))); 00366 } 00367 00368 // Trade requests with other processors 00369 for (processor_id_type p=1; p != libMesh::n_processors(); ++p) 00370 { 00371 // Trade my requests with processor procup and procdown 00372 const processor_id_type procup = 00373 libmesh_cast_int<processor_id_type> 00374 (libMesh::processor_id() + p) % libMesh::n_processors(); 00375 const processor_id_type procdown = 00376 libmesh_cast_int<processor_id_type> 00377 ((libMesh::n_processors() + libMesh::processor_id() - p) % 00378 libMesh::n_processors()); 00379 std::vector<dof_id_type> request_to_fill_parent_id; 00380 std::vector<unsigned char> request_to_fill_child_num; 00381 CommWorld.send_receive(procup, requested_objs_parent_id[procup], 00382 procdown, request_to_fill_parent_id); 00383 CommWorld.send_receive(procup, requested_objs_child_num[procup], 00384 procdown, request_to_fill_child_num); 00385 00386 // Find the id of each requested element 00387 std::size_t request_size = request_to_fill_parent_id.size(); 00388 std::vector<dof_id_type> request_to_fill_id(request_size); 00389 for (std::size_t i=0; i != request_size; ++i) 00390 { 00391 Elem *parent = mesh.elem(request_to_fill_parent_id[i]); 00392 libmesh_assert(parent); 00393 libmesh_assert(parent->has_children()); 00394 Elem *child = parent->child(request_to_fill_child_num[i]); 00395 libmesh_assert(child); 00396 libmesh_assert(child->active()); 00397 request_to_fill_id[i] = child->id(); 00398 } 00399 00400 // Gather whatever data the user wants 00401 std::vector<typename SyncFunctor::datum> data; 00402 sync.gather_data(request_to_fill_id, data); 00403 00404 // Trade back the results 00405 std::vector<typename SyncFunctor::datum> received_data; 00406 CommWorld.send_receive(procdown, data, 00407 procup, received_data); 00408 libmesh_assert_equal_to (requested_objs_id[procup].size(), 00409 received_data.size()); 00410 00411 // Let the user process the results 00412 sync.act_on_data(requested_objs_id[procup], received_data); 00413 } 00414 } 00415 #else 00416 template <typename Iterator, 00417 typename SyncFunctor> 00418 void sync_element_data_by_parent_id(MeshBase&, 00419 const Iterator&, 00420 const Iterator&, 00421 SyncFunctor&) 00422 { 00423 } 00424 #endif // LIBMESH_ENABLE_AMR 00425 00426 00427 00428 00429 } 00430 00431 00432 // This struct can be created and passed to the 00433 // Parallel::sync_dofobject_data_by_id() function. 00434 struct SyncNodalPositions 00435 { 00436 // The constructor. You need a reference to the mesh where you will 00437 // be setting/getting nodal positions. 00438 explicit 00439 SyncNodalPositions(MeshBase& m); 00440 00441 // The datum typedef is required of this functor, so that the 00442 // Parallel::sync_dofobject_data_by_id() function can create e.g. 00443 // std::vector<datum>. 00444 typedef Point datum; 00445 00446 // First required interface. This function must fill up the data vector for the 00447 // ids specified in the ids vector. 00448 void gather_data (const std::vector<dof_id_type>& ids, std::vector<datum>& data); 00449 00450 // Second required interface. This function must do something with the data in 00451 // the data vector for the ids in the ids vector. 00452 void act_on_data (const std::vector<dof_id_type>& ids, std::vector<datum>& data); 00453 00454 MeshBase &mesh; 00455 }; 00456 00457 00458 } // namespace libMesh 00459 00460 #endif // LIBMESH_PARALLEL_GHOST_SYNC_H
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: