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