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