1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 Copyright (c) 2012-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 #include "Communicator.h"
23 #include "Exception.h"
24 #include "AtomNumber.h"
25 #include <cstdlib>
26 #include <cstring>
27
28 using namespace std;
29
30 namespace PLMD {
31
Communicator()32 Communicator::Communicator()
33 #ifdef __PLUMED_HAS_MPI
34 : communicator(MPI_COMM_SELF)
35 #endif
36 {
37 }
38
Communicator(const Communicator & pc)39 Communicator::Communicator(const Communicator&pc) {
40 Set_comm(pc.communicator);
41 }
42
43 Communicator::Status Communicator::StatusIgnore;
44
operator =(const Communicator & pc)45 Communicator& Communicator::operator=(const Communicator&pc) {
46 if (this != &pc) {
47 Set_comm(pc.communicator);
48 }
49 return *this;
50 }
51
Get_rank() const52 int Communicator::Get_rank()const {
53 int r=0;
54 #ifdef __PLUMED_HAS_MPI
55 if(initialized()) MPI_Comm_rank(communicator,&r);
56 #endif
57 return r;
58 }
59
Get_size() const60 int Communicator::Get_size()const {
61 int s=1;
62 #ifdef __PLUMED_HAS_MPI
63 if(initialized()) MPI_Comm_size(communicator,&s);
64 #endif
65 return s;
66 }
67
Set_comm(MPI_Comm c)68 void Communicator::Set_comm(MPI_Comm c) {
69 #ifdef __PLUMED_HAS_MPI
70 if(initialized()) {
71 if(communicator!=MPI_COMM_SELF && communicator!=MPI_COMM_WORLD) MPI_Comm_free(&communicator);
72 if(c!=MPI_COMM_SELF) MPI_Comm_dup(c,&communicator);
73 }
74 #else
75 (void) c;
76 #endif
77 }
78
~Communicator()79 Communicator::~Communicator() {
80 #ifdef __PLUMED_HAS_MPI
81 if(initialized() && communicator!=MPI_COMM_SELF && communicator!=MPI_COMM_WORLD) MPI_Comm_free(&communicator);
82 #endif
83 }
84
Set_comm(void * val)85 void Communicator::Set_comm(void*val) {
86 #ifdef __PLUMED_HAS_MPI
87 plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
88 if(val) Set_comm(*(MPI_Comm*)val);
89 #else
90 (void) val;
91 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
92 #endif
93 }
94
Set_fcomm(void * val)95 void Communicator::Set_fcomm(void*val) {
96 #ifdef __PLUMED_HAS_MPI
97 plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
98 if(val) {
99 MPI_Comm comm=MPI_Comm_f2c(*(MPI_Fint*)val);
100 Set_comm(comm);
101 }
102 #else
103 (void) val;
104 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
105 #endif
106 }
107
Abort(int errorcode)108 void Communicator::Abort(int errorcode) {
109 #ifdef __PLUMED_HAS_MPI
110 if(initialized()) {
111 MPI_Abort(communicator,errorcode);
112 }
113 std::exit(errorcode);
114 #else
115 std::exit(errorcode);
116 #endif
117 }
118
Bcast(Data data,int root)119 void Communicator::Bcast(Data data,int root) {
120 #if defined(__PLUMED_HAS_MPI)
121 if(initialized()) MPI_Bcast(data.pointer,data.size,data.type,root,communicator);
122 #else
123 (void) data;
124 (void) root;
125 #endif
126 }
127
Sum(Data data)128 void Communicator::Sum(Data data) {
129 #if defined(__PLUMED_HAS_MPI)
130 if(initialized()) MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_SUM,communicator);
131 #else
132 (void) data;
133 #endif
134 }
135
Prod(Data data)136 void Communicator::Prod(Data data) {
137 #if defined(__PLUMED_HAS_MPI)
138 if(initialized()) MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_PROD,communicator);
139 #else
140 (void) data;
141 #endif
142 }
143
Max(Data data)144 void Communicator::Max(Data data) {
145 #if defined(__PLUMED_HAS_MPI)
146 if(initialized()) MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_MAX,communicator);
147 #else
148 (void) data;
149 #endif
150 }
151
Min(Data data)152 void Communicator::Min(Data data) {
153 #if defined(__PLUMED_HAS_MPI)
154 if(initialized()) MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_MIN,communicator);
155 #else
156 (void) data;
157 #endif
158 }
159
Isend(ConstData data,int source,int tag)160 Communicator::Request Communicator::Isend(ConstData data,int source,int tag) {
161 Request req;
162 #ifdef __PLUMED_HAS_MPI
163 plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
164 void*s=const_cast<void*>((const void*)data.pointer);
165 MPI_Isend(s,data.size,data.type,source,tag,communicator,&req.r);
166 #else
167 (void) data;
168 (void) source;
169 (void) tag;
170 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
171 #endif
172 return req;
173 }
174
Allgatherv(ConstData in,Data out,const int * recvcounts,const int * displs)175 void Communicator::Allgatherv(ConstData in,Data out,const int*recvcounts,const int*displs) {
176 void*s=const_cast<void*>((const void*)in.pointer);
177 void*r=const_cast<void*>((const void*)out.pointer);
178 int*rc=const_cast<int*>(recvcounts);
179 int*di=const_cast<int*>(displs);
180 #if defined(__PLUMED_HAS_MPI)
181 if(initialized()) {
182 if(s==NULL)s=MPI_IN_PLACE;
183 MPI_Allgatherv(s,in.size,in.type,r,rc,di,out.type,communicator);
184 } else {
185 plumed_assert(in.nbytes==out.nbytes);
186 plumed_assert(in.size==out.size);
187 plumed_assert(rc);
188 plumed_assert(rc[0]==in.size);
189 plumed_assert(di);
190 if(s) std::memcpy(static_cast<char*>(r)+displs[0]*in.nbytes,s,in.size*in.nbytes);
191 }
192 #else
193 plumed_assert(in.nbytes==out.nbytes);
194 plumed_assert(in.size==out.size);
195 plumed_assert(rc);
196 plumed_assert(rc[0]==in.size);
197 plumed_assert(di);
198 if(s) std::memcpy(static_cast<char*>(r)+displs[0]*in.nbytes,s,in.size*in.nbytes);
199 #endif
200 }
201
Allgather(ConstData in,Data out)202 void Communicator::Allgather(ConstData in,Data out) {
203 void*s=const_cast<void*>((const void*)in.pointer);
204 void*r=const_cast<void*>((const void*)out.pointer);
205 #if defined(__PLUMED_HAS_MPI)
206 if(initialized()) {
207 if(s==NULL)s=MPI_IN_PLACE;
208 MPI_Allgather(s,in.size,in.type,r,out.size/Get_size(),out.type,communicator);
209 } else {
210 plumed_assert(in.nbytes==out.nbytes);
211 plumed_assert(in.size==out.size);
212 if(s) std::memcpy(r,s,in.size*in.nbytes);
213 }
214 #else
215 plumed_assert(in.nbytes==out.nbytes);
216 plumed_assert(in.size==out.size);
217 if(s) std::memcpy(r,s,in.size*in.nbytes);
218 #endif
219 }
220
Recv(Data data,int source,int tag,Status & status)221 void Communicator::Recv(Data data,int source,int tag,Status&status) {
222 #ifdef __PLUMED_HAS_MPI
223 plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
224 if(&status==&StatusIgnore) MPI_Recv(data.pointer,data.size,data.type,source,tag,communicator,MPI_STATUS_IGNORE);
225 else MPI_Recv(data.pointer,data.size,data.type,source,tag,communicator,&status.s);
226 #else
227 (void) data;
228 (void) source;
229 (void) tag;
230 (void) status;
231 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
232 #endif
233 }
234
235
236
237
238
Barrier() const239 void Communicator::Barrier()const {
240 #ifdef __PLUMED_HAS_MPI
241 if(initialized()) MPI_Barrier(communicator);
242 #endif
243 }
244
Get_comm()245 MPI_Comm & Communicator::Get_comm() {
246 return communicator;
247 }
248
initialized()249 bool Communicator::initialized() {
250 #if defined(__PLUMED_HAS_MPI)
251 int flag=0;
252 MPI_Initialized(&flag);
253 if(flag) return true;
254 else return false;
255 #endif
256 return false;
257 }
258
wait(Status & s)259 void Communicator::Request::wait(Status&s) {
260 #ifdef __PLUMED_HAS_MPI
261 plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
262 if(&s==&StatusIgnore) MPI_Wait(&r,MPI_STATUS_IGNORE);
263 else MPI_Wait(&r,&s.s);
264 #else
265 (void) s;
266 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
267 #endif
268 }
269
270 #ifdef __PLUMED_HAS_MPI
getMPIType()271 template<> MPI_Datatype Communicator::getMPIType<float>() { return MPI_FLOAT;}
getMPIType()272 template<> MPI_Datatype Communicator::getMPIType<double>() { return MPI_DOUBLE;}
getMPIType()273 template<> MPI_Datatype Communicator::getMPIType<int>() { return MPI_INT;}
getMPIType()274 template<> MPI_Datatype Communicator::getMPIType<char>() { return MPI_CHAR;}
getMPIType()275 template<> MPI_Datatype Communicator::getMPIType<unsigned>() { return MPI_UNSIGNED;}
getMPIType()276 template<> MPI_Datatype Communicator::getMPIType<AtomNumber>() { return MPI_UNSIGNED;}
getMPIType()277 template<> MPI_Datatype Communicator::getMPIType<long unsigned>() { return MPI_UNSIGNED_LONG;}
getMPIType()278 template<> MPI_Datatype Communicator::getMPIType<long double>() { return MPI_LONG_DOUBLE;}
279 #else
getMPIType()280 template<> MPI_Datatype Communicator::getMPIType<float>() { return MPI_Datatype();}
getMPIType()281 template<> MPI_Datatype Communicator::getMPIType<double>() { return MPI_Datatype();}
getMPIType()282 template<> MPI_Datatype Communicator::getMPIType<int>() { return MPI_Datatype();}
getMPIType()283 template<> MPI_Datatype Communicator::getMPIType<char>() { return MPI_Datatype();}
getMPIType()284 template<> MPI_Datatype Communicator::getMPIType<unsigned>() { return MPI_Datatype();}
getMPIType()285 template<> MPI_Datatype Communicator::getMPIType<AtomNumber>() { return MPI_Datatype();}
getMPIType()286 template<> MPI_Datatype Communicator::getMPIType<long unsigned>() { return MPI_Datatype();}
getMPIType()287 template<> MPI_Datatype Communicator::getMPIType<long double>() { return MPI_Datatype();}
288 #endif
289
290
Split(int color,int key,Communicator & pc) const291 void Communicator::Split(int color,int key,Communicator&pc)const {
292 #ifdef __PLUMED_HAS_MPI
293 MPI_Comm_split(communicator,color,key,&pc.communicator);
294 #else
295 (void) color;
296 (void) key;
297 (void) pc;
298 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
299 #endif
300 }
301
Get_count(MPI_Datatype type) const302 int Communicator::Status::Get_count(MPI_Datatype type)const {
303 int i;
304 #ifdef __PLUMED_HAS_MPI
305 plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
306 MPI_Get_count(const_cast<MPI_Status*>(&s),type,&i);
307 #else
308 i=0;
309 plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
310 #endif
311 return i;
312 }
313
314 }
315
316