1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 Copyright (c) 2011-2021 The plumed team 3 (see the PEOPLE file at the root of the distribution for a list of names) 4 5 See http://www.plumed.org for more information. 6 7 This file is part of plumed, version 2. 8 9 plumed is free software: you can redistribute it and/or modify 10 it under the terms of the GNU Lesser General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 plumed is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public License 20 along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 #ifndef __PLUMED_tools_Communicator_h 23 #define __PLUMED_tools_Communicator_h 24 #ifdef __PLUMED_HAS_MPI 25 #include <mpi.h> 26 #endif 27 #include <cstdlib> 28 #include "Exception.h" 29 #include <vector> 30 #include <string> 31 #include "Vector.h" 32 #include "Tensor.h" 33 #include "Matrix.h" 34 35 namespace PLMD { 36 37 #ifndef __PLUMED_HAS_MPI 38 /// Surrogate of MPI_Comm when MPI library is not available 39 class MPI_Comm {}; 40 /// Surrogate of MPI_Datatype when MPI library is not available 41 class MPI_Datatype {}; 42 /// Surrogate of MPI_Status when MPI library is not available 43 class MPI_Status {}; 44 /// Surrogate of MPI_Request when MPI library is not available 45 class MPI_Request {}; 46 #endif 47 48 /// \ingroup TOOLBOX 49 /// Class containing wrappers to MPI. 50 /// All the MPI related stuff is relegated here. 51 class Communicator { 52 /// Communicator 53 MPI_Comm communicator; 54 /// Function returning the MPI type. 55 /// You can use it to access to the MPI type of a C++ type, e.g. 56 /// `MPI_Datatype type=getMPIType<double>();` 57 template <class T> 58 static MPI_Datatype getMPIType(); 59 /// Structure defining a buffer for MPI. 60 /// It contains info on the pointed data and its type and size. It is useful to 61 /// allow wrapper of MPI functions where the triplet (buffer,type,size) 62 /// is grouped into a single object. It can be built starting from 63 /// different kinds of data. To implement compatibility of MPI wrappers 64 /// with e.g. vectors, add constructors here. 65 struct Data { 66 void*pointer; 67 int size; 68 int nbytes=0; 69 MPI_Datatype type; 70 /// Init from pointer and size DataData71 template <typename T> Data(T*p,int s): pointer(p), size(s), nbytes(sizeof(T)), type(getMPIType<T>()) {} 72 /// Init from reference DataData73 template <typename T> explicit Data(T&p): pointer(&p), size(1), nbytes(sizeof(T)), type(getMPIType<T>()) {} 74 /// Init from pointer to VectorGeneric DataData75 template <unsigned n> explicit Data(VectorGeneric<n> *p,int s): pointer(p), size(n*s), nbytes(sizeof(double)), type(getMPIType<double>()) {} 76 /// Init from reference to VectorGeneric DataData77 template <unsigned n> explicit Data(VectorGeneric<n> &p): pointer(&p), size(n), nbytes(sizeof(double)), type(getMPIType<double>()) {} 78 /// Init from pointer to TensorGeneric DataData79 template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> *p,int s): pointer(p), size(n*m*s), nbytes(sizeof(double)), type(getMPIType<double>()) {} 80 /// Init from reference to TensorGeneric DataData81 template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> &p): pointer(&p), size(n*m), nbytes(sizeof(double)), type(getMPIType<double>()) {} 82 /// Init from reference to std::vector DataData83 template <typename T> explicit Data(std::vector<T>&v) { 84 Data d(v.data(),v.size()); pointer=d.pointer; size=d.size; type=d.type; 85 } 86 /// Init from reference to PLMD::Matrix DataData87 template <typename T> explicit Data(Matrix<T>&m ) { 88 if(m.nrows()*m.ncols()>0) { Data d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; } 89 else { pointer=NULL; size=0; } 90 } 91 /// Init from reference to std::string DataData92 explicit Data(std::string&s) { 93 if(s.size()>0) { Data d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; } 94 else { pointer=NULL; size=0; } 95 } 96 }; 97 /// Const version of Communicator::Data 98 /// See Communicator::Data documentation 99 struct ConstData { 100 const void*pointer; 101 int size; 102 int nbytes=0; 103 MPI_Datatype type; ConstDataConstData104 template <typename T> explicit ConstData(const T*p,int s): pointer(p), size(s), nbytes(sizeof(T)), type(getMPIType<T>()) {} ConstDataConstData105 template <typename T> explicit ConstData(const T&p): pointer(&p), size(1), nbytes(sizeof(T)), type(getMPIType<T>()) {} ConstDataConstData106 template <unsigned n> explicit ConstData(const VectorGeneric<n> *p,int s): pointer(p), size(n*s), nbytes(sizeof(double)), type(getMPIType<double>()) {} ConstDataConstData107 template <unsigned n> explicit ConstData(const VectorGeneric<n> &p): pointer(&p), size(n), nbytes(sizeof(double)), type(getMPIType<double>()) {} ConstDataConstData108 template <unsigned n,unsigned m> explicit ConstData(const TensorGeneric<n,m> *p,int s): pointer(p), size(n*m*s), nbytes(sizeof(double)), type(getMPIType<double>()) {} ConstDataConstData109 template <unsigned n,unsigned m> explicit ConstData(const TensorGeneric<n,m> &p): pointer(&p), size(n*m), nbytes(sizeof(double)), type(getMPIType<double>()) {} ConstDataConstData110 template <typename T> explicit ConstData(const std::vector<T>&v) { 111 ConstData d(v.data(),v.size()); pointer=d.pointer; size=d.size; type=d.type; 112 } ConstDataConstData113 template <typename T> explicit ConstData(const Matrix<T>&m ) { 114 if(m.nrows()*m.ncols()>0) { ConstData d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; } 115 else { pointer=NULL; size=0; } 116 } ConstDataConstData117 explicit ConstData(const std::string&s) { 118 if(s.size()>0) { ConstData d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; } 119 else { pointer=NULL; size=0; } 120 } 121 }; 122 public: 123 /// Wrapper class for MPI_Status 124 class Status { 125 int Get_count(MPI_Datatype)const; 126 public: 127 MPI_Status s; 128 template <class T> Get_count()129 int Get_count()const {return Get_count(getMPIType<T>());} 130 }; 131 /// Special status used when status should be ignored. 132 /// E.g. `Recv(a,0,1,Communicator::StatusIgnore);` 133 /// Notice that this is the default for Recv, so this is equivalent to 134 /// `Recv(a,0,1);` 135 static Status StatusIgnore; 136 /// Wrapper class for MPI_Request 137 class Request { 138 public: 139 MPI_Request r; 140 void wait(Status&s=StatusIgnore); 141 }; 142 /// Default constructor 143 Communicator(); 144 /// Copy constructor. 145 /// It effectively "clones" the communicator, providing a new one acting on the same group 146 Communicator(const Communicator&); 147 /// Assignment operator. 148 /// It effectively "clones" the communicator, providing a new one acting on the same group 149 Communicator& operator=(const Communicator&); 150 /// Destructor 151 virtual ~Communicator(); 152 /// Obtain the rank of the present process 153 int Get_rank()const; 154 /// Obtain the number of processes 155 int Get_size()const; 156 /// Set from a real MPI communicator. 157 /// \param comm MPI communicator 158 void Set_comm(MPI_Comm comm); 159 /// Reference to MPI communicator 160 MPI_Comm & Get_comm(); 161 /// Set from a pointer to a real MPI communicator (C). 162 /// \param comm Pointer to a C MPI communicator 163 void Set_comm(void*comm); 164 /// Set from a pointer to a real MPI communicator (FORTRAN). 165 /// \param comm Pointer to a FORTRAN MPI communicator (INTEGER) 166 void Set_fcomm(void*comm); 167 /// Wrapper to MPI_Abort. 168 /// \param code Error code 169 void Abort(int code); 170 /// Wrapper to MPI_Barrier 171 void Barrier()const; 172 /// Tests if MPI library is initialized 173 static bool initialized(); 174 /// Wrapper for MPI_Allreduce with MPI_SUM (data struct) 175 void Sum(Data); 176 /// Wrapper for MPI_Allreduce with MPI_SUM (pointer) Sum(T * buf,int count)177 template <class T> void Sum(T*buf,int count) {Sum(Data(buf,count));} 178 /// Wrapper for MPI_Allreduce with MPI_SUM (reference) Sum(T & buf)179 template <class T> void Sum(T&buf) {Sum(Data(buf));} 180 /// Wrapper for MPI_Allreduce with MPI_PROD (data struct) 181 void Prod(Data); 182 /// Wrapper for MPI_Allreduce with MPI_PROD (pointer) Prod(T * buf,int count)183 template <class T> void Prod(T*buf,int count) {Prod(Data(buf,count));} 184 /// Wrapper for MPI_Allreduce with MPI_PROD (reference) Prod(T & buf)185 template <class T> void Prod(T&buf) {Prod(Data(buf));} 186 /// Wrapper for MPI_Allreduce with MPI_MAX (data struct) 187 void Max(Data); 188 /// Wrapper for MPI_Allreduce with MPI_MAX (pointer) Max(T * buf,int count)189 template <class T> void Max(T*buf,int count) {Max(Data(buf,count));} 190 /// Wrapper for MPI_Allreduce with MPI_MAX (reference) Max(T & buf)191 template <class T> void Max(T&buf) {Max(Data(buf));} 192 /// Wrapper for MPI_Allreduce with MPI_MIN (data struct) 193 void Min(Data); 194 /// Wrapper for MPI_Allreduce with MPI_MIN (pointer) Min(T * buf,int count)195 template <class T> void Min(T*buf,int count) {Min(Data(buf,count));} 196 /// Wrapper for MPI_Allreduce with MPI_MIN (reference) Min(T & buf)197 template <class T> void Min(T&buf) {Min(Data(buf));} 198 199 /// Wrapper for MPI_Bcast (data struct) 200 void Bcast(Data,int); 201 /// Wrapper for MPI_Bcast (pointer) Bcast(T * buf,int count,int root)202 template <class T> void Bcast(T*buf,int count,int root) {Bcast(Data(buf,count),root);} 203 /// Wrapper for MPI_Bcast (reference) Bcast(T & buf,int root)204 template <class T> void Bcast(T&buf,int root) {Bcast(Data(buf),root);} 205 206 /// Wrapper for MPI_Isend (data struct) 207 Request Isend(ConstData,int,int); 208 /// Wrapper for MPI_Isend (pointer) Isend(const T * buf,int count,int source,int tag)209 template <class T> Request Isend(const T*buf,int count,int source,int tag) {return Isend(ConstData(buf,count),source,tag);} 210 /// Wrapper for MPI_Isend (reference) Isend(const T & buf,int source,int tag)211 template <class T> Request Isend(const T&buf,int source,int tag) {return Isend(ConstData(buf),source,tag);} 212 213 /// Wrapper for MPI_Allgatherv (data struct) 214 void Allgatherv(ConstData in,Data out,const int*,const int*); 215 /// Wrapper for MPI_Allgatherv (pointer) Allgatherv(const T * sendbuf,int sendcount,S * recvbuf,const int * recvcounts,const int * displs)216 template <class T,class S> void Allgatherv(const T*sendbuf,int sendcount,S*recvbuf,const int*recvcounts,const int*displs) { 217 Allgatherv(ConstData(sendbuf,sendcount),Data(recvbuf,0),recvcounts,displs); 218 } 219 /// Wrapper for MPI_Allgatherv (reference) Allgatherv(const T & sendbuf,S & recvbuf,const int * recvcounts,const int * displs)220 template <class T,class S> void Allgatherv(const T&sendbuf,S&recvbuf,const int*recvcounts,const int*displs) { 221 Allgatherv(ConstData(sendbuf),Data(recvbuf),recvcounts,displs); 222 } 223 224 /// Wrapper for MPI_Allgather (data struct) 225 void Allgather(ConstData in,Data out); 226 /// Wrapper for MPI_Allgatherv (pointer) Allgather(const T * sendbuf,int sendcount,S * recvbuf,int recvcount)227 template <class T,class S> void Allgather(const T*sendbuf,int sendcount,S*recvbuf,int recvcount) { 228 Allgather(ConstData(sendbuf,sendcount),Data(recvbuf,recvcount*Get_size())); 229 } 230 /// Wrapper for MPI_Allgatherv (reference) Allgather(const T & sendbuf,S & recvbuf)231 template <class T,class S> void Allgather(const T&sendbuf,S&recvbuf) { 232 Allgather(ConstData(sendbuf),Data(recvbuf)); 233 } 234 235 /// Wrapper for MPI_Recv (data struct) 236 void Recv(Data,int,int,Status&s=StatusIgnore); 237 /// Wrapper for MPI_Recv (pointer) 238 template <class T> void Recv(T*buf,int count,int source,int tag,Status&s=StatusIgnore) {Recv(Data(buf,count),source,tag,s);} 239 /// Wrapper for MPI_Recv (reference) 240 template <class T> void Recv(T&buf,int source,int tag,Status&s=StatusIgnore) {Recv(Data(buf),source,tag,s);} 241 242 /// Wrapper to MPI_Comm_split 243 void Split(int,int,Communicator&)const; 244 }; 245 246 } 247 248 #endif 249