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