Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2023 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 "TypesafePtr.h"
30 : #include <vector>
31 : #include <string>
32 : #include "Vector.h"
33 : #include "Tensor.h"
34 : #include "Matrix.h"
35 :
36 : namespace PLMD {
37 :
38 : #ifndef __PLUMED_HAS_MPI
39 : /// Surrogate of MPI_Comm when MPI library is not available
40 : class MPI_Comm {};
41 : /// Surrogate of MPI_Datatype when MPI library is not available
42 : class MPI_Datatype {};
43 : /// Surrogate of MPI_Status when MPI library is not available
44 : class MPI_Status {};
45 : /// Surrogate of MPI_Request when MPI library is not available
46 : class MPI_Request {};
47 : #endif
48 :
49 : /// \ingroup TOOLBOX
50 : /// Class containing wrappers to MPI.
51 : /// All the MPI related stuff is relegated here.
52 : class Communicator {
53 : /// Communicator
54 : MPI_Comm communicator;
55 : /// Function returning the MPI type.
56 : /// You can use it to access to the MPI type of a C++ type, e.g.
57 : /// `MPI_Datatype type=getMPIType<double>();`
58 : template <class T>
59 : static MPI_Datatype getMPIType();
60 : /// Structure defining a buffer for MPI.
61 : /// It contains info on the pointed data and its type and size. It is useful to
62 : /// allow wrapper of MPI functions where the triplet (buffer,type,size)
63 : /// is grouped into a single object. It can be built starting from
64 : /// different kinds of data. To implement compatibility of MPI wrappers
65 : /// with e.g. vectors, add constructors here.
66 : struct Data {
67 : void*pointer;
68 : int size;
69 : int nbytes=0;
70 : MPI_Datatype type;
71 : /// Init from pointer and size
72 2918535 : template <typename T> Data(T*p,int s): pointer(p), size(s), nbytes(sizeof(T)), type(getMPIType<T>()) {}
73 : /// Init from reference
74 14584458 : template <typename T> explicit Data(T&p): pointer(&p), size(1), nbytes(sizeof(T)), type(getMPIType<T>()) {}
75 : /// Init from pointer to VectorGeneric
76 11179 : template <unsigned n> explicit Data(VectorGeneric<n> *p,int s): pointer(p), size(n*s), nbytes(sizeof(double)), type(getMPIType<double>()) {}
77 : /// Init from reference to VectorGeneric
78 : template <unsigned n> explicit Data(VectorGeneric<n> &p): pointer(&p), size(n), nbytes(sizeof(double)), type(getMPIType<double>()) {}
79 : /// Init from pointer to TensorGeneric
80 16 : 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>()) {}
81 : /// Init from reference to TensorGeneric
82 41550 : template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> &p): pointer(&p), size(n*m), nbytes(sizeof(double)), type(getMPIType<double>()) {}
83 : /// Init from reference to std::vector
84 2652079 : template <typename T> explicit Data(std::vector<T>&v) {
85 2652250 : Data d(v.data(),v.size()); pointer=d.pointer; size=d.size; type=d.type;
86 2652079 : }
87 : /// Init from reference to PLMD::Matrix
88 : template <typename T> explicit Data(Matrix<T>&m ) {
89 : if(m.nrows()*m.ncols()>0) { Data d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; }
90 : else { pointer=NULL; size=0; }
91 : }
92 : /// Init from reference to std::string
93 61 : explicit Data(std::string&s) {
94 61 : if(s.size()>0) { Data d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; }
95 0 : else { pointer=NULL; size=0; }
96 61 : }
97 : };
98 : /// Const version of Communicator::Data
99 : /// See Communicator::Data documentation
100 : struct ConstData {
101 : const void*pointer;
102 : int size;
103 : int nbytes=0;
104 : MPI_Datatype type;
105 24124 : template <typename T> explicit ConstData(const T*p,int s): pointer(p), size(s), nbytes(sizeof(T)), type(getMPIType<T>()) {}
106 952 : template <typename T> explicit ConstData(const T&p): pointer(&p), size(1), nbytes(sizeof(T)), type(getMPIType<T>()) {}
107 : template <unsigned n> explicit ConstData(const VectorGeneric<n> *p,int s): pointer(p), size(n*s), nbytes(sizeof(double)), type(getMPIType<double>()) {}
108 : template <unsigned n> explicit ConstData(const VectorGeneric<n> &p): pointer(&p), size(n), nbytes(sizeof(double)), type(getMPIType<double>()) {}
109 : 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>()) {}
110 : template <unsigned n,unsigned m> explicit ConstData(const TensorGeneric<n,m> &p): pointer(&p), size(n*m), nbytes(sizeof(double)), type(getMPIType<double>()) {}
111 4956 : template <typename T> explicit ConstData(const std::vector<T>&v) {
112 4956 : ConstData d(v.data(),v.size()); pointer=d.pointer; size=d.size; type=d.type;
113 4956 : }
114 : template <typename T> explicit ConstData(const Matrix<T>&m ) {
115 : if(m.nrows()*m.ncols()>0) { ConstData d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; }
116 : else { pointer=NULL; size=0; }
117 : }
118 57 : explicit ConstData(const std::string&s) {
119 57 : if(s.size()>0) { ConstData d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; }
120 0 : else { pointer=NULL; size=0; }
121 57 : }
122 : };
123 : public:
124 : ///Runtime acces to the __PLUMED_HAS_MPI definition
125 : static bool plumedHasMPI();
126 :
127 : /// Wrapper class for MPI_Status
128 : class Status {
129 : int Get_count(MPI_Datatype)const;
130 : public:
131 : MPI_Status s;
132 : template <class T>
133 7634 : int Get_count()const {return Get_count(getMPIType<T>());}
134 : };
135 : /// Special status used when status should be ignored.
136 : /// E.g. `Recv(a,0,1,Communicator::StatusIgnore);`
137 : /// Notice that this is the default for Recv, so this is equivalent to
138 : /// `Recv(a,0,1);`
139 : static Status StatusIgnore;
140 : /// Wrapper class for MPI_Request
141 : class Request {
142 : public:
143 : MPI_Request r;
144 : void wait(Status&s=StatusIgnore);
145 : };
146 : /// Default constructor
147 : Communicator();
148 : /// Copy constructor.
149 : /// It effectively "clones" the communicator, providing a new one acting on the same group
150 : Communicator(const Communicator&);
151 : /// Assignment operator.
152 : /// It effectively "clones" the communicator, providing a new one acting on the same group
153 : Communicator& operator=(const Communicator&);
154 : /// Destructor
155 : virtual ~Communicator();
156 : /// Obtain the rank of the present process
157 : int Get_rank()const;
158 : /// Obtain the number of processes
159 : int Get_size()const;
160 : /// Set from a real MPI communicator.
161 : /// \param comm MPI communicator
162 : void Set_comm(MPI_Comm comm);
163 : /// Reference to MPI communicator
164 : MPI_Comm & Get_comm();
165 : /// Set from a pointer to a real MPI communicator (C).
166 : /// \param comm Pointer to a C MPI communicator
167 : void Set_comm(const TypesafePtr & comm);
168 : /// Set from a pointer to a real MPI communicator (FORTRAN).
169 : /// \param comm Pointer to a FORTRAN MPI communicator (INTEGER)
170 : void Set_fcomm(const TypesafePtr & comm);
171 : /// Wrapper to MPI_Abort.
172 : /// \param code Error code
173 : void Abort(int code);
174 : /// Wrapper to MPI_Barrier
175 : void Barrier()const;
176 : /// Tests if MPI library is initialized
177 : static bool initialized();
178 : /// Wrapper for MPI_Allreduce with MPI_SUM (data struct)
179 : void Sum(Data);
180 : /// Wrapper for MPI_Allreduce with MPI_SUM (pointer)
181 108444 : template <class T> void Sum(T*buf,int count) {Sum(Data(buf,count));}
182 : /// Wrapper for MPI_Allreduce with MPI_SUM (reference)
183 4422565 : template <class T> void Sum(T&buf) {Sum(Data(buf));}
184 : /// Wrapper for MPI_Allreduce with MPI_PROD (data struct)
185 : void Prod(Data);
186 : /// Wrapper for MPI_Allreduce with MPI_PROD (pointer)
187 : template <class T> void Prod(T*buf,int count) {Prod(Data(buf,count));}
188 : /// Wrapper for MPI_Allreduce with MPI_PROD (reference)
189 : template <class T> void Prod(T&buf) {Prod(Data(buf));}
190 : /// Wrapper for MPI_Allreduce with MPI_MAX (data struct)
191 : void Max(Data);
192 : /// Wrapper for MPI_Allreduce with MPI_MAX (pointer)
193 : template <class T> void Max(T*buf,int count) {Max(Data(buf,count));}
194 : /// Wrapper for MPI_Allreduce with MPI_MAX (reference)
195 152 : template <class T> void Max(T&buf) {Max(Data(buf));}
196 : /// Wrapper for MPI_Allreduce with MPI_MIN (data struct)
197 : void Min(Data);
198 : /// Wrapper for MPI_Allreduce with MPI_MIN (pointer)
199 : template <class T> void Min(T*buf,int count) {Min(Data(buf,count));}
200 : /// Wrapper for MPI_Allreduce with MPI_MIN (reference)
201 0 : template <class T> void Min(T&buf) {Min(Data(buf));}
202 :
203 : /// Wrapper for MPI_Bcast (data struct)
204 : void Bcast(Data,int);
205 : /// Wrapper for MPI_Bcast (pointer)
206 : template <class T> void Bcast(T*buf,int count,int root) {Bcast(Data(buf,count),root);}
207 : /// Wrapper for MPI_Bcast (reference)
208 5536690 : template <class T> void Bcast(T&buf,int root) {Bcast(Data(buf),root);}
209 :
210 : /// Wrapper for MPI_Isend (data struct)
211 : Request Isend(ConstData,int,int);
212 : /// Wrapper for MPI_Isend (pointer)
213 15268 : template <class T> Request Isend(const T*buf,int count,int source,int tag) {return Isend(ConstData(buf,count),source,tag);}
214 : /// Wrapper for MPI_Isend (reference)
215 114 : template <class T> Request Isend(const T&buf,int source,int tag) {return Isend(ConstData(buf),source,tag);}
216 :
217 : /// Wrapper for MPI_Allgatherv (data struct)
218 : void Allgatherv(ConstData in,Data out,const int*,const int*);
219 : /// Wrapper for MPI_Allgatherv (pointer)
220 18907 : template <class T,class S> void Allgatherv(const T*sendbuf,int sendcount,S*recvbuf,const int*recvcounts,const int*displs) {
221 18907 : Allgatherv(ConstData(sendbuf,sendcount),Data(recvbuf,0),recvcounts,displs);
222 18907 : }
223 : /// Wrapper for MPI_Allgatherv (reference)
224 152 : template <class T,class S> void Allgatherv(const T&sendbuf,S&recvbuf,const int*recvcounts,const int*displs) {
225 152 : Allgatherv(ConstData(sendbuf),Data(recvbuf),recvcounts,displs);
226 152 : }
227 :
228 : /// Wrapper for MPI_Allgather (data struct)
229 : void Allgather(ConstData in,Data out);
230 : /// Wrapper for MPI_Allgatherv (pointer)
231 204 : template <class T,class S> void Allgather(const T*sendbuf,int sendcount,S*recvbuf,int recvcount) {
232 408 : Allgather(ConstData(sendbuf,sendcount),Data(recvbuf,recvcount*Get_size()));
233 204 : }
234 : /// Wrapper for MPI_Allgatherv (reference)
235 5642 : template <class T,class S> void Allgather(const T&sendbuf,S&recvbuf) {
236 6480 : Allgather(ConstData(sendbuf),Data(recvbuf));
237 5642 : }
238 :
239 : /// Wrapper for MPI_Recv (data struct)
240 : void Recv(Data,int,int,Status&s=StatusIgnore);
241 : /// Wrapper for MPI_Recv (pointer)
242 15268 : template <class T> void Recv(T*buf,int count,int source,int tag,Status&s=StatusIgnore) {Recv(Data(buf,count),source,tag,s);}
243 : /// Wrapper for MPI_Recv (reference)
244 114 : template <class T> void Recv(T&buf,int source,int tag,Status&s=StatusIgnore) {Recv(Data(buf),source,tag,s);}
245 :
246 : /// Wrapper to MPI_Comm_split
247 : void Split(int,int,Communicator&)const;
248 : };
249 :
250 : }
251 :
252 : #endif
|