8c1ef5153d1e917cc9707bc400ed8ff9d00883b2
[alexxy/gromacs.git] / src / gromacs / mdlib / domdec_network.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2008,2009,2010,2012,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 #include "gmxpre.h"
37
38 #include "config.h"
39
40 #include <string.h>
41 #include "gromacs/legacyheaders/types/commrec.h"
42 #include "gromacs/legacyheaders/domdec_network.h"
43
44 #include "gromacs/utility/gmxmpi.h"
45
46
47 #define DDMASTERRANK(dd)   (dd->masterrank)
48
49
50 void dd_sendrecv_int(const gmx_domdec_t gmx_unused *dd,
51                      int gmx_unused ddimind, int gmx_unused direction,
52                      int gmx_unused *buf_s, int gmx_unused n_s,
53                      int gmx_unused *buf_r, int gmx_unused n_r)
54 {
55 #ifdef GMX_MPI
56     int        rank_s, rank_r;
57     MPI_Status stat;
58
59     rank_s = dd->neighbor[ddimind][direction == dddirForward ? 0 : 1];
60     rank_r = dd->neighbor[ddimind][direction == dddirForward ? 1 : 0];
61
62     if (n_s && n_r)
63     {
64         MPI_Sendrecv(buf_s, n_s*sizeof(int), MPI_BYTE, rank_s, 0,
65                      buf_r, n_r*sizeof(int), MPI_BYTE, rank_r, 0,
66                      dd->mpi_comm_all, &stat);
67     }
68     else if (n_s)
69     {
70         MPI_Send(    buf_s, n_s*sizeof(int), MPI_BYTE, rank_s, 0,
71                      dd->mpi_comm_all);
72     }
73     else if (n_r)
74     {
75         MPI_Recv(    buf_r, n_r*sizeof(int), MPI_BYTE, rank_r, 0,
76                      dd->mpi_comm_all, &stat);
77     }
78
79 #endif
80 }
81
82 void dd_sendrecv_real(const gmx_domdec_t gmx_unused *dd,
83                       int gmx_unused ddimind, int gmx_unused direction,
84                       real gmx_unused *buf_s, int gmx_unused n_s,
85                       real gmx_unused *buf_r, int gmx_unused n_r)
86 {
87 #ifdef GMX_MPI
88     int        rank_s, rank_r;
89     MPI_Status stat;
90
91     rank_s = dd->neighbor[ddimind][direction == dddirForward ? 0 : 1];
92     rank_r = dd->neighbor[ddimind][direction == dddirForward ? 1 : 0];
93
94     if (n_s && n_r)
95     {
96         MPI_Sendrecv(buf_s, n_s*sizeof(real), MPI_BYTE, rank_s, 0,
97                      buf_r, n_r*sizeof(real), MPI_BYTE, rank_r, 0,
98                      dd->mpi_comm_all, &stat);
99     }
100     else if (n_s)
101     {
102         MPI_Send(    buf_s, n_s*sizeof(real), MPI_BYTE, rank_s, 0,
103                      dd->mpi_comm_all);
104     }
105     else if (n_r)
106     {
107         MPI_Recv(    buf_r, n_r*sizeof(real), MPI_BYTE, rank_r, 0,
108                      dd->mpi_comm_all, &stat);
109     }
110
111 #endif
112 }
113
114 void dd_sendrecv_rvec(const gmx_domdec_t gmx_unused *dd,
115                       int gmx_unused ddimind, int gmx_unused direction,
116                       rvec gmx_unused *buf_s, int gmx_unused n_s,
117                       rvec gmx_unused *buf_r, int gmx_unused n_r)
118 {
119 #ifdef GMX_MPI
120     int        rank_s, rank_r;
121     MPI_Status stat;
122
123     rank_s = dd->neighbor[ddimind][direction == dddirForward ? 0 : 1];
124     rank_r = dd->neighbor[ddimind][direction == dddirForward ? 1 : 0];
125
126     if (n_s && n_r)
127     {
128         MPI_Sendrecv(buf_s[0], n_s*sizeof(rvec), MPI_BYTE, rank_s, 0,
129                      buf_r[0], n_r*sizeof(rvec), MPI_BYTE, rank_r, 0,
130                      dd->mpi_comm_all, &stat);
131     }
132     else if (n_s)
133     {
134         MPI_Send(    buf_s[0], n_s*sizeof(rvec), MPI_BYTE, rank_s, 0,
135                      dd->mpi_comm_all);
136     }
137     else if (n_r)
138     {
139         MPI_Recv(    buf_r[0], n_r*sizeof(rvec), MPI_BYTE, rank_r, 0,
140                      dd->mpi_comm_all, &stat);
141     }
142
143 #endif
144 }
145
146 void dd_sendrecv2_rvec(const gmx_domdec_t gmx_unused *dd,
147                        int gmx_unused ddimind,
148                        rvec gmx_unused *buf_s_fw, int gmx_unused n_s_fw,
149                        rvec gmx_unused *buf_r_fw, int gmx_unused n_r_fw,
150                        rvec gmx_unused *buf_s_bw, int gmx_unused n_s_bw,
151                        rvec gmx_unused *buf_r_bw, int gmx_unused n_r_bw)
152 {
153 #ifdef GMX_MPI
154     int         rank_fw, rank_bw, nreq;
155     MPI_Request req[4];
156     MPI_Status  stat[4];
157
158     rank_fw = dd->neighbor[ddimind][0];
159     rank_bw = dd->neighbor[ddimind][1];
160
161     if (!dd->bSendRecv2)
162     {
163         /* Try to send and receive in two directions simultaneously.
164          * Should be faster, especially on machines
165          * with full 3D communication networks.
166          * However, it could be that communication libraries are
167          * optimized for MPI_Sendrecv and non-blocking MPI calls
168          * are slower.
169          * SendRecv2 can be turned on with the env.var. GMX_DD_SENDRECV2
170          */
171         nreq = 0;
172         if (n_r_fw)
173         {
174             MPI_Irecv(buf_r_fw[0], n_r_fw*sizeof(rvec), MPI_BYTE,
175                       rank_bw, 0, dd->mpi_comm_all, &req[nreq++]);
176         }
177         if (n_r_bw)
178         {
179             MPI_Irecv(buf_r_bw[0], n_r_bw*sizeof(rvec), MPI_BYTE,
180                       rank_fw, 1, dd->mpi_comm_all, &req[nreq++]);
181         }
182         if (n_s_fw)
183         {
184             MPI_Isend(buf_s_fw[0], n_s_fw*sizeof(rvec), MPI_BYTE,
185                       rank_fw, 0, dd->mpi_comm_all, &req[nreq++]);
186         }
187         if (n_s_bw)
188         {
189             MPI_Isend(buf_s_bw[0], n_s_bw*sizeof(rvec), MPI_BYTE,
190                       rank_bw, 1, dd->mpi_comm_all, &req[nreq++]);
191         }
192         if (nreq)
193         {
194             MPI_Waitall(nreq, req, stat);
195         }
196     }
197     else
198     {
199         /* Communicate in two ordered phases.
200          * This is slower, even on a dual-core Opteron cluster
201          * with a single full-duplex network connection per machine.
202          */
203         /* Forward */
204         MPI_Sendrecv(buf_s_fw[0], n_s_fw*sizeof(rvec), MPI_BYTE, rank_fw, 0,
205                      buf_r_fw[0], n_r_fw*sizeof(rvec), MPI_BYTE, rank_bw, 0,
206                      dd->mpi_comm_all, &stat[0]);
207         /* Backward */
208         MPI_Sendrecv(buf_s_bw[0], n_s_bw*sizeof(rvec), MPI_BYTE, rank_bw, 0,
209                      buf_r_bw[0], n_r_bw*sizeof(rvec), MPI_BYTE, rank_fw, 0,
210                      dd->mpi_comm_all, &stat[0]);
211     }
212 #endif
213 }
214
215 /* IBM's BlueGene(/L) MPI_Bcast dereferences the data pointer
216  * even when 0 == nbytes, so we protect calls to it on BlueGene.
217  * Fortunately dd_bcast() and dd_bcastc() are only
218  * called during DD setup and partition.
219  */
220
221 void dd_bcast(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *data)
222 {
223 #ifdef GMX_MPI
224 #ifdef GMX_BLUEGENE
225     if (nbytes > 0)
226     {
227 #endif
228     MPI_Bcast(data, nbytes, MPI_BYTE,
229               DDMASTERRANK(dd), dd->mpi_comm_all);
230 #ifdef GMX_BLUEGENE
231 }
232 #endif
233 #endif
234 }
235
236 void dd_bcastc(gmx_domdec_t *dd, int nbytes, void *src, void *dest)
237 {
238     if (DDMASTER(dd))
239     {
240         memcpy(dest, src, nbytes);
241     }
242 #ifdef GMX_MPI
243 #ifdef GMX_BLUEGENE
244     if (nbytes > 0)
245     {
246 #endif
247     MPI_Bcast(dest, nbytes, MPI_BYTE,
248               DDMASTERRANK(dd), dd->mpi_comm_all);
249 #ifdef GMX_BLUEGENE
250 }
251 #endif
252 #endif
253 }
254
255 void dd_scatter(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *src, void gmx_unused *dest)
256 {
257 #ifdef GMX_MPI
258     MPI_Scatter(src, nbytes, MPI_BYTE,
259                 dest, nbytes, MPI_BYTE,
260                 DDMASTERRANK(dd), dd->mpi_comm_all);
261 #endif
262 }
263
264 void dd_gather(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *src, void gmx_unused *dest)
265 {
266 #ifdef GMX_MPI
267     MPI_Gather(src, nbytes, MPI_BYTE,
268                dest, nbytes, MPI_BYTE,
269                DDMASTERRANK(dd), dd->mpi_comm_all);
270 #endif
271 }
272
273 void dd_scatterv(gmx_domdec_t gmx_unused *dd,
274                  int gmx_unused *scounts, int gmx_unused *disps, void gmx_unused *sbuf,
275                  int gmx_unused rcount, void gmx_unused *rbuf)
276 {
277 #ifdef GMX_MPI
278     int dum;
279
280     if (rcount == 0)
281     {
282         /* MPI does not allow NULL pointers */
283         rbuf = &dum;
284     }
285     MPI_Scatterv(sbuf, scounts, disps, MPI_BYTE,
286                  rbuf, rcount, MPI_BYTE,
287                  DDMASTERRANK(dd), dd->mpi_comm_all);
288 #endif
289 }
290
291 void dd_gatherv(gmx_domdec_t gmx_unused *dd,
292                 int gmx_unused scount, void gmx_unused *sbuf,
293                 int gmx_unused *rcounts, int gmx_unused *disps, void gmx_unused *rbuf)
294 {
295 #ifdef GMX_MPI
296     int dum;
297
298     if (scount == 0)
299     {
300         /* MPI does not allow NULL pointers */
301         sbuf = &dum;
302     }
303     MPI_Gatherv(sbuf, scount, MPI_BYTE,
304                 rbuf, rcounts, disps, MPI_BYTE,
305                 DDMASTERRANK(dd), dd->mpi_comm_all);
306 #endif
307 }