parallel_implementation.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 #ifndef LIBMESH_PARALLEL_IMPLEMENTATION_H 00020 #define LIBMESH_PARALLEL_IMPLEMENTATION_H 00021 00022 // Local includes 00023 #include "parallel.h" 00024 00025 00026 // First declare StandardType specializations so we can use them in anonymous 00027 // helper functions later 00028 00029 namespace libMesh { 00030 namespace Parallel { 00031 00032 #ifdef LIBMESH_HAVE_MPI 00033 00034 #define STANDARD_TYPE(cxxtype,mpitype) \ 00035 template<> \ 00036 class StandardType<cxxtype> : public DataType \ 00037 { \ 00038 public: \ 00039 explicit \ 00040 StandardType(const cxxtype* = NULL) : DataType(mpitype) {} \ 00041 } 00042 00043 #else 00044 00045 #define STANDARD_TYPE(cxxtype,mpitype) \ 00046 template<> \ 00047 class StandardType<cxxtype> : public DataType \ 00048 { \ 00049 public: \ 00050 explicit \ 00051 StandardType(const cxxtype* = NULL) : DataType() {} \ 00052 } 00053 00054 #endif 00055 00056 #define INT_TYPE(cxxtype,mpitype) \ 00057 STANDARD_TYPE(cxxtype,mpitype); \ 00058 \ 00059 template<> \ 00060 struct Attributes<cxxtype> \ 00061 { \ 00062 static const bool has_min_max = true; \ 00063 static void set_lowest(cxxtype& x) { x = std::numeric_limits<cxxtype>::min(); } \ 00064 static void set_highest(cxxtype& x) { x = std::numeric_limits<cxxtype>::max(); } \ 00065 } 00066 00067 #define FLOAT_TYPE(cxxtype,mpitype) \ 00068 STANDARD_TYPE(cxxtype,mpitype); \ 00069 \ 00070 template<> \ 00071 struct Attributes<cxxtype> \ 00072 { \ 00073 static const bool has_min_max = true; \ 00074 static void set_lowest(cxxtype& x) { x = -std::numeric_limits<cxxtype>::max(); } \ 00075 static void set_highest(cxxtype& x) { x = std::numeric_limits<cxxtype>::max(); } \ 00076 } 00077 00078 #define CONTAINER_TYPE(cxxtype) \ 00079 template<typename T> \ 00080 struct Attributes<cxxtype<T> > \ 00081 { \ 00082 static const bool has_min_max = Attributes<T>::has_min_max; \ 00083 static void set_lowest(cxxtype<T>& x) { \ 00084 for (typename cxxtype<T>::iterator i = x.begin(); i != x.end(); ++i) \ 00085 Attributes<T>::set_lowest(*i); } \ 00086 static void set_highest(cxxtype<T>& x) { \ 00087 for (typename cxxtype<T>::iterator i = x.begin(); i != x.end(); ++i) \ 00088 Attributes<T>::set_highest(*i); } \ 00089 } 00090 00091 00092 INT_TYPE(char,MPI_CHAR); 00093 #if MPI_VERSION > 1 00094 INT_TYPE(signed char,MPI_SIGNED_CHAR); 00095 #endif 00096 INT_TYPE(unsigned char,MPI_UNSIGNED_CHAR); 00097 INT_TYPE(short int,MPI_SHORT); 00098 INT_TYPE(unsigned short int,MPI_UNSIGNED_SHORT); 00099 INT_TYPE(int,MPI_INT); 00100 INT_TYPE(unsigned int,MPI_UNSIGNED); 00101 INT_TYPE(long,MPI_LONG); 00102 INT_TYPE(unsigned long,MPI_UNSIGNED_LONG); 00103 FLOAT_TYPE(float,MPI_FLOAT); 00104 FLOAT_TYPE(double,MPI_DOUBLE); 00105 FLOAT_TYPE(long double,MPI_LONG_DOUBLE); 00106 CONTAINER_TYPE(std::set); 00107 CONTAINER_TYPE(std::vector); 00108 00109 // We'd love to do a singleton pattern on derived data types, rather 00110 // than commit, free, commit, free, ad infinitum... but it's a 00111 // little tricky when our T1 and T2 are undefined. 00112 template<typename T1, typename T2> 00113 class StandardType<std::pair<T1, T2> > : public DataType 00114 { 00115 public: 00116 explicit 00117 StandardType(const std::pair<T1, T2> *example = NULL) { 00118 // We need an example for MPI_Address to use 00119 libmesh_assert(example); 00120 00121 #ifdef LIBMESH_HAVE_MPI 00122 // Get the sub-data-types, and make sure they live long enough 00123 // to construct the derived type 00124 StandardType<T1> d1(&example->first); 00125 StandardType<T2> d2(&example->second); 00126 MPI_Datatype types[] = { (data_type)d1, (data_type)d2 }; 00127 int blocklengths[] = {1,1}; 00128 00129 MPI_Aint displs[2]; 00130 MPI_Address (const_cast<T1*>(&example->first), &displs[0]); 00131 MPI_Address (const_cast<T2*>(&example->second), &displs[1]); 00132 displs[1] -= displs[0]; 00133 displs[0] = 0; 00134 00135 #if MPI_VERSION > 1 00136 MPI_Type_create_struct (2, blocklengths, displs, types, &_datatype); 00137 #else 00138 MPI_Type_struct (2, blocklengths, displs, types, &_datatype); 00139 #endif // #if MPI_VERSION > 1 00140 MPI_Type_commit (&_datatype); 00141 #endif // LIBMESH_HAVE_MPI 00142 } 00143 00144 ~StandardType() { this->free(); } 00145 }; 00146 00147 template<typename T> 00148 class StandardType<std::complex<T> > : public DataType 00149 { 00150 public: 00151 explicit 00152 StandardType(const std::complex<T> * /*example*/ = NULL) : 00153 DataType(StandardType<T>(NULL), 2) {} 00154 00155 ~StandardType() { this->free(); } 00156 }; 00157 00158 } // namespace Parallel 00159 00160 } // namespace libMesh 00161 00162 00163 // Anonymous namespace for helper functions 00164 namespace { 00165 00166 // Safe to use this here since it won't "infect" anything outside the 00167 // anonymous namespace 00168 using namespace libMesh; 00169 00170 // Internal helper function to create vector<something_useable> from 00171 // vector<bool> for compatibility with MPI bitwise operations 00172 template <typename T> 00173 inline void pack_vector_bool(const std::vector<bool> &in, 00174 std::vector<T> &out) 00175 { 00176 unsigned int data_bits = 8*sizeof(T); 00177 std::size_t in_size = in.size(); 00178 std::size_t out_size = in_size/data_bits + (in_size%data_bits?1:0); 00179 out.clear(); 00180 out.resize(out_size); 00181 for (std::size_t i=0; i != in_size; ++i) 00182 { 00183 std::size_t index = i/data_bits; 00184 std::size_t offset = i%data_bits; 00185 out[index] += (in[i]?1:0) << offset; 00186 } 00187 } 00188 00189 // Internal helper function to create vector<bool> from 00190 // vector<something usable> for compatibility with MPI byte 00191 // operations 00192 template <typename T> 00193 inline void unpack_vector_bool(const std::vector<T> &in, 00194 std::vector<bool> &out) 00195 { 00196 unsigned int data_bits = 8*sizeof(T); 00197 // We need the output vector to already be properly sized 00198 std::size_t out_size = out.size(); 00199 libmesh_assert_equal_to (out_size/data_bits + (out_size%data_bits?1:0), in.size()); 00200 00201 for (std::size_t i=0; i != out_size; ++i) 00202 { 00203 std::size_t index = i/data_bits; 00204 std::size_t offset = i%data_bits; 00205 out[i] = in[index] << (data_bits-1-offset) >> (data_bits-1); 00206 } 00207 } 00208 00209 00210 #ifdef LIBMESH_HAVE_MPI 00211 // We use a helper function here to avoid ambiguity when calling 00212 // send_receive of (vector<vector<T>>,vector<vector<T>>) 00213 template <typename T1, typename T2> 00214 inline void send_receive_vec_of_vec 00215 (const unsigned int dest_processor_id, 00216 std::vector<std::vector<T1> > &send, 00217 const unsigned int source_processor_id, 00218 std::vector<std::vector<T2> > &recv, 00219 const Parallel::MessageTag &send_tag, 00220 const Parallel::MessageTag &recv_tag, 00221 const Parallel::Communicator &comm) 00222 { 00223 START_LOG("send_receive()", "Parallel"); 00224 00225 if (dest_processor_id == comm.rank() && 00226 source_processor_id == comm.rank()) 00227 { 00228 recv = send; 00229 STOP_LOG("send_receive()", "Parallel"); 00230 return; 00231 } 00232 00233 // temporary buffers - these will be sized in bytes 00234 // and manipulated with MPI_Pack and friends 00235 std::vector<char> sendbuf, recvbuf; 00236 00237 // figure out how many bytes we need to pack all the data 00238 int packedsize=0, sendsize=0; 00239 00240 // The outer buffer size 00241 MPI_Pack_size (1, 00242 Parallel::StandardType<unsigned int>(), 00243 comm.get(), 00244 &packedsize); 00245 sendsize += packedsize; 00246 00247 for (std::size_t i=0; i<send.size(); i++) 00248 { 00249 // The size of the ith inner buffer 00250 MPI_Pack_size (1, 00251 Parallel::StandardType<unsigned int>(), 00252 comm.get(), 00253 &packedsize); 00254 sendsize += packedsize; 00255 00256 // The data for each inner buffer 00257 MPI_Pack_size (libmesh_cast_int<int>(send[i].size()), 00258 Parallel::StandardType<T1> 00259 (send[i].empty() ? NULL : &send[i][0]), 00260 comm.get(), 00261 &packedsize); 00262 sendsize += packedsize; 00263 } 00264 00265 libmesh_assert (sendsize /* should at least be 1! */); 00266 sendbuf.resize (sendsize); 00267 00268 // Pack the send buffer 00269 int pos=0; 00270 00271 // ... the size of the outer buffer 00272 sendsize = libmesh_cast_int<int>(send.size()); 00273 MPI_Pack (&sendsize, 1, Parallel::StandardType<unsigned int>(), 00274 &sendbuf[0], libmesh_cast_int<int>(sendbuf.size()), &pos, 00275 comm.get()); 00276 00277 for (std::size_t i=0; i<send.size(); i++) 00278 { 00279 // ... the size of the ith inner buffer 00280 sendsize = libmesh_cast_int<int>(send[i].size()); 00281 MPI_Pack (&sendsize, 1, Parallel::StandardType<unsigned int>(), 00282 &sendbuf[0], libmesh_cast_int<int>(sendbuf.size()), &pos, 00283 comm.get()); 00284 00285 // ... the contents of the ith inner buffer 00286 if (!send[i].empty()) 00287 MPI_Pack (&send[i][0], libmesh_cast_int<int>(send[i].size()), 00288 Parallel::StandardType<T1>(&send[i][0]), 00289 &sendbuf[0], libmesh_cast_int<int>(sendbuf.size()), &pos, 00290 comm.get()); 00291 } 00292 00293 libmesh_assert_equal_to (static_cast<unsigned int>(pos), sendbuf.size()); 00294 00295 Parallel::Request request; 00296 00297 comm.send (dest_processor_id, sendbuf, MPI_PACKED, request, send_tag); 00298 00299 comm.receive (source_processor_id, recvbuf, MPI_PACKED, recv_tag); 00300 00301 // Unpack the received buffer 00302 libmesh_assert (!recvbuf.empty()); 00303 pos=0; 00304 MPI_Unpack (&recvbuf[0], libmesh_cast_int<int>(recvbuf.size()), &pos, 00305 &sendsize, 1, Parallel::StandardType<unsigned int>(), 00306 comm.get()); 00307 00308 // ... size the outer buffer 00309 recv.resize (sendsize); 00310 00311 for (std::size_t i=0; i<recv.size(); i++) 00312 { 00313 MPI_Unpack (&recvbuf[0], libmesh_cast_int<int>(recvbuf.size()), &pos, 00314 &sendsize, 1, Parallel::StandardType<unsigned int>(), 00315 comm.get()); 00316 00317 // ... size the inner buffer 00318 recv[i].resize (sendsize); 00319 00320 // ... unpack the inner buffer if it is not empty 00321 if (!recv[i].empty()) 00322 MPI_Unpack (&recvbuf[0], libmesh_cast_int<int>(recvbuf.size()), &pos, 00323 &recv[i][0], libmesh_cast_int<int>(recv[i].size()), 00324 Parallel::StandardType<T2>(&recv[i][0]), 00325 comm.get()); 00326 } 00327 00328 request.wait(); 00329 00330 STOP_LOG("send_receive()", "Parallel"); 00331 } 00332 00333 #endif // LIBMESH_HAVE_MPI 00334 00335 } // Anonymous namespace 00336 00337 00338 00339 namespace libMesh 00340 { 00341 00342 namespace Parallel 00343 { 00344 00345 /* 00346 * A reference to the default libMesh communicator. This is now 00347 * deprecated - instead of libMesh::Parallel::Communicator_World use 00348 * libMesh::CommWorld 00349 */ 00350 extern Communicator& Communicator_World; 00351 00352 00356 template <typename Context, typename Iter> 00357 inline void pack_range (const Context *context, 00358 Iter range_begin, 00359 const Iter range_end, 00360 std::vector<int>& buffer) 00361 { 00362 // Count the total size of and preallocate buffer for efficiency 00363 unsigned int buffer_size = 0; 00364 for (Iter range_count = range_begin; 00365 range_count != range_end; 00366 ++range_count) 00367 { 00368 buffer_size += Parallel::packable_size(*range_count, context); 00369 } 00370 buffer.reserve(buffer.size() + buffer_size); 00371 00372 // Pack the objects into the buffer 00373 for (; range_begin != range_end; ++range_begin) 00374 { 00375 #ifndef NDEBUG 00376 std::size_t old_size = buffer.size(); 00377 #endif 00378 00379 Parallel::pack(*range_begin, buffer, context); 00380 00381 #ifndef NDEBUG 00382 unsigned int my_packable_size = 00383 Parallel::packable_size(*range_begin, context); 00384 unsigned int my_packed_size = 00385 Parallel::packed_size (*range_begin, buffer.begin() + 00386 old_size); 00387 libmesh_assert_equal_to (my_packable_size, my_packed_size); 00388 libmesh_assert_equal_to (buffer.size(), old_size + my_packable_size); 00389 #endif 00390 } 00391 } 00392 00393 00394 00398 template <typename Context, typename OutputIter> 00399 inline void unpack_range (const std::vector<int>& buffer, 00400 Context *context, 00401 OutputIter out) 00402 { 00403 // Our objects should be of the correct type to be assigned to the 00404 // output iterator 00405 typedef typename std::iterator_traits<OutputIter>::value_type T; 00406 00407 // Loop through the buffer and unpack each object, returning the 00408 // object pointer via the output iterator 00409 std::vector<int>::const_iterator next_object_start = buffer.begin(); 00410 00411 while (next_object_start < buffer.end()) 00412 { 00413 T* obj; 00414 Parallel::unpack(next_object_start, &obj, context); 00415 libmesh_assert(obj); 00416 next_object_start += Parallel::packed_size(obj, next_object_start); 00417 *out++ = obj; 00418 } 00419 00420 // We should have used up the exact amount of data in the buffer 00421 libmesh_assert (next_object_start == buffer.end()); 00422 } 00423 00424 00425 inline Communicator::Communicator () : 00426 #ifdef LIBMESH_HAVE_MPI 00427 _communicator(MPI_COMM_NULL), 00428 #endif 00429 _rank(0), 00430 _size(1), 00431 used_tag_values(), 00432 _I_duped_it(false) {} 00433 00434 inline Communicator::Communicator (const communicator &comm) : 00435 #ifdef LIBMESH_HAVE_MPI 00436 _communicator(MPI_COMM_NULL), 00437 #endif 00438 _rank(0), 00439 _size(1), 00440 used_tag_values(), 00441 _I_duped_it(false) 00442 { 00443 this->assign(comm); 00444 } 00445 00446 inline Communicator::~Communicator () { 00447 this->clear(); 00448 } 00449 00450 #ifdef LIBMESH_HAVE_MPI 00451 inline void Communicator::split(int color, int key, Communicator &target) { 00452 MPI_Comm_split(this->get(), color, key, &target.get()); 00453 } 00454 #else 00455 inline void Communicator::split(int, int, Communicator &target) { 00456 target.assign(this->get()); 00457 } 00458 #endif 00459 00460 inline void Communicator::duplicate(const Communicator &comm) { 00461 this->duplicate(comm._communicator); 00462 } 00463 00464 #ifdef LIBMESH_HAVE_MPI 00465 inline void Communicator::duplicate(const communicator &comm) { 00466 if (_communicator != MPI_COMM_NULL) 00467 { 00468 MPI_Comm_dup(comm, &_communicator); 00469 _I_duped_it = true; 00470 } 00471 this->assign(_communicator); 00472 } 00473 #else 00474 inline void Communicator::duplicate(const communicator &) { } 00475 #endif 00476 00477 inline void Communicator::clear() { 00478 #ifdef LIBMESH_HAVE_MPI 00479 if (_I_duped_it) 00480 { 00481 libmesh_assert (_communicator != MPI_COMM_NULL); 00482 MPI_Comm_free(&_communicator); 00483 _communicator = MPI_COMM_NULL; 00484 } 00485 _I_duped_it = false; 00486 #endif 00487 } 00488 00489 inline Communicator& Communicator::operator= (const communicator &comm) { 00490 this->clear(); 00491 this->assign(comm); 00492 return *this; 00493 } 00494 00495 // Disallowed copy constructor 00496 inline Communicator::Communicator (const Communicator &) : 00497 #ifdef LIBMESH_HAVE_MPI 00498 _communicator(MPI_COMM_NULL), 00499 #endif 00500 _rank(0), 00501 _size(1), 00502 used_tag_values(), 00503 _I_duped_it(false) 00504 { 00505 libmesh_error(); 00506 } 00507 00508 inline void Communicator::assign(const communicator &comm) 00509 { 00510 _communicator = comm; 00511 #ifdef LIBMESH_HAVE_MPI 00512 if (_communicator != MPI_COMM_NULL) 00513 { 00514 int i; 00515 MPI_Comm_size(_communicator, &i); 00516 libmesh_assert_greater_equal (i, 0); 00517 _size = static_cast<unsigned int>(i); 00518 00519 MPI_Comm_rank(_communicator, &i); 00520 libmesh_assert_greater_equal (i, 0); 00521 _rank = static_cast<unsigned int>(i); 00522 } 00523 else 00524 { 00525 _rank = 0; 00526 _size = 1; 00527 } 00528 #endif 00529 } 00530 00531 00532 00533 inline Status::Status () : 00534 _status(), 00535 _datatype() 00536 {} 00537 00538 inline Status::Status (const data_type &type) : 00539 _status(), 00540 _datatype(type) 00541 {} 00542 00543 inline Status::Status (const status &stat) : 00544 _status(stat), 00545 _datatype() 00546 {} 00547 00548 inline Status::Status (const status &stat, 00549 const data_type &type) : 00550 _status(stat), 00551 _datatype(type) 00552 {} 00553 00554 inline Status::Status (const Status &stat) : 00555 _status(stat._status), 00556 _datatype(stat._datatype) 00557 {} 00558 00559 inline Status::Status (const Status &stat, 00560 const data_type &type) : 00561 _status(stat._status), 00562 _datatype(type) 00563 {} 00564 00565 inline int Status::source () const 00566 { 00567 #ifdef LIBMESH_HAVE_MPI 00568 return _status.MPI_SOURCE; 00569 #else 00570 return 0; 00571 #endif 00572 } 00573 00574 inline int Status::tag () const 00575 { 00576 #ifdef LIBMESH_HAVE_MPI 00577 return _status.MPI_TAG; 00578 #else 00579 libmesh_error(); 00580 return 0; 00581 #endif 00582 } 00583 00584 #ifdef LIBMESH_HAVE_MPI 00585 inline unsigned int Status::size (const data_type &type) const 00586 { 00587 int msg_size; 00588 MPI_Get_count (const_cast<MPI_Status*>(&_status), type, &msg_size); 00589 libmesh_assert_greater_equal (msg_size, 0); 00590 return msg_size; 00591 } 00592 #else 00593 inline unsigned int Status::size (const data_type &) const 00594 { 00595 libmesh_error(); 00596 return 0; 00597 } 00598 #endif 00599 00600 inline unsigned int Status::size () const 00601 { return this->size (this->datatype()); } 00602 00603 00604 00605 inline Request::Request () : 00606 #ifdef LIBMESH_HAVE_MPI 00607 _request(MPI_REQUEST_NULL), 00608 #else 00609 _request(), 00610 #endif 00611 post_wait_work(NULL) 00612 {} 00613 00614 inline Request::Request (const request &r) : 00615 _request(r), 00616 post_wait_work(NULL) 00617 {} 00618 00619 inline Request::Request (const Request &other) : 00620 _request(other._request), 00621 post_wait_work(other.post_wait_work) 00622 { 00623 // operator= should behave like a shared pointer 00624 if (post_wait_work) 00625 post_wait_work->second++; 00626 } 00627 00628 inline void Request::cleanup() 00629 { 00630 if (post_wait_work) 00631 { 00632 // Decrement the use count 00633 post_wait_work->second--; 00634 00635 if (!post_wait_work->second) 00636 { 00637 #ifdef DEBUG 00638 // If we're done using this request, then we'd better have 00639 // done the work we waited for 00640 for (std::vector<PostWaitWork*>::iterator i = 00641 post_wait_work->first.begin(); 00642 i != post_wait_work->first.end(); ++i) 00643 libmesh_assert(!(*i)); 00644 #endif 00645 delete post_wait_work; 00646 post_wait_work = NULL; 00647 } 00648 } 00649 } 00650 00651 inline Request& Request::operator = (const Request &other) 00652 { 00653 this->cleanup(); 00654 _request = other._request; 00655 post_wait_work = other.post_wait_work; 00656 00657 // operator= should behave like a shared pointer 00658 if (post_wait_work) 00659 post_wait_work->second++; 00660 00661 return *this; 00662 } 00663 00664 inline Request& Request::operator = (const request &r) 00665 { 00666 this->cleanup(); 00667 _request = r; 00668 post_wait_work = NULL; 00669 return *this; 00670 } 00671 00672 inline Request::~Request () { 00673 this->cleanup(); 00674 } 00675 00676 inline Status Request::wait () 00677 { 00678 START_LOG("wait()", "Parallel::Request"); 00679 00680 Status stat; 00681 #ifdef LIBMESH_HAVE_MPI 00682 MPI_Wait (&_request, stat.get()); 00683 #endif 00684 if (post_wait_work) 00685 for (std::vector<PostWaitWork*>::iterator i = 00686 post_wait_work->first.begin(); 00687 i != post_wait_work->first.end(); ++i) 00688 { 00689 // The user should never try to give us NULL work or try 00690 // to wait() twice. 00691 libmesh_assert (*i); 00692 (*i)->run(); 00693 delete (*i); 00694 *i = NULL; 00695 } 00696 00697 STOP_LOG("wait()", "Parallel::Request"); 00698 return stat; 00699 } 00700 00701 inline bool Request::test () 00702 { 00703 #ifdef LIBMESH_HAVE_MPI 00704 int val=0; 00705 00706 MPI_Test (&_request, 00707 &val, 00708 MPI_STATUS_IGNORE); 00709 if (val) 00710 { 00711 libmesh_assert (_request == MPI_REQUEST_NULL); 00712 libmesh_assert_equal_to (val, 1); 00713 } 00714 00715 return val; 00716 #else 00717 return true; 00718 #endif 00719 } 00720 00721 #ifdef LIBMESH_HAVE_MPI 00722 inline bool Request::test (status &stat) 00723 { 00724 int val=0; 00725 00726 MPI_Test (&_request, 00727 &val, 00728 &stat); 00729 00730 return val; 00731 } 00732 #else 00733 inline bool Request::test (status &) 00734 { 00735 return true; 00736 } 00737 #endif 00738 00739 inline void Request::add_post_wait_work(PostWaitWork* work) 00740 { 00741 if (!post_wait_work) 00742 post_wait_work = new 00743 std::pair<std::vector <PostWaitWork* >, unsigned int> 00744 (std::vector <PostWaitWork* >(), 1); 00745 post_wait_work->first.push_back(work); 00746 } 00747 00748 00749 00750 inline void barrier (const Communicator &comm = Communicator_World) 00751 { 00752 comm.barrier(); 00753 } 00754 00758 #ifdef LIBMESH_HAVE_MPI 00759 inline void Communicator::barrier () const 00760 { 00761 if (libMesh::n_processors() > 1) 00762 { 00763 START_LOG("barrier()", "Parallel"); 00764 00765 MPI_Barrier (this->get()); 00766 00767 STOP_LOG("barrier()", "Parallel"); 00768 } 00769 } 00770 #else 00771 inline void Communicator::barrier () const {} 00772 #endif 00773 00774 template <typename T> 00775 inline bool verify(const T &r, 00776 const Communicator &comm = Communicator_World) 00777 { return comm.verify(r); } 00778 00779 template <typename T> 00780 inline void min(T &r, 00781 const Communicator &comm = Communicator_World) 00782 { comm.min(r); } 00783 00784 template <typename T, typename U> 00785 inline void minloc(T &r, 00786 U &min_id, 00787 const Communicator &comm = Communicator_World) 00788 { comm.minloc(r, min_id); } 00789 00790 template <typename T> 00791 inline void max(T &r, 00792 const Communicator &comm = Communicator_World) 00793 { comm.max(r); } 00794 00795 template <typename T, typename U> 00796 inline void maxloc(T &r, 00797 U &max_id, 00798 const Communicator &comm = Communicator_World) 00799 { comm.maxloc(r, max_id); } 00800 00801 template <typename T> 00802 inline void sum(T &r, 00803 const Communicator &comm = Communicator_World) 00804 { comm.sum(r); } 00805 00806 template <typename T> 00807 inline void set_union(T &data, const unsigned int root_id, 00808 const Communicator &comm = Communicator_World) 00809 { comm.set_union(data, root_id); } 00810 00811 template <typename T> 00812 inline void set_union(T &data, 00813 const Communicator &comm = Communicator_World) 00814 { comm.set_union(data); } 00815 00816 inline status probe (const unsigned int src_processor_id, 00817 const MessageTag &tag=any_tag, 00818 const Communicator &comm = Communicator_World) 00819 { return comm.probe(src_processor_id, tag); } 00820 00821 template <typename T> 00822 inline void send (const unsigned int dest_processor_id, 00823 T &data, 00824 const MessageTag &tag=no_tag, 00825 const Communicator &comm = Communicator_World) 00826 { comm.send(dest_processor_id, data, tag); } 00827 00828 template <typename T> 00829 inline void send (const unsigned int dest_processor_id, 00830 T &data, 00831 Request &req, 00832 const MessageTag &tag=no_tag, 00833 const Communicator &comm = Communicator_World) 00834 { comm.send(dest_processor_id, data, req, tag); } 00835 00836 template <typename T> 00837 inline void send (const unsigned int dest_processor_id, 00838 T &data, 00839 const DataType &type, 00840 const MessageTag &tag=no_tag, 00841 const Communicator &comm = Communicator_World) 00842 { comm.send(dest_processor_id, data, type, tag); } 00843 00844 template <typename T> 00845 inline void send (const unsigned int dest_processor_id, 00846 T &data, 00847 const DataType &type, 00848 Request &req, 00849 const MessageTag &tag=no_tag, 00850 const Communicator &comm = Communicator_World) 00851 { comm.send(dest_processor_id, data, type, req, tag); } 00852 00853 00854 template <typename Context, typename Iter> 00855 inline void send_packed_range (const unsigned int dest_processor_id, 00856 const Context *context, 00857 Iter range_begin, 00858 const Iter range_end, 00859 const MessageTag &tag=no_tag, 00860 const Communicator &comm = Communicator_World) 00861 { comm.send_packed_range(dest_processor_id, context, range_begin, range_end, tag); } 00862 00863 00864 template <typename Context, typename Iter> 00865 inline void send_packed_range (const unsigned int dest_processor_id, 00866 const Context *context, 00867 Iter range_begin, 00868 const Iter range_end, 00869 Request &req, 00870 const MessageTag &tag=no_tag, 00871 const Communicator &comm = Communicator_World) 00872 { comm.send_packed_range(dest_processor_id, context, range_begin, range_end, req, tag); } 00873 00874 00875 template <typename T> 00876 inline void nonblocking_send (const unsigned int dest_processor_id, 00877 T &buf, 00878 const DataType &type, 00879 Request &r, 00880 const MessageTag &tag=no_tag, 00881 const Communicator &comm = Communicator_World) 00882 { comm.send (dest_processor_id, buf, type, r, tag); } 00883 00884 template <typename T> 00885 inline void nonblocking_send (const unsigned int dest_processor_id, 00886 T &buf, 00887 Request &r, 00888 const MessageTag &tag=no_tag, 00889 const Communicator &comm = Communicator_World) 00890 { comm.send (dest_processor_id, buf, r, tag); } 00891 00892 template <typename T> 00893 inline Status receive (const unsigned int src_processor_id, 00894 T &buf, 00895 const MessageTag &tag=any_tag, 00896 const Communicator &comm = Communicator_World) 00897 { return comm.receive (src_processor_id, buf, tag); } 00898 00899 template <typename T> 00900 inline void receive (const unsigned int src_processor_id, 00901 T &buf, 00902 Request &req, 00903 const MessageTag &tag=any_tag, 00904 const Communicator &comm = Communicator_World) 00905 { comm.receive (src_processor_id, buf, req, tag); } 00906 00907 template <typename T> 00908 inline Status receive (const unsigned int src_processor_id, 00909 T &buf, 00910 const DataType &type, 00911 const MessageTag &tag=any_tag, 00912 const Communicator &comm = Communicator_World) 00913 { return comm.receive (src_processor_id, buf, type, tag); } 00914 00915 template <typename T> 00916 inline void receive (const unsigned int src_processor_id, 00917 T &buf, 00918 const DataType &type, 00919 Request &req, 00920 const MessageTag &tag=any_tag, 00921 const Communicator &comm = Communicator_World) 00922 { comm.receive (src_processor_id, buf, type, req, tag); } 00923 00924 template <typename Context, typename OutputIter> 00925 inline void receive_packed_range (const unsigned int src_processor_id, 00926 Context *context, 00927 OutputIter out, 00928 const MessageTag &tag=any_tag, 00929 const Communicator &comm = Communicator_World) 00930 { comm.receive_packed_range (src_processor_id, context, out, tag); } 00931 00932 template <typename Context, typename OutputIter> 00933 inline void receive_packed_range (const unsigned int src_processor_id, 00934 Context *context, 00935 OutputIter out, 00936 Request &req, 00937 const MessageTag &tag=any_tag, 00938 const Communicator &comm = Communicator_World) 00939 { comm.receive_packed_range (src_processor_id, context, out, req, tag); } 00940 00941 template <typename T> 00942 inline void nonblocking_receive (const unsigned int src_processor_id, 00943 T &buf, 00944 const DataType &type, 00945 Request &r, 00946 const MessageTag &tag=any_tag, 00947 const Communicator &comm = Communicator_World) 00948 { comm.receive (src_processor_id, buf, type, r, tag); } 00949 00950 template <typename T> 00951 inline void nonblocking_receive (const unsigned int src_processor_id, 00952 T &buf, 00953 Request &r, 00954 const MessageTag &tag=any_tag, 00955 const Communicator &comm = Communicator_World) 00956 { comm.receive (src_processor_id, buf, r, tag); } 00957 00958 template <typename T1, typename T2> 00959 inline void send_receive(const unsigned int dest_processor_id, 00960 T1 &send, 00961 const unsigned int source_processor_id, 00962 T2 &recv, 00963 const MessageTag &send_tag = no_tag, 00964 const MessageTag &recv_tag = any_tag, 00965 const Communicator &comm = Communicator_World) 00966 { comm.send_receive(dest_processor_id, send, source_processor_id, recv, 00967 send_tag, recv_tag); } 00968 00969 template <typename Context1, typename RangeIter, typename Context2, typename OutputIter> 00970 inline void send_receive_packed_range(const unsigned int dest_processor_id, 00971 const Context1* context1, 00972 RangeIter send_begin, 00973 const RangeIter send_end, 00974 const unsigned int source_processor_id, 00975 Context2* context2, 00976 OutputIter out, 00977 const MessageTag &send_tag = no_tag, 00978 const MessageTag &recv_tag = any_tag, 00979 const Communicator &comm = Communicator_World) 00980 { comm.send_receive_packed_range(dest_processor_id, context1, send_begin, send_end, 00981 source_processor_id, context2, out, send_tag, recv_tag); } 00982 00983 template <typename T1, typename T2> 00984 inline void send_receive(const unsigned int dest_processor_id, 00985 T1 &send, 00986 const DataType &type1, 00987 const unsigned int source_processor_id, 00988 T2 &recv, 00989 const DataType &type2, 00990 const MessageTag &send_tag = no_tag, 00991 const MessageTag &recv_tag = any_tag, 00992 const Communicator &comm = Communicator_World) 00993 { comm.send_receive(dest_processor_id, send, type1, source_processor_id, 00994 recv, type2, send_tag, recv_tag); } 00995 00996 template <typename T> 00997 inline void gather(const unsigned int root_id, 00998 T send, 00999 std::vector<T> &recv, 01000 const Communicator &comm = Communicator_World) 01001 { comm.gather(root_id, send, recv); } 01002 01003 template <typename T> 01004 inline void gather(const unsigned int root_id, 01005 std::vector<T> &r, 01006 const Communicator &comm = Communicator_World) 01007 { comm.gather(root_id, r); } 01008 01009 template <typename T> 01010 inline void allgather(T send, 01011 std::vector<T> &recv, 01012 const Communicator &comm = Communicator_World) 01013 { comm.allgather(send, recv); } 01014 01015 template <typename T> 01016 inline void allgather(std::vector<T> &r, 01017 const bool identical_buffer_sizes = false, 01018 const Communicator &comm = Communicator_World) 01019 { comm.allgather(r, identical_buffer_sizes); } 01020 01021 template <typename Context, typename Iter, typename OutputIter> 01022 inline void allgather_packed_range (Context *context, 01023 Iter range_begin, 01024 const Iter range_end, 01025 OutputIter out, 01026 const Communicator &comm = Communicator_World) 01027 { comm.allgather_packed_range(context, range_begin, range_end, out); } 01028 01029 template <typename T> 01030 inline void alltoall(std::vector<T> &r, 01031 const Communicator &comm = Communicator_World) 01032 { comm.alltoall(r); } 01033 01034 template <typename T> 01035 inline void broadcast(T &data, const unsigned int root_id=0, 01036 const Communicator &comm = Communicator_World) 01037 { comm.broadcast(data, root_id); } 01038 01039 template <typename Context, typename OutputContext, typename Iter, typename OutputIter> 01040 inline void broadcast_packed_range (const Context *context1, 01041 Iter range_begin, 01042 const Iter range_end, 01043 OutputContext *context2, 01044 OutputIter out, 01045 const unsigned int root_id = 0, 01046 const Communicator &comm = Communicator_World) 01047 { comm.broadcast_packed_range(context1, range_begin, range_end, context2, out, root_id); } 01048 01049 01050 //----------------------------------------------------------------------- 01051 // Parallel members 01052 01053 inline 01054 MessageTag::~MessageTag() 01055 { 01056 if (_comm) 01057 _comm->dereference_unique_tag(_tagvalue); 01058 } 01059 01060 01061 inline 01062 MessageTag::MessageTag(const MessageTag &other) 01063 : _tagvalue(other._tagvalue), _comm(other._comm) 01064 { 01065 if (_comm) 01066 _comm->reference_unique_tag(_tagvalue); 01067 } 01068 01069 01070 inline 01071 MessageTag Communicator::get_unique_tag(int tagvalue) const 01072 { 01073 if (used_tag_values.count(tagvalue)) 01074 { 01075 // Get the largest value in the used values, and pick one 01076 // larger 01077 tagvalue = used_tag_values.rbegin()->first+1; 01078 libmesh_assert(!used_tag_values.count(tagvalue)); 01079 } 01080 used_tag_values[tagvalue] = 1; 01081 01082 // #ifndef NDEBUG 01083 // // Make sure everyone called get_unique_tag and make sure 01084 // // everyone got the same value 01085 // int maxval = tagvalue; 01086 // this->max(maxval); 01087 // libmesh_assert_equal_to (tagvalue, maxval); 01088 // #endif 01089 01090 return MessageTag(tagvalue, this); 01091 } 01092 01093 01094 inline 01095 void Communicator::reference_unique_tag(int tagvalue) const 01096 { 01097 // This has better be an already-acquired tag. 01098 libmesh_assert(used_tag_values.count(tagvalue)); 01099 01100 used_tag_values[tagvalue]++; 01101 } 01102 01103 01104 inline 01105 void Communicator::dereference_unique_tag(int tagvalue) const 01106 { 01107 // This has better be an already-acquired tag. 01108 libmesh_assert(used_tag_values.count(tagvalue)); 01109 01110 used_tag_values[tagvalue]--; 01111 // If we don't have any more outstanding references, we 01112 // don't even need to keep this tag in our "used" set. 01113 if (!used_tag_values[tagvalue]) 01114 used_tag_values.erase(tagvalue); 01115 } 01116 01117 01118 #ifdef LIBMESH_HAVE_MPI 01119 template<> 01120 inline data_type dataplusint_type<short int>() { return MPI_SHORT_INT; } 01121 01122 template<> 01123 inline data_type dataplusint_type<int>() { return MPI_2INT; } 01124 01125 template<> 01126 inline data_type dataplusint_type<long>() { return MPI_LONG_INT; } 01127 01128 template<> 01129 inline data_type dataplusint_type<float>() { return MPI_FLOAT_INT; } 01130 01131 template<> 01132 inline data_type dataplusint_type<double>() { return MPI_DOUBLE_INT; } 01133 01134 template<> 01135 inline data_type dataplusint_type<long double>() { return MPI_LONG_DOUBLE_INT; } 01136 01137 template <typename T> 01138 inline bool Communicator::verify(const T &r) const 01139 { 01140 if (this->size() > 1 && Attributes<T>::has_min_max == true) 01141 { 01142 T tempmin = r, tempmax = r; 01143 this->min(tempmin); 01144 this->max(tempmax); 01145 bool verified = (r == tempmin) && 01146 (r == tempmax); 01147 this->min(verified); 01148 return verified; 01149 } 01150 return true; 01151 } 01152 01153 01154 01155 template <typename T> 01156 inline bool Communicator::semiverify(const T *r) const 01157 { 01158 if (this->size() > 1 && Attributes<T>::has_min_max == true) 01159 { 01160 T tempmin, tempmax; 01161 if (r) 01162 tempmin = tempmax = *r; 01163 else 01164 { 01165 Attributes<T>::set_highest(tempmin); 01166 Attributes<T>::set_lowest(tempmax); 01167 } 01168 this->min(tempmin); 01169 this->max(tempmax); 01170 bool invalid = r && ((*r != tempmin) && 01171 (*r != tempmax)); 01172 this->max(invalid); 01173 return !invalid; 01174 } 01175 return true; 01176 } 01177 01178 01179 01180 template <typename T> 01181 inline bool Communicator::semiverify(const std::vector<T> *r) const 01182 { 01183 if (this->size() > 1 && Attributes<T>::has_min_max == true) 01184 { 01185 std::size_t rsize = r ? r->size() : 0; 01186 std::size_t *psize = r ? &rsize : NULL; 01187 01188 if (!this->semiverify(psize)) 01189 return false; 01190 01191 this->max(rsize); 01192 01193 std::vector<T> tempmin, tempmax; 01194 if (r) 01195 { 01196 tempmin = tempmax = *r; 01197 } 01198 else 01199 { 01200 tempmin.resize(rsize); 01201 tempmax.resize(rsize); 01202 Attributes<std::vector<T> >::set_highest(tempmin); 01203 Attributes<std::vector<T> >::set_lowest(tempmax); 01204 } 01205 this->min(tempmin); 01206 this->max(tempmax); 01207 bool invalid = r && ((*r != tempmin) && 01208 (*r != tempmax)); 01209 this->max(invalid); 01210 return !invalid; 01211 } 01212 return true; 01213 } 01214 01215 01216 01217 inline bool Communicator::verify(const std::string & r) const 01218 { 01219 if (this->size() > 1) 01220 { 01221 // Cannot use <char> since MPI_MIN is not 01222 // strictly defined for chars! 01223 std::vector<short int> temp; temp.reserve(r.size()); 01224 for (std::size_t i=0; i != r.size(); ++i) 01225 temp.push_back(r[i]); 01226 return this->verify(temp); 01227 } 01228 return true; 01229 } 01230 01231 01232 01233 inline bool Communicator::semiverify(const std::string * r) const 01234 { 01235 if (this->size() > 1) 01236 { 01237 std::size_t rsize = r ? r->size() : 0; 01238 std::size_t *psize = r ? &rsize : NULL; 01239 01240 if (!this->semiverify(psize)) 01241 return false; 01242 01243 this->max(rsize); 01244 01245 // Cannot use <char> since MPI_MIN is not 01246 // strictly defined for chars! 01247 std::vector<short int> temp (rsize); 01248 if (r) 01249 { 01250 temp.reserve(rsize); 01251 for (std::size_t i=0; i != rsize; ++i) 01252 temp.push_back((*r)[i]); 01253 } 01254 01255 std::vector<short int> *ptemp = r ? &temp: NULL; 01256 01257 return this->semiverify(ptemp); 01258 } 01259 return true; 01260 } 01261 01262 01263 01264 template <typename T> 01265 inline void Communicator::min(T &r) const 01266 { 01267 if (this->size() > 1) 01268 { 01269 START_LOG("min(scalar)", "Parallel"); 01270 01271 T temp = r; 01272 MPI_Allreduce (&temp, 01273 &r, 01274 1, 01275 StandardType<T>(&temp), 01276 MPI_MIN, 01277 this->get()); 01278 01279 STOP_LOG("min(scalar)", "Parallel"); 01280 } 01281 } 01282 01283 01284 inline void Communicator::min(bool &r) const 01285 { 01286 if (this->size() > 1) 01287 { 01288 START_LOG("min(bool)", "Parallel"); 01289 01290 unsigned int tempsend = r; 01291 unsigned int temp; 01292 MPI_Allreduce (&tempsend, 01293 &temp, 01294 1, 01295 StandardType<unsigned int>(), 01296 MPI_MIN, 01297 this->get()); 01298 r = temp; 01299 01300 STOP_LOG("min(bool)", "Parallel"); 01301 } 01302 } 01303 01304 01305 template <typename T> 01306 inline void Communicator::min(std::vector<T> &r) const 01307 { 01308 if (this->size() > 1 && !r.empty()) 01309 { 01310 START_LOG("min(vector)", "Parallel"); 01311 01312 libmesh_assert(this->verify(r.size())); 01313 01314 std::vector<T> temp(r); 01315 MPI_Allreduce (&temp[0], 01316 &r[0], 01317 libmesh_cast_int<int>(r.size()), 01318 StandardType<T>(&temp[0]), 01319 MPI_MIN, 01320 this->get()); 01321 01322 STOP_LOG("min(vector)", "Parallel"); 01323 } 01324 } 01325 01326 01327 inline void Communicator::min(std::vector<bool> &r) const 01328 { 01329 if (this->size() > 1 && !r.empty()) 01330 { 01331 START_LOG("min(vector<bool>)", "Parallel"); 01332 01333 libmesh_assert(this->verify(r.size())); 01334 01335 std::vector<unsigned int> ruint; 01336 pack_vector_bool(r, ruint); 01337 std::vector<unsigned int> temp(ruint.size()); 01338 MPI_Allreduce (&ruint[0], 01339 &temp[0], 01340 libmesh_cast_int<int>(ruint.size()), 01341 StandardType<unsigned int>(), 01342 MPI_BAND, 01343 this->get()); 01344 unpack_vector_bool(temp, r); 01345 01346 STOP_LOG("min(vector<bool>)", "Parallel"); 01347 } 01348 } 01349 01350 01351 template <typename T> 01352 inline void Communicator::minloc(T &r, 01353 unsigned int &min_id) const 01354 { 01355 if (this->size() > 1) 01356 { 01357 START_LOG("minloc(scalar)", "Parallel"); 01358 01359 DataPlusInt<T> in; 01360 in.val = r; 01361 in.rank = this->rank(); 01362 DataPlusInt<T> out; 01363 MPI_Allreduce (&in, 01364 &out, 01365 1, 01366 dataplusint_type<T>(), 01367 MPI_MINLOC, 01368 this->get()); 01369 r = out.val; 01370 min_id = out.rank; 01371 01372 STOP_LOG("minloc(scalar)", "Parallel"); 01373 } 01374 else 01375 min_id = this->rank(); 01376 } 01377 01378 01379 inline void Communicator::minloc(bool &r, 01380 unsigned int &min_id) const 01381 { 01382 if (this->size() > 1) 01383 { 01384 START_LOG("minloc(bool)", "Parallel"); 01385 01386 DataPlusInt<int> in; 01387 in.val = r; 01388 in.rank = this->rank(); 01389 DataPlusInt<int> out; 01390 MPI_Allreduce (&in, 01391 &out, 01392 1, 01393 dataplusint_type<int>(), 01394 MPI_MINLOC, 01395 this->get()); 01396 r = out.val; 01397 min_id = out.rank; 01398 01399 STOP_LOG("minloc(bool)", "Parallel"); 01400 } 01401 else 01402 min_id = this->rank(); 01403 } 01404 01405 01406 template <typename T> 01407 inline void Communicator::minloc(std::vector<T> &r, 01408 std::vector<unsigned int> &min_id) const 01409 { 01410 if (this->size() > 1 && !r.empty()) 01411 { 01412 START_LOG("minloc(vector)", "Parallel"); 01413 01414 libmesh_assert(this->verify(r.size())); 01415 01416 std::vector<DataPlusInt<T> > in(r.size()); 01417 for (std::size_t i=0; i != r.size(); ++i) 01418 { 01419 in[i].val = r[i]; 01420 in[i].rank = this->rank(); 01421 } 01422 std::vector<DataPlusInt<T> > out(r.size()); 01423 MPI_Allreduce (&in[0], 01424 &out[0], 01425 libmesh_cast_int<int>(r.size()), 01426 dataplusint_type<T>(), 01427 MPI_MINLOC, 01428 this->get()); 01429 for (std::size_t i=0; i != r.size(); ++i) 01430 { 01431 r[i] = out[i].val; 01432 min_id[i] = out[i].rank; 01433 } 01434 01435 STOP_LOG("minloc(vector)", "Parallel"); 01436 } 01437 else if (!r.empty()) 01438 { 01439 for (std::size_t i=0; i != r.size(); ++i) 01440 min_id[i] = this->rank(); 01441 } 01442 } 01443 01444 01445 inline void Communicator::minloc(std::vector<bool> &r, 01446 std::vector<unsigned int> &min_id) const 01447 { 01448 if (this->size() > 1 && !r.empty()) 01449 { 01450 START_LOG("minloc(vector<bool>)", "Parallel"); 01451 01452 libmesh_assert(this->verify(r.size())); 01453 01454 std::vector<DataPlusInt<int> > in(r.size()); 01455 for (std::size_t i=0; i != r.size(); ++i) 01456 { 01457 in[i].val = r[i]; 01458 in[i].rank = this->rank(); 01459 } 01460 std::vector<DataPlusInt<int> > out(r.size()); 01461 MPI_Allreduce (&in[0], 01462 &out[0], 01463 libmesh_cast_int<int>(r.size()), 01464 StandardType<int>(), 01465 MPI_MINLOC, 01466 this->get()); 01467 for (std::size_t i=0; i != r.size(); ++i) 01468 { 01469 r[i] = out[i].val; 01470 min_id[i] = out[i].rank; 01471 } 01472 01473 STOP_LOG("minloc(vector<bool>)", "Parallel"); 01474 } 01475 else if (!r.empty()) 01476 { 01477 for (std::size_t i=0; i != r.size(); ++i) 01478 min_id[i] = this->rank(); 01479 } 01480 } 01481 01482 01483 template <typename T> 01484 inline void Communicator::max(T &r) const 01485 { 01486 if (this->size() > 1) 01487 { 01488 START_LOG("max(scalar)", "Parallel"); 01489 01490 T temp; 01491 MPI_Allreduce (&r, 01492 &temp, 01493 1, 01494 StandardType<T>(&r), 01495 MPI_MAX, 01496 this->get()); 01497 r = temp; 01498 01499 STOP_LOG("max(scalar)", "Parallel"); 01500 } 01501 } 01502 01503 01504 inline void Communicator::max(bool &r) const 01505 { 01506 if (this->size() > 1) 01507 { 01508 START_LOG("max(bool)", "Parallel"); 01509 01510 unsigned int tempsend = r; 01511 unsigned int temp; 01512 MPI_Allreduce (&tempsend, 01513 &temp, 01514 1, 01515 StandardType<unsigned int>(), 01516 MPI_MAX, 01517 this->get()); 01518 r = temp; 01519 01520 STOP_LOG("max(bool)", "Parallel"); 01521 } 01522 } 01523 01524 01525 template <typename T> 01526 inline void Communicator::max(std::vector<T> &r) const 01527 { 01528 if (this->size() > 1 && !r.empty()) 01529 { 01530 START_LOG("max(vector)", "Parallel"); 01531 01532 libmesh_assert(this->verify(r.size())); 01533 01534 std::vector<T> temp(r); 01535 MPI_Allreduce (&temp[0], 01536 &r[0], 01537 libmesh_cast_int<int>(r.size()), 01538 StandardType<T>(&temp[0]), 01539 MPI_MAX, 01540 this->get()); 01541 01542 STOP_LOG("max(vector)", "Parallel"); 01543 } 01544 } 01545 01546 01547 inline void Communicator::max(std::vector<bool> &r) const 01548 { 01549 if (this->size() > 1 && !r.empty()) 01550 { 01551 START_LOG("max(vector<bool>)", "Parallel"); 01552 01553 libmesh_assert(this->verify(r.size())); 01554 01555 std::vector<unsigned int> ruint; 01556 pack_vector_bool(r, ruint); 01557 std::vector<unsigned int> temp(ruint.size()); 01558 MPI_Allreduce (&ruint[0], 01559 &temp[0], 01560 libmesh_cast_int<int>(ruint.size()), 01561 StandardType<unsigned int>(), 01562 MPI_BOR, 01563 this->get()); 01564 unpack_vector_bool(temp, r); 01565 01566 STOP_LOG("max(vector<bool>)", "Parallel"); 01567 } 01568 } 01569 01570 01571 template <typename T> 01572 inline void Communicator::maxloc(T &r, 01573 unsigned int &max_id) const 01574 { 01575 if (this->size() > 1) 01576 { 01577 START_LOG("maxloc(scalar)", "Parallel"); 01578 01579 DataPlusInt<T> in; 01580 in.val = r; 01581 in.rank = this->rank(); 01582 DataPlusInt<T> out; 01583 MPI_Allreduce (&in, 01584 &out, 01585 1, 01586 dataplusint_type<T>(), 01587 MPI_MAXLOC, 01588 this->get()); 01589 r = out.val; 01590 max_id = out.rank; 01591 01592 STOP_LOG("maxloc(scalar)", "Parallel"); 01593 } 01594 else 01595 max_id = this->rank(); 01596 } 01597 01598 01599 inline void Communicator::maxloc(bool &r, 01600 unsigned int &max_id) const 01601 { 01602 if (this->size() > 1) 01603 { 01604 START_LOG("maxloc(bool)", "Parallel"); 01605 01606 DataPlusInt<int> in; 01607 in.val = r; 01608 in.rank = this->rank(); 01609 DataPlusInt<int> out; 01610 MPI_Allreduce (&in, 01611 &out, 01612 1, 01613 dataplusint_type<int>(), 01614 MPI_MAXLOC, 01615 this->get()); 01616 r = out.val; 01617 max_id = out.rank; 01618 01619 STOP_LOG("maxloc(bool)", "Parallel"); 01620 } 01621 else 01622 max_id = this->rank(); 01623 } 01624 01625 01626 template <typename T> 01627 inline void Communicator::maxloc(std::vector<T> &r, 01628 std::vector<unsigned int> &max_id) const 01629 { 01630 if (this->size() > 1 && !r.empty()) 01631 { 01632 START_LOG("maxloc(vector)", "Parallel"); 01633 01634 libmesh_assert(this->verify(r.size())); 01635 01636 std::vector<DataPlusInt<T> > in(r.size()); 01637 for (std::size_t i=0; i != r.size(); ++i) 01638 { 01639 in[i].val = r[i]; 01640 in[i].rank = this->rank(); 01641 } 01642 std::vector<DataPlusInt<T> > out(r.size()); 01643 MPI_Allreduce (&in[0], 01644 &out[0], 01645 libmesh_cast_int<int>(r.size()), 01646 dataplusint_type<T>(), 01647 MPI_MAXLOC, 01648 this->get()); 01649 for (std::size_t i=0; i != r.size(); ++i) 01650 { 01651 r[i] = out[i].val; 01652 max_id[i] = out[i].rank; 01653 } 01654 01655 STOP_LOG("maxloc(vector)", "Parallel"); 01656 } 01657 else if (!r.empty()) 01658 { 01659 for (std::size_t i=0; i != r.size(); ++i) 01660 max_id[i] = this->rank(); 01661 } 01662 } 01663 01664 01665 inline void Communicator::maxloc(std::vector<bool> &r, 01666 std::vector<unsigned int> &max_id) const 01667 { 01668 if (this->size() > 1 && !r.empty()) 01669 { 01670 START_LOG("maxloc(vector<bool>)", "Parallel"); 01671 01672 libmesh_assert(this->verify(r.size())); 01673 01674 std::vector<DataPlusInt<int> > in(r.size()); 01675 for (std::size_t i=0; i != r.size(); ++i) 01676 { 01677 in[i].val = r[i]; 01678 in[i].rank = this->rank(); 01679 } 01680 std::vector<DataPlusInt<int> > out(r.size()); 01681 MPI_Allreduce (&in[0], 01682 &out[0], 01683 libmesh_cast_int<int>(r.size()), 01684 StandardType<int>(), 01685 MPI_MAXLOC, 01686 this->get()); 01687 for (std::size_t i=0; i != r.size(); ++i) 01688 { 01689 r[i] = out[i].val; 01690 max_id[i] = out[i].rank; 01691 } 01692 01693 STOP_LOG("maxloc(vector<bool>)", "Parallel"); 01694 } 01695 else if (!r.empty()) 01696 { 01697 for (std::size_t i=0; i != r.size(); ++i) 01698 max_id[i] = this->rank(); 01699 } 01700 } 01701 01702 01703 template <typename T> 01704 inline void Communicator::sum(T &r) const 01705 { 01706 if (this->size() > 1) 01707 { 01708 START_LOG("sum()", "Parallel"); 01709 01710 T temp = r; 01711 MPI_Allreduce (&temp, 01712 &r, 01713 1, 01714 StandardType<T>(&temp), 01715 MPI_SUM, 01716 this->get()); 01717 01718 STOP_LOG("sum()", "Parallel"); 01719 } 01720 } 01721 01722 01723 template <typename T> 01724 inline void Communicator::sum(std::vector<T> &r) const 01725 { 01726 if (this->size() > 1 && !r.empty()) 01727 { 01728 START_LOG("sum()", "Parallel"); 01729 01730 libmesh_assert(this->verify(r.size())); 01731 01732 std::vector<T> temp(r); 01733 MPI_Allreduce (&temp[0], 01734 &r[0], 01735 libmesh_cast_int<int>(r.size()), 01736 StandardType<T>(&temp[0]), 01737 MPI_SUM, 01738 this->get()); 01739 01740 STOP_LOG("sum()", "Parallel"); 01741 } 01742 } 01743 01744 01745 // We still do function overloading for complex sums - in a perfect 01746 // world we'd have a StandardSumOp to go along with StandardType... 01747 template <typename T> 01748 inline void Communicator::sum(std::complex<T> &r) const 01749 { 01750 if (this->size() > 1) 01751 { 01752 START_LOG("sum()", "Parallel"); 01753 01754 std::complex<T> temp(r); 01755 MPI_Allreduce (&temp, 01756 &r, 01757 2, 01758 StandardType<T>(), 01759 MPI_SUM, 01760 this->get()); 01761 01762 STOP_LOG("sum()", "Parallel"); 01763 } 01764 } 01765 01766 01767 template <typename T> 01768 inline void Communicator::sum(std::vector<std::complex<T> > &r) const 01769 { 01770 if (this->size() > 1 && !r.empty()) 01771 { 01772 START_LOG("sum()", "Parallel"); 01773 01774 libmesh_assert(this->verify(r.size())); 01775 01776 std::vector<std::complex<T> > temp(r); 01777 MPI_Allreduce (&temp[0], 01778 &r[0], 01779 libmesh_cast_int<int>(r.size() * 2), 01780 StandardType<T>(NULL), 01781 MPI_SUM, 01782 this->get()); 01783 01784 STOP_LOG("sum()", "Parallel"); 01785 } 01786 } 01787 01788 01789 template <typename T> 01790 inline void Communicator::set_union(std::set<T> &data, 01791 const unsigned int root_id) const 01792 { 01793 std::vector<T> vecdata(data.begin(), data.end()); 01794 this->gather(root_id, vecdata); 01795 if (this->rank() == root_id) 01796 data.insert(vecdata.begin(), vecdata.end()); 01797 } 01798 01799 01800 01801 template <typename T> 01802 inline void Communicator::set_union(std::set<T> &data) const 01803 { 01804 std::vector<T> vecdata(data.begin(), data.end()); 01805 this->allgather(vecdata, false); 01806 data.insert(vecdata.begin(), vecdata.end()); 01807 } 01808 01809 01810 01811 template <typename T1, typename T2> 01812 inline void Communicator::set_union(std::map<T1,T2> &data, 01813 const unsigned int root_id) const 01814 { 01815 std::vector<std::pair<T1,T2> > vecdata(data.begin(), data.end()); 01816 this->gather(root_id, vecdata); 01817 if (this->rank() == root_id) 01818 data.insert(vecdata.begin(), vecdata.end()); 01819 } 01820 01821 01822 01823 template <typename T1, typename T2> 01824 inline void Communicator::set_union(std::map<T1,T2> &data) const 01825 { 01826 std::vector<std::pair<T1,T2> > vecdata(data.begin(), data.end()); 01827 this->allgather(vecdata, false); 01828 data.insert(vecdata.begin(), vecdata.end()); 01829 } 01830 01831 01832 01833 inline status Communicator::probe (const unsigned int src_processor_id, 01834 const MessageTag &tag) const 01835 { 01836 START_LOG("probe()", "Parallel"); 01837 01838 status stat; 01839 01840 MPI_Probe (src_processor_id, 01841 tag.value(), 01842 this->get(), 01843 &stat); 01844 01845 STOP_LOG("probe()", "Parallel"); 01846 01847 return stat; 01848 } 01849 01850 01851 01852 template<typename T> 01853 inline void Communicator::send (const unsigned int dest_processor_id, 01854 std::basic_string<T> &buf, 01855 const MessageTag &tag) const 01856 { 01857 START_LOG("send()", "Parallel"); 01858 01859 T* dataptr = buf.empty() ? NULL : const_cast<T*>(buf.data()); 01860 01861 #ifndef NDEBUG 01862 // Only catch the return value when asserts are active. 01863 const int ierr = 01864 #endif 01865 MPI_Send (dataptr, 01866 libmesh_cast_int<int>(buf.size()), 01867 StandardType<T>(dataptr), 01868 dest_processor_id, 01869 tag.value(), 01870 this->get()); 01871 01872 libmesh_assert (ierr == MPI_SUCCESS); 01873 01874 STOP_LOG("send()", "Parallel"); 01875 } 01876 01877 01878 01879 template <typename T> 01880 inline void Communicator::send (const unsigned int dest_processor_id, 01881 std::basic_string<T> &buf, 01882 Request &req, 01883 const MessageTag &tag) const 01884 { 01885 START_LOG("send()", "Parallel"); 01886 01887 T* dataptr = buf.empty() ? NULL : const_cast<T*>(buf.data()); 01888 01889 #ifndef NDEBUG 01890 // Only catch the return value when asserts are active. 01891 const int ierr = 01892 #endif 01893 MPI_Isend (dataptr, 01894 libmesh_cast_int<int>(buf.size()), 01895 StandardType<T>(dataptr), 01896 dest_processor_id, 01897 tag.value(), 01898 this->get(), 01899 req.get()); 01900 libmesh_assert (ierr == MPI_SUCCESS); 01901 01902 STOP_LOG("send()", "Parallel"); 01903 } 01904 01905 01906 01907 template <typename T> 01908 inline void Communicator::send (const unsigned int dest_processor_id, 01909 std::set<T> &buf, 01910 const MessageTag &tag) const 01911 { 01912 this->send(dest_processor_id, 01913 StandardType<T>(buf.empty() ? NULL : &buf.front()), tag); 01914 } 01915 01916 01917 01918 template <typename T> 01919 inline void Communicator::send (const unsigned int dest_processor_id, 01920 std::set<T> &buf, 01921 Request &req, 01922 const MessageTag &tag) const 01923 { 01924 this->send(dest_processor_id, 01925 StandardType<T>(buf.empty() ? NULL : &buf.front()), req, tag); 01926 } 01927 01928 01929 01930 template <typename T> 01931 inline void Communicator::send (const unsigned int dest_processor_id, 01932 std::set<T> &buf, 01933 const DataType &type, 01934 const MessageTag &tag) const 01935 { 01936 START_LOG("send()", "Parallel"); 01937 01938 std::vector<T> vecbuf(buf.begin(), buf.end()); 01939 this->send(dest_processor_id, vecbuf, type, tag); 01940 01941 STOP_LOG("send()", "Parallel"); 01942 } 01943 01944 01945 01946 template <typename T> 01947 inline void Communicator::send (const unsigned int dest_processor_id, 01948 std::set<T> &buf, 01949 const DataType &type, 01950 Request &req, 01951 const MessageTag &tag) const 01952 { 01953 START_LOG("send()", "Parallel"); 01954 01955 // Allocate temporary buffer on the heap so it lives until after 01956 // the non-blocking send completes 01957 std::vector<T> *vecbuf = 01958 new std::vector<T>(buf.begin(), buf.end()); 01959 01960 // Make the Request::wait() handle deleting the buffer 01961 req.add_post_wait_work 01962 (new Parallel::PostWaitDeleteBuffer<std::vector<T> >(vecbuf)); 01963 01964 this->send(dest_processor_id, *vecbuf, type, req, tag); 01965 01966 STOP_LOG("send()", "Parallel"); 01967 } 01968 01969 01970 01971 template <typename T> 01972 inline void Communicator::send (const unsigned int dest_processor_id, 01973 std::vector<T> &buf, 01974 const MessageTag &tag) const 01975 { 01976 this->send(dest_processor_id, buf, 01977 StandardType<T>(buf.empty() ? NULL : &buf.front()), tag); 01978 } 01979 01980 01981 01982 template <typename T> 01983 inline void Communicator::send (const unsigned int dest_processor_id, 01984 std::vector<T> &buf, 01985 Request &req, 01986 const MessageTag &tag) const 01987 { 01988 this->send(dest_processor_id, buf, 01989 StandardType<T>(buf.empty() ? NULL : &buf.front()), req, tag); 01990 } 01991 01992 01993 01994 template <typename T> 01995 inline void Communicator::send (const unsigned int dest_processor_id, 01996 std::vector<T> &buf, 01997 const DataType &type, 01998 const MessageTag &tag) const 01999 { 02000 START_LOG("send()", "Parallel"); 02001 02002 #ifndef NDEBUG 02003 // Only catch the return value when asserts are active. 02004 const int ierr = 02005 #endif 02006 MPI_Send (buf.empty() ? NULL : &buf[0], 02007 libmesh_cast_int<int>(buf.size()), 02008 type, 02009 dest_processor_id, 02010 tag.value(), 02011 this->get()); 02012 02013 libmesh_assert (ierr == MPI_SUCCESS); 02014 02015 STOP_LOG("send()", "Parallel"); 02016 } 02017 02018 02019 02020 template <typename T> 02021 inline void Communicator::send (const unsigned int dest_processor_id, 02022 std::vector<T> &buf, 02023 const DataType &type, 02024 Request &req, 02025 const MessageTag &tag) const 02026 { 02027 START_LOG("send()", "Parallel"); 02028 02029 #ifndef NDEBUG 02030 // Only catch the return value when asserts are active. 02031 const int ierr = 02032 #endif 02033 MPI_Isend (buf.empty() ? NULL : &buf[0], 02034 libmesh_cast_int<int>(buf.size()), 02035 type, 02036 dest_processor_id, 02037 tag.value(), 02038 this->get(), 02039 req.get()); 02040 libmesh_assert (ierr == MPI_SUCCESS); 02041 02042 STOP_LOG("send()", "Parallel"); 02043 } 02044 02045 02046 template <typename Context, typename Iter> 02047 inline void Communicator::send_packed_range (const unsigned int dest_processor_id, 02048 const Context *context, 02049 Iter range_begin, 02050 const Iter range_end, 02051 const MessageTag &tag) const 02052 { 02053 // We will serialize variable size objects from *range_begin to 02054 // *range_end as a sequence of ints in this buffer 02055 std::vector<int> buffer; 02056 02057 Parallel::pack_range(context, range_begin, range_end, buffer); 02058 02059 // Blocking send of the buffer 02060 this->send(dest_processor_id, buffer, tag); 02061 } 02062 02063 02064 template <typename Context, typename Iter> 02065 inline void Communicator::send_packed_range (const unsigned int dest_processor_id, 02066 const Context *context, 02067 Iter range_begin, 02068 const Iter range_end, 02069 Request &req, 02070 const MessageTag &tag) const 02071 { 02072 // Allocate a buffer on the heap so we don't have to free it until 02073 // after the Request::wait() 02074 std::vector<int> *buffer = new std::vector<int>(); 02075 02076 Parallel::pack_range(context, range_begin, range_end, *buffer); 02077 02078 // Make the Request::wait() handle deleting the buffer 02079 req.add_post_wait_work 02080 (new Parallel::PostWaitDeleteBuffer<std::vector<int> >(buffer)); 02081 02082 // Non-blocking send of the buffer 02083 this->send(dest_processor_id, *buffer, req, tag); 02084 } 02085 02086 02087 02088 template <typename T> 02089 inline Status Communicator::receive (const unsigned int src_processor_id, 02090 std::basic_string<T> &buf, 02091 const MessageTag &tag) const 02092 { 02093 std::vector<T> tempbuf; // Officially C++ won't let us get a 02094 // modifiable array from a string 02095 02096 Status stat = this->receive(src_processor_id, tempbuf, tag); 02097 buf.assign(tempbuf.begin(), tempbuf.end()); 02098 return stat; 02099 } 02100 02101 02102 02103 template <typename T> 02104 inline void Communicator::receive (const unsigned int src_processor_id, 02105 std::basic_string<T> &buf, 02106 Request &req, 02107 const MessageTag &tag) const 02108 { 02109 // Officially C++ won't let us get a modifiable array from a 02110 // string, and we can't even put one on the stack for the 02111 // non-blocking case. 02112 std::vector<T> *tempbuf = new std::vector<T>(); 02113 02114 // We can clear the string, but the Request::wait() will need to 02115 // handle copying our temporary buffer to it 02116 buf.clear(); 02117 02118 req.add_post_wait_work 02119 (new Parallel::PostWaitCopyBuffer<std::vector<T>, 02120 std::back_insert_iterator<std::basic_string<T> > > 02121 (tempbuf, std::back_inserter(buf))); 02122 02123 // Make the Request::wait() then handle deleting the buffer 02124 req.add_post_wait_work 02125 (new Parallel::PostWaitDeleteBuffer<std::vector<T> >(tempbuf)); 02126 02127 this->receive(src_processor_id, tempbuf, req, tag); 02128 } 02129 02130 02131 02132 template <typename T> 02133 inline Status Communicator::receive (const unsigned int src_processor_id, 02134 std::set<T> &buf, 02135 const MessageTag &tag) const 02136 { 02137 return this->receive 02138 (src_processor_id, buf, 02139 StandardType<T>(buf.empty() ? NULL : &buf.front()), tag); 02140 } 02141 02142 02143 02144 template <typename T> 02145 inline void Communicator::receive (const unsigned int src_processor_id, 02146 std::set<T> &buf, 02147 Request &req, 02148 const MessageTag &tag) const 02149 { 02150 this->receive (src_processor_id, buf, 02151 StandardType<T>(buf.empty() ? NULL : &buf.front()), req, tag); 02152 } 02153 02154 02155 02156 template <typename T> 02157 inline Status Communicator::receive (const unsigned int src_processor_id, 02158 std::set<T> &buf, 02159 const DataType &type, 02160 const MessageTag &tag) const 02161 { 02162 START_LOG("receive()", "Parallel"); 02163 02164 std::vector<T> vecbuf; 02165 Status stat = this->receive(src_processor_id, vecbuf, type, tag); 02166 buf.clear(); 02167 buf.insert(vecbuf.begin(), vecbuf.end()); 02168 02169 STOP_LOG("receive()", "Parallel"); 02170 02171 return stat; 02172 } 02173 02174 02175 02176 template <typename T> 02177 inline void Communicator::receive (const unsigned int src_processor_id, 02178 std::set<T> &buf, 02179 const DataType &type, 02180 Request &req, 02181 const MessageTag &tag) const 02182 { 02183 START_LOG("receive()", "Parallel"); 02184 02185 // Allocate temporary buffer on the heap so it lives until after 02186 // the non-blocking send completes 02187 std::vector<T> *vecbuf = new std::vector<T>(); 02188 02189 // We can clear the set, but the Request::wait() will need to 02190 // handle copying our temporary buffer to it 02191 buf.clear(); 02192 02193 req.add_post_wait_work 02194 (new Parallel::PostWaitCopyBuffer<std::vector<T>, 02195 std::back_insert_iterator<std::set<T> > > 02196 (vecbuf, std::back_inserter(buf))); 02197 02198 // Make the Request::wait() then handle deleting the buffer 02199 req.add_post_wait_work 02200 (new Parallel::PostWaitDeleteBuffer<std::vector<T> >(vecbuf)); 02201 02202 this->receive(src_processor_id, *vecbuf, type, req, tag); 02203 02204 STOP_LOG("receive()", "Parallel"); 02205 } 02206 02207 02208 02209 template <typename T> 02210 inline Status Communicator::receive (const unsigned int src_processor_id, 02211 std::vector<T> &buf, 02212 const MessageTag &tag) const 02213 { 02214 return this->receive 02215 (src_processor_id, buf, 02216 StandardType<T>(buf.empty() ? NULL : &buf.front()), tag); 02217 } 02218 02219 02220 02221 template <typename T> 02222 inline void Communicator::receive (const unsigned int src_processor_id, 02223 std::vector<T> &buf, 02224 Request &req, 02225 const MessageTag &tag) const 02226 { 02227 this->receive (src_processor_id, buf, 02228 StandardType<T>(buf.empty() ? NULL : &buf.front()), req, tag); 02229 } 02230 02231 02232 02233 template <typename T> 02234 inline Status Communicator::receive (const unsigned int src_processor_id, 02235 std::vector<T> &buf, 02236 const DataType &type, 02237 const MessageTag &tag) const 02238 { 02239 START_LOG("receive()", "Parallel"); 02240 02241 // Get the status of the message, explicitly provide the 02242 // datatype so we can later query the size 02243 Status stat(this->probe(src_processor_id, tag), type); 02244 02245 buf.resize(stat.size()); 02246 02247 #ifndef NDEBUG 02248 // Only catch the return value when asserts are active. 02249 const int ierr = 02250 #endif 02251 MPI_Recv (buf.empty() ? NULL : &buf[0], 02252 libmesh_cast_int<int>(buf.size()), 02253 type, 02254 src_processor_id, 02255 tag.value(), 02256 this->get(), 02257 stat.get()); 02258 libmesh_assert (ierr == MPI_SUCCESS); 02259 02260 STOP_LOG("receive()", "Parallel"); 02261 02262 return stat; 02263 } 02264 02265 02266 02267 template <typename T> 02268 inline void Communicator::receive (const unsigned int src_processor_id, 02269 std::vector<T> &buf, 02270 const DataType &type, 02271 Request &req, 02272 const MessageTag &tag) const 02273 { 02274 START_LOG("receive()", "Parallel"); 02275 02276 #ifndef NDEBUG 02277 // Only catch the return value when asserts are active. 02278 const int ierr = 02279 #endif 02280 MPI_Irecv (buf.empty() ? NULL : &buf[0], 02281 libmesh_cast_int<int>(buf.size()), 02282 type, 02283 src_processor_id, 02284 tag.value(), 02285 this->get(), 02286 req.get()); 02287 libmesh_assert (ierr == MPI_SUCCESS); 02288 02289 STOP_LOG("receive()", "Parallel"); 02290 } 02291 02292 02293 template <typename Context, typename OutputIter> 02294 inline void Communicator::receive_packed_range (const unsigned int src_processor_id, 02295 Context *context, 02296 OutputIter out, 02297 const MessageTag &tag) const 02298 { 02299 // Receive serialized variable size objects as a sequence of ints 02300 std::vector<int> buffer; 02301 this->receive(src_processor_id, buffer, tag); 02302 Parallel::unpack_range(buffer, context, out); 02303 } 02304 02305 02306 02307 template <typename Context, typename OutputIter> 02308 inline void Communicator::receive_packed_range (const unsigned int src_processor_id, 02309 Context *context, 02310 OutputIter out, 02311 Request &req, 02312 const MessageTag &tag) const 02313 { 02314 // Receive serialized variable size objects as a sequence of ints. 02315 // Allocate a buffer on the heap so we don't have to free it until 02316 // after the Request::wait() 02317 std::vector<int> *buffer = new std::vector<int>(); 02318 this->receive(src_processor_id, *buffer, req, tag); 02319 02320 // Make the Request::wait() handle unpacking the buffer 02321 req.add_post_wait_work 02322 (new Parallel::PostWaitUnpackBuffer<std::vector<int>, Context, OutputIter> 02323 (buffer, context, out)); 02324 02325 // Make the Request::wait() then handle deleting the buffer 02326 req.add_post_wait_work 02327 (new Parallel::PostWaitDeleteBuffer<std::vector<int> >(buffer)); 02328 } 02329 02330 02331 02332 template <typename T1, typename T2> 02333 inline void Communicator::send_receive(const unsigned int dest_processor_id, 02334 std::vector<T1> &sendvec, 02335 const DataType &type1, 02336 const unsigned int source_processor_id, 02337 std::vector<T2> &recv, 02338 const DataType &type2, 02339 const MessageTag &send_tag, 02340 const MessageTag &recv_tag) const 02341 { 02342 START_LOG("send_receive()", "Parallel"); 02343 02344 if (dest_processor_id == this->rank() && 02345 source_processor_id == this->rank()) 02346 { 02347 recv = sendvec; 02348 STOP_LOG("send_receive()", "Parallel"); 02349 return; 02350 } 02351 02352 Parallel::Request req; 02353 02354 this->send (dest_processor_id, sendvec, type1, req, send_tag); 02355 02356 this->receive (source_processor_id, recv, type2, recv_tag); 02357 02358 req.wait(); 02359 02360 STOP_LOG("send_receive()", "Parallel"); 02361 } 02362 02363 02364 02365 template <typename T1, typename T2> 02366 inline void Communicator::send_receive(const unsigned int dest_processor_id, 02367 T1 &sendvec, 02368 const unsigned int source_processor_id, 02369 T2 &recv, 02370 const MessageTag &send_tag, 02371 const MessageTag &recv_tag) const 02372 { 02373 START_LOG("send_receive()", "Parallel"); 02374 02375 if (dest_processor_id == this->rank() && 02376 source_processor_id == this->rank()) 02377 { 02378 recv = sendvec; 02379 STOP_LOG("send_receive()", "Parallel"); 02380 return; 02381 } 02382 02383 MPI_Sendrecv(&sendvec, 1, StandardType<T1>(&sendvec), 02384 dest_processor_id, send_tag.value(), 02385 &recv, 1, StandardType<T2>(&recv), 02386 source_processor_id, recv_tag.value(), 02387 this->get(), 02388 MPI_STATUS_IGNORE); 02389 02390 STOP_LOG("send_receive()", "Parallel"); 02391 } 02392 02393 02394 02395 // This is both a declaration and definition for a new overloaded 02396 // function template, so we have to re-specify the default 02397 // arguments. 02398 // 02399 // We specialize on the T1==T2 case so that we can handle 02400 // send_receive-to-self with a plain copy rather than going through 02401 // MPI. 02402 template <typename T> 02403 inline void Communicator::send_receive(const unsigned int dest_processor_id, 02404 std::vector<T> &sendvec, 02405 const unsigned int source_processor_id, 02406 std::vector<T> &recv, 02407 const MessageTag &send_tag, 02408 const MessageTag &recv_tag) const 02409 { 02410 if (dest_processor_id == this->rank() && 02411 source_processor_id == this->rank()) 02412 { 02413 START_LOG("send_receive()", "Parallel"); 02414 recv = sendvec; 02415 STOP_LOG("send_receive()", "Parallel"); 02416 return; 02417 } 02418 02419 // Call the user-defined type version with automatic 02420 // type conversion based on template argument: 02421 this->send_receive (dest_processor_id, sendvec, 02422 StandardType<T>(sendvec.empty() ? NULL : &sendvec[0]), 02423 source_processor_id, recv, 02424 StandardType<T>(recv.empty() ? NULL : &recv[0]), 02425 send_tag, recv_tag); 02426 } 02427 02428 02429 // This is both a declaration and definition for a new overloaded 02430 // function template, so we have to re-specify the default arguments 02431 template <typename T1, typename T2> 02432 inline void Communicator::send_receive(const unsigned int dest_processor_id, 02433 std::vector<T1> &sendvec, 02434 const unsigned int source_processor_id, 02435 std::vector<T2> &recv, 02436 const MessageTag &send_tag, 02437 const MessageTag &recv_tag) const 02438 { 02439 // Call the user-defined type version with automatic 02440 // type conversion based on template argument: 02441 this->send_receive (dest_processor_id, sendvec, 02442 StandardType<T1>(sendvec.empty() ? NULL : &sendvec[0]), 02443 source_processor_id, recv, 02444 StandardType<T2>(recv.empty() ? NULL : &recv[0]), 02445 send_tag, recv_tag); 02446 } 02447 02448 02449 02450 02451 template <typename T1, typename T2> 02452 inline void Communicator::send_receive(const unsigned int dest_processor_id, 02453 std::vector<std::vector<T1> > &sendvec, 02454 const unsigned int source_processor_id, 02455 std::vector<std::vector<T2> > &recv, 02456 const MessageTag & /* send_tag */, 02457 const MessageTag & /* recv_tag */) const 02458 { 02459 // FIXME - why aren't we honoring send_tag and recv_tag here? 02460 send_receive_vec_of_vec 02461 (dest_processor_id, sendvec, source_processor_id, recv, 02462 no_tag, any_tag, *this); 02463 } 02464 02465 02466 02467 // This is both a declaration and definition for a new overloaded 02468 // function template, so we have to re-specify the default arguments 02469 template <typename T> 02470 inline void Communicator::send_receive(const unsigned int dest_processor_id, 02471 std::vector<std::vector<T> > &sendvec, 02472 const unsigned int source_processor_id, 02473 std::vector<std::vector<T> > &recv, 02474 const MessageTag & /* send_tag */, 02475 const MessageTag & /* recv_tag */) const 02476 { 02477 // FIXME - why aren't we honoring send_tag and recv_tag here? 02478 send_receive_vec_of_vec 02479 (dest_processor_id, sendvec, source_processor_id, recv, 02480 no_tag, any_tag, *this); 02481 } 02482 02483 02484 02485 02486 template <typename Context1, typename RangeIter, typename Context2, typename OutputIter> 02487 inline void Communicator::send_receive_packed_range 02488 (const unsigned int dest_processor_id, 02489 const Context1* context1, 02490 RangeIter send_begin, 02491 const RangeIter send_end, 02492 const unsigned int source_processor_id, 02493 Context2* context2, 02494 OutputIter out, 02495 const MessageTag &send_tag, 02496 const MessageTag &recv_tag) const 02497 { 02498 START_LOG("send_receive()", "Parallel"); 02499 02500 Parallel::Request req; 02501 02502 this->send_packed_range (dest_processor_id, context1, send_begin, send_end, 02503 req, send_tag); 02504 02505 this->receive_packed_range (source_processor_id, context2, out, recv_tag); 02506 02507 req.wait(); 02508 02509 STOP_LOG("send_receive()", "Parallel"); 02510 02511 } 02512 02513 02514 02515 template <typename T> 02516 inline void Communicator::gather(const unsigned int root_id, 02517 T sendval, 02518 std::vector<T> &recv) const 02519 { 02520 libmesh_assert_less (root_id, this->size()); 02521 02522 if (this->rank() == root_id) 02523 recv.resize(this->size()); 02524 02525 if (this->size() > 1) 02526 { 02527 START_LOG("gather()", "Parallel"); 02528 02529 StandardType<T> send_type(&sendval); 02530 02531 MPI_Gather(&sendval, 02532 1, 02533 send_type, 02534 recv.empty() ? NULL : &recv[0], 02535 1, 02536 send_type, 02537 root_id, 02538 this->get()); 02539 02540 STOP_LOG("gather()", "Parallel"); 02541 } 02542 else 02543 recv[0] = sendval; 02544 } 02545 02546 02547 02548 template <typename T> 02549 inline void Communicator::gather(const unsigned int root_id, 02550 std::vector<T> &r) const 02551 { 02552 if (this->size() == 1) 02553 { 02554 libmesh_assert (!this->rank()); 02555 libmesh_assert (!root_id); 02556 return; 02557 } 02558 02559 libmesh_assert_less (root_id, this->size()); 02560 02561 std::vector<int> 02562 sendlengths (this->size(), 0), 02563 displacements(this->size(), 0); 02564 02565 const int mysize = static_cast<int>(r.size()); 02566 this->allgather(mysize, sendlengths); 02567 02568 START_LOG("gather()", "Parallel"); 02569 02570 // Find the total size of the final array and 02571 // set up the displacement offsets for each processor. 02572 unsigned int globalsize = 0; 02573 for (unsigned int i=0; i != this->size(); ++i) 02574 { 02575 displacements[i] = globalsize; 02576 globalsize += sendlengths[i]; 02577 } 02578 02579 // Check for quick return 02580 if (globalsize == 0) 02581 { 02582 STOP_LOG("gather()", "Parallel"); 02583 return; 02584 } 02585 02586 // copy the input buffer 02587 std::vector<T> r_src(r); 02588 02589 // now resize it to hold the global data 02590 // on the receiving processor 02591 if (root_id == this->rank()) 02592 r.resize(globalsize); 02593 02594 // and get the data from the remote processors 02595 #ifndef NDEBUG 02596 // Only catch the return value when asserts are active. 02597 const int ierr = 02598 #endif 02599 MPI_Gatherv (r_src.empty() ? NULL : &r_src[0], mysize, StandardType<T>(), 02600 r.empty() ? NULL : &r[0], &sendlengths[0], 02601 &displacements[0], StandardType<T>(), 02602 root_id, 02603 this->get()); 02604 02605 libmesh_assert (ierr == MPI_SUCCESS); 02606 02607 STOP_LOG("gather()", "Parallel"); 02608 } 02609 02610 02611 template <typename T> 02612 inline void Communicator::allgather(T sendval, 02613 std::vector<T> &recv) const 02614 { 02615 START_LOG ("allgather()","Parallel"); 02616 02617 libmesh_assert(this->size()); 02618 recv.resize(this->size()); 02619 02620 unsigned int comm_size = this->size(); 02621 if (comm_size > 1) 02622 { 02623 StandardType<T> send_type(&sendval); 02624 02625 MPI_Allgather (&sendval, 02626 1, 02627 send_type, 02628 &recv[0], 02629 1, 02630 send_type, 02631 this->get()); 02632 } 02633 else if (comm_size > 0) 02634 recv[0] = sendval; 02635 02636 STOP_LOG ("allgather()","Parallel"); 02637 } 02638 02639 02640 02641 template <typename T> 02642 inline void Communicator::allgather 02643 (std::vector<T> &r, 02644 const bool identical_buffer_sizes) const 02645 { 02646 if (this->size() < 2) 02647 return; 02648 02649 START_LOG("allgather()", "Parallel"); 02650 02651 if (identical_buffer_sizes) 02652 { 02653 if (r.empty()) 02654 return; 02655 02656 libmesh_assert(this->verify(r.size())); 02657 02658 std::vector<T> r_src(r.size()*this->size()); 02659 r_src.swap(r); 02660 StandardType<T> send_type(&r_src[0]); 02661 02662 MPI_Allgather (&r_src[0], 02663 libmesh_cast_int<int>(r_src.size()), 02664 send_type, 02665 &r[0], 02666 libmesh_cast_int<int>(r_src.size()), 02667 send_type, 02668 this->get()); 02669 libmesh_assert(this->verify(r)); 02670 STOP_LOG("allgather()", "Parallel"); 02671 return; 02672 } 02673 02674 std::vector<int> 02675 sendlengths (this->size(), 0), 02676 displacements(this->size(), 0); 02677 02678 const int mysize = static_cast<int>(r.size()); 02679 this->allgather(mysize, sendlengths); 02680 02681 // Find the total size of the final array and 02682 // set up the displacement offsets for each processor. 02683 unsigned int globalsize = 0; 02684 for (unsigned int i=0; i != this->size(); ++i) 02685 { 02686 displacements[i] = globalsize; 02687 globalsize += sendlengths[i]; 02688 } 02689 02690 // Check for quick return 02691 if (globalsize == 0) 02692 { 02693 STOP_LOG("allgather()", "Parallel"); 02694 return; 02695 } 02696 02697 // copy the input buffer 02698 std::vector<T> r_src(globalsize); 02699 r_src.swap(r); 02700 02701 StandardType<T> send_type(&r[0]); 02702 02703 // and get the data from the remote processors. 02704 // Pass NULL if our vector is empty. 02705 #ifndef NDEBUG 02706 // Only catch the return value when asserts are active. 02707 const int ierr = 02708 #endif 02709 MPI_Allgatherv (r_src.empty() ? NULL : &r_src[0], mysize, send_type, 02710 &r[0], &sendlengths[0], 02711 &displacements[0], send_type, this->get()); 02712 02713 libmesh_assert (ierr == MPI_SUCCESS); 02714 02715 STOP_LOG("allgather()", "Parallel"); 02716 } 02717 02718 02719 template <typename Context, typename Iter, typename OutputIter> 02720 inline void Communicator::allgather_packed_range 02721 (Context *context, 02722 Iter range_begin, 02723 const Iter range_end, 02724 OutputIter out) const 02725 { 02726 // We will serialize variable size objects from *range_begin to 02727 // *range_end as a sequence of ints in this buffer 02728 std::vector<int> buffer; 02729 02730 Parallel::pack_range(context, range_begin, range_end, buffer); 02731 02732 this->allgather(buffer, false); 02733 02734 Parallel::unpack_range(buffer, context, out); 02735 } 02736 02737 02738 template <typename T> 02739 inline void Communicator::alltoall(std::vector<T> &buf) const 02740 { 02741 if (this->size() < 2 || buf.empty()) 02742 return; 02743 02744 START_LOG("alltoall()", "Parallel"); 02745 02746 // the per-processor size. this is the same for all 02747 // processors using MPI_Alltoall, could be variable 02748 // using MPI_Alltoallv 02749 const int size_per_proc = 02750 libmesh_cast_int<int>(buf.size()/this->size()); 02751 02752 libmesh_assert_equal_to (buf.size()%this->size(), 0); 02753 02754 libmesh_assert(this->verify(size_per_proc)); 02755 02756 std::vector<T> tmp(buf); 02757 02758 StandardType<T> send_type(&tmp[0]); 02759 02760 #ifndef NDEBUG 02761 // Only catch the return value when asserts are active. 02762 const int ierr = 02763 #endif 02764 MPI_Alltoall (&tmp[0], 02765 size_per_proc, 02766 send_type, 02767 &buf[0], 02768 size_per_proc, 02769 send_type, 02770 this->get()); 02771 libmesh_assert (ierr == MPI_SUCCESS); 02772 02773 STOP_LOG("alltoall()", "Parallel"); 02774 } 02775 02776 02777 02778 template <typename T> 02779 inline void Communicator::broadcast (T &data, const unsigned int root_id) const 02780 { 02781 if (this->size() == 1) 02782 { 02783 libmesh_assert (!this->rank()); 02784 libmesh_assert (!root_id); 02785 return; 02786 } 02787 02788 libmesh_assert_less (root_id, this->size()); 02789 02790 START_LOG("broadcast()", "Parallel"); 02791 02792 // Spread data to remote processors. 02793 #ifndef NDEBUG 02794 // Only catch the return value when asserts are active. 02795 const int ierr = 02796 #endif 02797 MPI_Bcast (&data, 1, StandardType<T>(&data), root_id, this->get()); 02798 02799 libmesh_assert (ierr == MPI_SUCCESS); 02800 02801 STOP_LOG("broadcast()", "Parallel"); 02802 } 02803 02804 02805 template <typename T> 02806 inline void Communicator::broadcast (std::basic_string<T> &data, 02807 const unsigned int root_id) const 02808 { 02809 if (this->size() == 1) 02810 { 02811 libmesh_assert (!this->rank()); 02812 libmesh_assert (!root_id); 02813 return; 02814 } 02815 02816 libmesh_assert_less (root_id, this->size()); 02817 02818 START_LOG("broadcast()", "Parallel"); 02819 02820 std::size_t data_size = data.size(); 02821 this->broadcast(data_size, root_id); 02822 02823 std::vector<T> data_c(data_size); 02824 #ifndef NDEBUG 02825 std::string orig(data); 02826 #endif 02827 02828 if (this->rank() == root_id) 02829 for(std::size_t i=0; i<data.size(); i++) 02830 data_c[i] = data[i]; 02831 02832 this->broadcast (data_c, root_id); 02833 02834 data.assign(data_c.begin(), data_c.end()); 02835 02836 #ifndef NDEBUG 02837 if (this->rank() == root_id) 02838 libmesh_assert_equal_to (data, orig); 02839 #endif 02840 02841 STOP_LOG("broadcast()", "Parallel"); 02842 } 02843 02844 02845 02846 template <typename T> 02847 inline void Communicator::broadcast (std::vector<T> &data, 02848 const unsigned int root_id) const 02849 { 02850 if (this->size() == 1) 02851 { 02852 libmesh_assert (!this->rank()); 02853 libmesh_assert (!root_id); 02854 return; 02855 } 02856 02857 libmesh_assert_less (root_id, this->size()); 02858 02859 START_LOG("broadcast()", "Parallel"); 02860 02861 // and get the data from the remote processors. 02862 // Pass NULL if our vector is empty. 02863 T *data_ptr = data.empty() ? NULL : &data[0]; 02864 02865 #ifndef NDEBUG 02866 // Only catch the return value when asserts are active. 02867 const int ierr = 02868 #endif 02869 MPI_Bcast (data_ptr, libmesh_cast_int<int>(data.size()), 02870 StandardType<T>(data_ptr), root_id, this->get()); 02871 02872 libmesh_assert (ierr == MPI_SUCCESS); 02873 02874 STOP_LOG("broadcast()", "Parallel"); 02875 } 02876 02877 02878 template <typename T> 02879 inline void Communicator::broadcast (std::set<T> &data, 02880 const unsigned int root_id) const 02881 { 02882 if (this->size() == 1) 02883 { 02884 libmesh_assert (!this->rank()); 02885 libmesh_assert (!root_id); 02886 return; 02887 } 02888 02889 libmesh_assert_less (root_id, this->size()); 02890 02891 START_LOG("broadcast()", "Parallel"); 02892 02893 std::vector<T> vecdata; 02894 if (this->rank() == root_id) 02895 vecdata.assign(data.begin(), data.end()); 02896 02897 std::size_t vecsize = vecdata.size(); 02898 this->broadcast(vecsize, root_id); 02899 if (this->rank() != root_id) 02900 vecdata.resize(vecsize); 02901 02902 this->broadcast(vecdata, root_id); 02903 if (this->rank() != root_id) 02904 { 02905 data.clear(); 02906 data.insert(vecdata.begin(), vecdata.end()); 02907 } 02908 02909 STOP_LOG("broadcast()", "Parallel"); 02910 } 02911 02912 02913 template <typename Context, typename OutputContext, 02914 typename Iter, typename OutputIter> 02915 inline void Communicator::broadcast_packed_range 02916 (const Context *context1, 02917 Iter range_begin, 02918 const Iter range_end, 02919 OutputContext *context2, 02920 OutputIter out, 02921 const unsigned int root_id) const 02922 { 02923 // We will serialize variable size objects from *range_begin to 02924 // *range_end as a sequence of ints in this buffer 02925 std::vector<int> buffer; 02926 02927 if (this->rank() == root_id) 02928 Parallel::pack_range(context1, range_begin, range_end, buffer); 02929 02930 // this->broadcast(vector) requires the receiving vectors to 02931 // already be the appropriate size 02932 std::size_t buffer_size = buffer.size(); 02933 this->broadcast (buffer_size); 02934 buffer.resize(buffer_size); 02935 02936 // Broadcast the packed data 02937 this->broadcast (buffer, root_id); 02938 02939 if (this->rank() != root_id) 02940 Parallel::unpack_range(buffer, context2, out); 02941 } 02942 02943 02944 #else // LIBMESH_HAVE_MPI 02945 02946 template <typename T> 02947 inline bool Communicator::verify(const T &) const { return true; } 02948 02949 template <typename T> 02950 inline bool Communicator::semiverify(const T *) const { return true; } 02951 02952 template <typename T> 02953 inline void Communicator::min(T &) const {} 02954 02955 template <typename T> 02956 inline void Communicator::minloc(T &, unsigned int &min_id) const { min_id = 0; } 02957 02958 template <typename T> 02959 inline void Communicator::minloc 02960 (std::vector<T> &r, std::vector<unsigned int> &min_id) const 02961 { for (std::size_t i=0; i!= r.size(); ++i) min_id[i] = 0; } 02962 02963 template <typename T> 02964 inline void Communicator::max(T &) const {} 02965 02966 template <typename T> 02967 inline void Communicator::maxloc(T &, unsigned int &max_id) const { max_id = 0; } 02968 02969 template <typename T> 02970 inline void Communicator::maxloc 02971 (std::vector<T> &r, std::vector<unsigned int> &max_id) const 02972 { for (std::size_t i=0; i!= r.size(); ++i) max_id[i] = 0; } 02973 02974 template <typename T> 02975 inline void Communicator::sum(T &) const {} 02976 02977 template <typename T> 02978 inline void Communicator::set_union(T&) const {} 02979 02980 template <typename T> 02981 inline void Communicator::set_union(T&, const unsigned int root_id) const 02982 { libmesh_assert_equal_to(root_id, 0); } 02983 02987 inline status Communicator::probe (const unsigned int, 02988 const MessageTag&) const 02989 { libmesh_error(); status s; return s; } 02990 02994 template <typename T> 02995 inline void Communicator::send (const unsigned int, T&, const MessageTag &) const 02996 { libmesh_error(); } 02997 02998 template <typename T> 02999 inline void Communicator::send (const unsigned int, T&, Request&, 03000 const MessageTag&) const 03001 { libmesh_error(); } 03002 03003 template <typename T> 03004 inline void Communicator::send (const unsigned int, T&, const DataType&, 03005 const MessageTag &) const 03006 { libmesh_error(); } 03007 03008 template <typename T> 03009 inline void Communicator::send (const unsigned int, T&, const DataType&, Request&, 03010 const MessageTag &) const 03011 { libmesh_error(); } 03012 03013 template <typename Context, typename Iter> 03014 inline void Communicator::send_packed_range 03015 (const unsigned int, const Context*, Iter, const Iter, const MessageTag&) const 03016 { libmesh_error(); } 03017 03018 template <typename Context, typename Iter> 03019 inline void Communicator::send_packed_range 03020 (const unsigned int, const Context*, Iter, const Iter, Request&, 03021 const MessageTag&) const 03022 { libmesh_error(); } 03023 03027 template <typename T> 03028 inline Status Communicator::receive (const unsigned int, T&, const MessageTag&) const 03029 { libmesh_error(); return Status(); } 03030 03031 template <typename T> 03032 inline void Communicator::receive 03033 (const unsigned int, T&, Request&, const MessageTag&) const 03034 { libmesh_error(); } 03035 03036 template <typename T> 03037 inline Status Communicator::receive 03038 (const unsigned int, T&, const DataType&, const MessageTag&) const 03039 { libmesh_error(); return Status(); } 03040 03041 template <typename T> 03042 inline void Communicator::receive 03043 (const unsigned int, T&, const DataType&, Request&, const MessageTag&) const 03044 { libmesh_error(); } 03045 03046 template <typename Context, typename OutputIter> 03047 inline void Communicator::receive_packed_range 03048 (const unsigned int, Context*, OutputIter, const MessageTag&) const 03049 { libmesh_error(); } 03050 03051 template <typename Context, typename OutputIter> 03052 inline void Communicator::receive_packed_range 03053 (const unsigned int, Context*, OutputIter, Request&, const MessageTag&) const 03054 { libmesh_error(); } 03055 03059 template <typename T1, typename T2> 03060 inline void Communicator::send_receive (const unsigned int send_tgt, 03061 T1 &send, 03062 const unsigned int recv_source, 03063 T2 &recv, 03064 const MessageTag &, 03065 const MessageTag &) const 03066 { 03067 libmesh_assert_equal_to (send_tgt, 0); 03068 libmesh_assert_equal_to (recv_source, 0); 03069 recv = send; 03070 } 03071 03077 template <typename Context1, typename RangeIter, 03078 typename Context2, typename OutputIter> 03079 inline void Communicator::send_receive_packed_range 03080 (const unsigned int dest_processor_id, const Context1*, RangeIter send_begin, 03081 const RangeIter send_end, const unsigned int source_processor_id, Context2*, 03082 OutputIter out, const MessageTag &, const MessageTag &) const 03083 { libmesh_error(); } 03084 03088 template <typename T> 03089 inline void Communicator::gather(const unsigned int root_id, 03090 T send, 03091 std::vector<T> &recv) const 03092 { 03093 libmesh_assert_equal_to (root_id, 0); 03094 recv.resize(1); 03095 recv[0] = send; 03096 } 03097 03098 template <typename T> 03099 inline void Communicator::gather(const unsigned int root_id, std::vector<T>&) const 03100 { libmesh_assert_equal_to(root_id, 0); } 03101 03102 template <typename T> 03103 inline void Communicator::allgather(T send, std::vector<T> &recv) const 03104 { 03105 recv.resize(1); 03106 recv[0] = send; 03107 } 03108 03109 template <typename T> 03110 inline void Communicator::allgather(std::vector<T> &, const bool) const {} 03111 03112 template <typename T> 03113 inline void Communicator::alltoall(std::vector<T> &) const {} 03114 03115 template <typename T> 03116 inline void Communicator::broadcast (T &, const unsigned int root_id) const 03117 { libmesh_assert_equal_to(root_id, 0); } 03118 03119 #endif // LIBMESH_HAVE_MPI 03120 03121 } // namespace Parallel 03122 03123 } // namespace libMesh 03124 03125 #endif // LIBMESH_PARALLEL_IMPLEMENTATION_H
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: