Merge branch release-2016
[alexxy/gromacs.git] / src / gromacs / gmxlib / network.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "network.h"
40
41 #include "config.h"
42
43 #include <cctype>
44 #include <cstdarg>
45 #include <cstdlib>
46 #include <cstring>
47
48 #include "gromacs/commandline/filenm.h"
49 #include "gromacs/mdtypes/commrec.h"
50 #include "gromacs/utility/basenetwork.h"
51 #include "gromacs/utility/cstringutil.h"
52 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/futil.h"
54 #include "gromacs/utility/gmxmpi.h"
55 #include "gromacs/utility/smalloc.h"
56
57 /* The source code in this file should be thread-safe.
58       Please keep it that way. */
59
60 void gmx_fill_commrec_from_mpi(t_commrec gmx_unused *cr)
61 {
62 #if !GMX_MPI
63     gmx_call("gmx_fill_commrec_from_mpi");
64 #else
65     if (!gmx_mpi_initialized())
66     {
67         gmx_comm("MPI has not been initialized properly");
68     }
69
70     cr->nnodes           = gmx_node_num();
71     cr->nodeid           = gmx_node_rank();
72     if (PAR(cr) || MULTISIM(cr))
73     {
74         MPI_Comm_split(MPI_COMM_WORLD, gmx_physicalnode_id_hash(), cr->nodeid, &cr->mpi_comm_physicalnode);
75     }
76     cr->sim_nodeid       = cr->nodeid;
77     cr->mpi_comm_mysim   = MPI_COMM_WORLD;
78     cr->mpi_comm_mygroup = MPI_COMM_WORLD;
79
80 #endif
81 }
82
83 t_commrec *init_commrec()
84 {
85     t_commrec    *cr;
86
87     snew(cr, 1);
88
89 #if GMX_LIB_MPI
90     gmx_fill_commrec_from_mpi(cr);
91 #else
92     cr->mpi_comm_mysim   = nullptr;
93     cr->mpi_comm_mygroup = nullptr;
94     cr->nnodes           = 1;
95     cr->sim_nodeid       = 0;
96     cr->nodeid           = cr->sim_nodeid;
97 #endif
98
99     // TODO cr->duty should not be initialized here
100     cr->duty = (DUTY_PP | DUTY_PME);
101
102 #if GMX_MPI && !MPI_IN_PLACE_EXISTS
103     /* initialize the MPI_IN_PLACE replacement buffers */
104     snew(cr->mpb, 1);
105     cr->mpb->ibuf        = NULL;
106     cr->mpb->libuf       = NULL;
107     cr->mpb->fbuf        = NULL;
108     cr->mpb->dbuf        = NULL;
109     cr->mpb->ibuf_alloc  = 0;
110     cr->mpb->libuf_alloc = 0;
111     cr->mpb->fbuf_alloc  = 0;
112     cr->mpb->dbuf_alloc  = 0;
113 #endif
114
115     return cr;
116 }
117
118 static void done_mpi_in_place_buf(mpi_in_place_buf_t *buf)
119 {
120     if (nullptr != buf)
121     {
122         sfree(buf->ibuf);
123         sfree(buf->libuf);
124         sfree(buf->fbuf);
125         sfree(buf->dbuf);
126         sfree(buf);
127     }
128 }
129
130 void done_commrec(t_commrec *cr)
131 {
132 #if GMX_MPI
133     if (PAR(cr) || MULTISIM(cr))
134     {
135         MPI_Comm_free(&cr->mpi_comm_physicalnode);
136     }
137 #endif
138     if (nullptr != cr->dd)
139     {
140         // TODO: implement
141         // done_domdec(cr->dd);
142     }
143     if (nullptr != cr->ms)
144     {
145         done_mpi_in_place_buf(cr->ms->mpb);
146         sfree(cr->ms);
147     }
148     done_mpi_in_place_buf(cr->mpb);
149     sfree(cr);
150 }
151
152 t_commrec *reinitialize_commrec_for_this_thread(const t_commrec gmx_unused *cro)
153 {
154 #if GMX_THREAD_MPI
155     t_commrec *cr;
156
157     /* make a thread-specific commrec */
158     snew(cr, 1);
159     /* now copy the whole thing, so settings like the number of PME nodes
160        get propagated. */
161     *cr = *cro;
162
163     /* and we start setting our own thread-specific values for things */
164     gmx_fill_commrec_from_mpi(cr);
165
166     // TODO cr->duty should not be initialized here
167     cr->duty             = (DUTY_PP | DUTY_PME);
168
169     return cr;
170 #else
171     return nullptr;
172 #endif
173 }
174
175 void gmx_setup_nodecomm(FILE gmx_unused *fplog, t_commrec *cr)
176 {
177     gmx_nodecomm_t *nc;
178
179     /* Many MPI implementations do not optimize MPI_Allreduce
180      * (and probably also other global communication calls)
181      * for multi-core nodes connected by a network.
182      * We can optimize such communication by using one MPI call
183      * within each node and one between the nodes.
184      * For MVAPICH2 and Intel MPI this reduces the time for
185      * the global_stat communication by 25%
186      * for 2x2-core 3 GHz Woodcrest connected by mixed DDR/SDR Infiniband.
187      * B. Hess, November 2007
188      */
189
190     nc = &cr->nc;
191
192     nc->bUse = FALSE;
193 #if !GMX_THREAD_MPI
194 #if GMX_MPI
195     int n, rank;
196
197     MPI_Comm_size(cr->mpi_comm_mygroup, &n);
198     MPI_Comm_rank(cr->mpi_comm_mygroup, &rank);
199
200     int nodehash = gmx_physicalnode_id_hash();
201
202     if (debug)
203     {
204         fprintf(debug, "In gmx_setup_nodecomm: splitting communicator of size %d\n", n);
205     }
206
207
208     /* The intra-node communicator, split on node number */
209     MPI_Comm_split(cr->mpi_comm_mygroup, nodehash, rank, &nc->comm_intra);
210     MPI_Comm_rank(nc->comm_intra, &nc->rank_intra);
211     if (debug)
212     {
213         fprintf(debug, "In gmx_setup_nodecomm: node ID %d rank within node %d\n",
214                 rank, nc->rank_intra);
215     }
216     /* The inter-node communicator, split on rank_intra.
217      * We actually only need the one for rank=0,
218      * but it is easier to create them all.
219      */
220     MPI_Comm_split(cr->mpi_comm_mygroup, nc->rank_intra, rank, &nc->comm_inter);
221     /* Check if this really created two step communication */
222     int ng, ni;
223
224     MPI_Comm_size(nc->comm_inter, &ng);
225     MPI_Comm_size(nc->comm_intra, &ni);
226     if (debug)
227     {
228         fprintf(debug, "In gmx_setup_nodecomm: groups %d, my group size %d\n",
229                 ng, ni);
230     }
231
232     if (getenv("GMX_NO_NODECOMM") == nullptr &&
233         ((ng > 1 && ng < n) || (ni > 1 && ni < n)))
234     {
235         nc->bUse = TRUE;
236         if (fplog)
237         {
238             fprintf(fplog, "Using two step summing over %d groups of on average %.1f ranks\n\n",
239                     ng, (real)n/(real)ng);
240         }
241         if (nc->rank_intra > 0)
242         {
243             MPI_Comm_free(&nc->comm_inter);
244         }
245     }
246     else
247     {
248         /* One group or all processes in a separate group, use normal summing */
249         MPI_Comm_free(&nc->comm_inter);
250         MPI_Comm_free(&nc->comm_intra);
251         if (debug)
252         {
253             fprintf(debug, "In gmx_setup_nodecomm: not unsing separate inter- and intra-node communicators.\n");
254         }
255     }
256 #endif
257 #else
258     /* tMPI runs only on a single node so just use the nodeid */
259     nc->rank_intra = cr->nodeid;
260 #endif
261 }
262
263 void gmx_init_intranode_counters(t_commrec *cr)
264 {
265     /* counters for PP+PME and PP-only processes on my physical node */
266     int nrank_intranode, rank_intranode;
267     int nrank_pp_intranode, rank_pp_intranode;
268     /* thread-MPI is not initialized when not running in parallel */
269 #if GMX_MPI && !GMX_THREAD_MPI
270     int nrank_world, rank_world;
271     int i, myhash, *hash, *hash_s, *hash_pp, *hash_pp_s;
272
273     MPI_Comm_size(MPI_COMM_WORLD, &nrank_world);
274     MPI_Comm_rank(MPI_COMM_WORLD, &rank_world);
275
276     /* Get a (hopefully unique) hash that identifies our physical node */
277     myhash = gmx_physicalnode_id_hash();
278
279     /* We can't rely on MPI_IN_PLACE, so we need send and receive buffers */
280     snew(hash,   nrank_world);
281     snew(hash_s, nrank_world);
282     snew(hash_pp,   nrank_world);
283     snew(hash_pp_s, nrank_world);
284
285     hash_s[rank_world]    = myhash;
286     hash_pp_s[rank_world] = (cr->duty & DUTY_PP) ? myhash : -1;
287
288     MPI_Allreduce(hash_s,    hash,    nrank_world, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
289     MPI_Allreduce(hash_pp_s, hash_pp, nrank_world, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
290
291     nrank_intranode    = 0;
292     rank_intranode     = 0;
293     nrank_pp_intranode = 0;
294     rank_pp_intranode  = 0;
295     for (i = 0; i < nrank_world; i++)
296     {
297         if (hash[i] == myhash)
298         {
299             nrank_intranode++;
300             if (i < rank_world)
301             {
302                 rank_intranode++;
303             }
304         }
305         if (hash_pp[i] == myhash)
306         {
307             nrank_pp_intranode++;
308             if ((cr->duty & DUTY_PP) && i < rank_world)
309             {
310                 rank_pp_intranode++;
311             }
312         }
313     }
314     sfree(hash);
315     sfree(hash_s);
316     sfree(hash_pp);
317     sfree(hash_pp_s);
318 #else
319     /* Serial or thread-MPI code: we run within a single physical node */
320     nrank_intranode    = cr->nnodes;
321     rank_intranode     = cr->sim_nodeid;
322     nrank_pp_intranode = cr->nnodes - cr->npmenodes;
323     rank_pp_intranode  = cr->nodeid;
324 #endif
325
326     if (debug)
327     {
328         char sbuf[STRLEN];
329         if ((cr->duty & DUTY_PP) && (cr->duty & DUTY_PME))
330         {
331             sprintf(sbuf, "PP+PME");
332         }
333         else
334         {
335             sprintf(sbuf, "%s", (cr->duty & DUTY_PP) ? "PP" : "PME");
336         }
337         fprintf(debug, "On %3s rank %d: nrank_intranode=%d, rank_intranode=%d, "
338                 "nrank_pp_intranode=%d, rank_pp_intranode=%d\n",
339                 sbuf, cr->sim_nodeid,
340                 nrank_intranode, rank_intranode,
341                 nrank_pp_intranode, rank_pp_intranode);
342     }
343
344     cr->nrank_intranode    = nrank_intranode;
345     cr->rank_intranode     = rank_intranode;
346     cr->nrank_pp_intranode = nrank_pp_intranode;
347     cr->rank_pp_intranode  = rank_pp_intranode;
348 }
349
350
351 void gmx_barrier(const t_commrec gmx_unused *cr)
352 {
353 #if !GMX_MPI
354     gmx_call("gmx_barrier");
355 #else
356     MPI_Barrier(cr->mpi_comm_mygroup);
357 #endif
358 }
359
360 void gmx_barrier_physical_node(const t_commrec gmx_unused *cr)
361 {
362 #if !GMX_MPI
363     gmx_call("gmx_barrier_physical_node");
364 #else
365     MPI_Barrier(cr->mpi_comm_physicalnode);
366 #endif
367 }
368
369 void gmx_bcast(int gmx_unused nbytes, void gmx_unused *b, const t_commrec gmx_unused *cr)
370 {
371 #if !GMX_MPI
372     gmx_call("gmx_bast");
373 #else
374     MPI_Bcast(b, nbytes, MPI_BYTE, MASTERRANK(cr), cr->mpi_comm_mygroup);
375 #endif
376 }
377
378 void gmx_bcast_sim(int gmx_unused nbytes, void gmx_unused *b, const t_commrec gmx_unused *cr)
379 {
380 #if !GMX_MPI
381     gmx_call("gmx_bast");
382 #else
383     MPI_Bcast(b, nbytes, MPI_BYTE, MASTERRANK(cr), cr->mpi_comm_mysim);
384 #endif
385 }
386
387 void gmx_sumd(int gmx_unused nr, double gmx_unused r[], const t_commrec gmx_unused *cr)
388 {
389 #if !GMX_MPI
390     gmx_call("gmx_sumd");
391 #else
392 #if MPI_IN_PLACE_EXISTS
393     if (cr->nc.bUse)
394     {
395         if (cr->nc.rank_intra == 0)
396         {
397             /* Use two step summing. */
398             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM, 0,
399                        cr->nc.comm_intra);
400             /* Sum the roots of the internal (intra) buffers. */
401             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM,
402                           cr->nc.comm_inter);
403         }
404         else
405         {
406             /* This is here because of the silly MPI specification
407                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
408             MPI_Reduce(r, nullptr, nr, MPI_DOUBLE, MPI_SUM, 0, cr->nc.comm_intra);
409         }
410         MPI_Bcast(r, nr, MPI_DOUBLE, 0, cr->nc.comm_intra);
411     }
412     else
413     {
414         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM,
415                       cr->mpi_comm_mygroup);
416     }
417 #else
418     int i;
419
420     if (nr > cr->mpb->dbuf_alloc)
421     {
422         cr->mpb->dbuf_alloc = nr;
423         srenew(cr->mpb->dbuf, cr->mpb->dbuf_alloc);
424     }
425     if (cr->nc.bUse)
426     {
427         /* Use two step summing */
428         MPI_Allreduce(r, cr->mpb->dbuf, nr, MPI_DOUBLE, MPI_SUM, cr->nc.comm_intra);
429         if (cr->nc.rank_intra == 0)
430         {
431             /* Sum with the buffers reversed */
432             MPI_Allreduce(cr->mpb->dbuf, r, nr, MPI_DOUBLE, MPI_SUM,
433                           cr->nc.comm_inter);
434         }
435         MPI_Bcast(r, nr, MPI_DOUBLE, 0, cr->nc.comm_intra);
436     }
437     else
438     {
439         MPI_Allreduce(r, cr->mpb->dbuf, nr, MPI_DOUBLE, MPI_SUM,
440                       cr->mpi_comm_mygroup);
441         for (i = 0; i < nr; i++)
442         {
443             r[i] = cr->mpb->dbuf[i];
444         }
445     }
446 #endif
447 #endif
448 }
449
450 void gmx_sumf(int gmx_unused nr, float gmx_unused r[], const t_commrec gmx_unused *cr)
451 {
452 #if !GMX_MPI
453     gmx_call("gmx_sumf");
454 #else
455 #if MPI_IN_PLACE_EXISTS
456     if (cr->nc.bUse)
457     {
458         /* Use two step summing.  */
459         if (cr->nc.rank_intra == 0)
460         {
461             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, 0,
462                        cr->nc.comm_intra);
463             /* Sum the roots of the internal (intra) buffers */
464             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM,
465                           cr->nc.comm_inter);
466         }
467         else
468         {
469             /* This is here because of the silly MPI specification
470                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
471             MPI_Reduce(r, nullptr, nr, MPI_FLOAT, MPI_SUM, 0, cr->nc.comm_intra);
472         }
473         MPI_Bcast(r, nr, MPI_FLOAT, 0, cr->nc.comm_intra);
474     }
475     else
476     {
477         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, cr->mpi_comm_mygroup);
478     }
479 #else
480     int i;
481
482     if (nr > cr->mpb->fbuf_alloc)
483     {
484         cr->mpb->fbuf_alloc = nr;
485         srenew(cr->mpb->fbuf, cr->mpb->fbuf_alloc);
486     }
487     if (cr->nc.bUse)
488     {
489         /* Use two step summing */
490         MPI_Allreduce(r, cr->mpb->fbuf, nr, MPI_FLOAT, MPI_SUM, cr->nc.comm_intra);
491         if (cr->nc.rank_intra == 0)
492         {
493             /* Sum with the buffers reversed */
494             MPI_Allreduce(cr->mpb->fbuf, r, nr, MPI_FLOAT, MPI_SUM,
495                           cr->nc.comm_inter);
496         }
497         MPI_Bcast(r, nr, MPI_FLOAT, 0, cr->nc.comm_intra);
498     }
499     else
500     {
501         MPI_Allreduce(r, cr->mpb->fbuf, nr, MPI_FLOAT, MPI_SUM,
502                       cr->mpi_comm_mygroup);
503         for (i = 0; i < nr; i++)
504         {
505             r[i] = cr->mpb->fbuf[i];
506         }
507     }
508 #endif
509 #endif
510 }
511
512 void gmx_sumi(int gmx_unused nr, int gmx_unused r[], const t_commrec gmx_unused *cr)
513 {
514 #if !GMX_MPI
515     gmx_call("gmx_sumi");
516 #else
517 #if MPI_IN_PLACE_EXISTS
518     if (cr->nc.bUse)
519     {
520         /* Use two step summing */
521         if (cr->nc.rank_intra == 0)
522         {
523             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, 0, cr->nc.comm_intra);
524             /* Sum with the buffers reversed */
525             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, cr->nc.comm_inter);
526         }
527         else
528         {
529             /* This is here because of the silly MPI specification
530                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
531             MPI_Reduce(r, nullptr, nr, MPI_INT, MPI_SUM, 0, cr->nc.comm_intra);
532         }
533         MPI_Bcast(r, nr, MPI_INT, 0, cr->nc.comm_intra);
534     }
535     else
536     {
537         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, cr->mpi_comm_mygroup);
538     }
539 #else
540     int i;
541
542     if (nr > cr->mpb->ibuf_alloc)
543     {
544         cr->mpb->ibuf_alloc = nr;
545         srenew(cr->mpb->ibuf, cr->mpb->ibuf_alloc);
546     }
547     if (cr->nc.bUse)
548     {
549         /* Use two step summing */
550         MPI_Allreduce(r, cr->mpb->ibuf, nr, MPI_INT, MPI_SUM, cr->nc.comm_intra);
551         if (cr->nc.rank_intra == 0)
552         {
553             /* Sum with the buffers reversed */
554             MPI_Allreduce(cr->mpb->ibuf, r, nr, MPI_INT, MPI_SUM, cr->nc.comm_inter);
555         }
556         MPI_Bcast(r, nr, MPI_INT, 0, cr->nc.comm_intra);
557     }
558     else
559     {
560         MPI_Allreduce(r, cr->mpb->ibuf, nr, MPI_INT, MPI_SUM, cr->mpi_comm_mygroup);
561         for (i = 0; i < nr; i++)
562         {
563             r[i] = cr->mpb->ibuf[i];
564         }
565     }
566 #endif
567 #endif
568 }
569
570 void gmx_sumli(int gmx_unused nr, gmx_int64_t gmx_unused r[], const t_commrec gmx_unused *cr)
571 {
572 #if !GMX_MPI
573     gmx_call("gmx_sumli");
574 #else
575 #if MPI_IN_PLACE_EXISTS
576     if (cr->nc.bUse)
577     {
578         /* Use two step summing */
579         if (cr->nc.rank_intra == 0)
580         {
581             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_INT64_T, MPI_SUM, 0,
582                        cr->nc.comm_intra);
583             /* Sum with the buffers reversed */
584             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT64_T, MPI_SUM,
585                           cr->nc.comm_inter);
586         }
587         else
588         {
589             /* This is here because of the silly MPI specification
590                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
591             MPI_Reduce(r, nullptr, nr, MPI_INT64_T, MPI_SUM, 0, cr->nc.comm_intra);
592         }
593         MPI_Bcast(r, nr, MPI_INT64_T, 0, cr->nc.comm_intra);
594     }
595     else
596     {
597         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT64_T, MPI_SUM, cr->mpi_comm_mygroup);
598     }
599 #else
600     int i;
601
602     if (nr > cr->mpb->libuf_alloc)
603     {
604         cr->mpb->libuf_alloc = nr;
605         srenew(cr->mpb->libuf, cr->mpb->libuf_alloc);
606     }
607     if (cr->nc.bUse)
608     {
609         /* Use two step summing */
610         MPI_Allreduce(r, cr->mpb->libuf, nr, MPI_INT64_T, MPI_SUM,
611                       cr->nc.comm_intra);
612         if (cr->nc.rank_intra == 0)
613         {
614             /* Sum with the buffers reversed */
615             MPI_Allreduce(cr->mpb->libuf, r, nr, MPI_INT64_T, MPI_SUM,
616                           cr->nc.comm_inter);
617         }
618         MPI_Bcast(r, nr, MPI_INT64_T, 0, cr->nc.comm_intra);
619     }
620     else
621     {
622         MPI_Allreduce(r, cr->mpb->libuf, nr, MPI_INT64_T, MPI_SUM,
623                       cr->mpi_comm_mygroup);
624         for (i = 0; i < nr; i++)
625         {
626             r[i] = cr->mpb->libuf[i];
627         }
628     }
629 #endif
630 #endif
631 }
632
633
634
635 #if GMX_MPI
636 static void gmx_sumd_comm(int nr, double r[], MPI_Comm mpi_comm)
637 {
638 #if MPI_IN_PLACE_EXISTS
639     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM, mpi_comm);
640 #else
641     /* this function is only used in code that is not performance critical,
642        (during setup, when comm_rec is not the appropriate communication
643        structure), so this isn't as bad as it looks. */
644     double *buf;
645     int     i;
646
647     snew(buf, nr);
648     MPI_Allreduce(r, buf, nr, MPI_DOUBLE, MPI_SUM, mpi_comm);
649     for (i = 0; i < nr; i++)
650     {
651         r[i] = buf[i];
652     }
653     sfree(buf);
654 #endif
655 }
656 #endif
657
658 #if GMX_MPI
659 static void gmx_sumf_comm(int nr, float r[], MPI_Comm mpi_comm)
660 {
661 #if MPI_IN_PLACE_EXISTS
662     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, mpi_comm);
663 #else
664     /* this function is only used in code that is not performance critical,
665        (during setup, when comm_rec is not the appropriate communication
666        structure), so this isn't as bad as it looks. */
667     float *buf;
668     int    i;
669
670     snew(buf, nr);
671     MPI_Allreduce(r, buf, nr, MPI_FLOAT, MPI_SUM, mpi_comm);
672     for (i = 0; i < nr; i++)
673     {
674         r[i] = buf[i];
675     }
676     sfree(buf);
677 #endif
678 }
679 #endif
680
681 void gmx_sumd_sim(int gmx_unused nr, double gmx_unused r[], const gmx_multisim_t gmx_unused *ms)
682 {
683 #if !GMX_MPI
684     gmx_call("gmx_sumd_sim");
685 #else
686     gmx_sumd_comm(nr, r, ms->mpi_comm_masters);
687 #endif
688 }
689
690 void gmx_sumf_sim(int gmx_unused nr, float gmx_unused r[], const gmx_multisim_t gmx_unused *ms)
691 {
692 #if !GMX_MPI
693     gmx_call("gmx_sumf_sim");
694 #else
695     gmx_sumf_comm(nr, r, ms->mpi_comm_masters);
696 #endif
697 }
698
699 void gmx_sumi_sim(int gmx_unused nr, int gmx_unused r[], const gmx_multisim_t gmx_unused *ms)
700 {
701 #if !GMX_MPI
702     gmx_call("gmx_sumi_sim");
703 #else
704 #if MPI_IN_PLACE_EXISTS
705     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, ms->mpi_comm_masters);
706 #else
707     /* this is thread-unsafe, but it will do for now: */
708     int i;
709
710     if (nr > ms->mpb->ibuf_alloc)
711     {
712         ms->mpb->ibuf_alloc = nr;
713         srenew(ms->mpb->ibuf, ms->mpb->ibuf_alloc);
714     }
715     MPI_Allreduce(r, ms->mpb->ibuf, nr, MPI_INT, MPI_SUM, ms->mpi_comm_masters);
716     for (i = 0; i < nr; i++)
717     {
718         r[i] = ms->mpb->ibuf[i];
719     }
720 #endif
721 #endif
722 }
723
724 void gmx_sumli_sim(int gmx_unused nr, gmx_int64_t gmx_unused r[], const gmx_multisim_t gmx_unused *ms)
725 {
726 #if !GMX_MPI
727     gmx_call("gmx_sumli_sim");
728 #else
729 #if MPI_IN_PLACE_EXISTS
730     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT64_T, MPI_SUM,
731                   ms->mpi_comm_masters);
732 #else
733     /* this is thread-unsafe, but it will do for now: */
734     int i;
735
736     if (nr > ms->mpb->libuf_alloc)
737     {
738         ms->mpb->libuf_alloc = nr;
739         srenew(ms->mpb->libuf, ms->mpb->libuf_alloc);
740     }
741     MPI_Allreduce(r, ms->mpb->libuf, nr, MPI_INT64_T, MPI_SUM,
742                   ms->mpi_comm_masters);
743     for (i = 0; i < nr; i++)
744     {
745         r[i] = ms->mpb->libuf[i];
746     }
747 #endif
748 #endif
749 }
750
751 const char *opt2fn_master(const char *opt, int nfile, const t_filenm fnm[],
752                           t_commrec *cr)
753 {
754     return SIMMASTER(cr) ? opt2fn(opt, nfile, fnm) : nullptr;
755 }
756
757 void gmx_fatal_collective(int f_errno, const char *file, int line,
758                           MPI_Comm comm, gmx_bool bMaster,
759                           const char *fmt, ...)
760 {
761     va_list  ap;
762     gmx_bool bFinalize;
763 #if GMX_MPI
764     int      result;
765     /* Check if we are calling on all processes in MPI_COMM_WORLD */
766     MPI_Comm_compare(comm, MPI_COMM_WORLD, &result);
767     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
768     bFinalize = (result != MPI_UNEQUAL);
769 #else
770     GMX_UNUSED_VALUE(comm);
771     bFinalize = TRUE;
772 #endif
773
774     va_start(ap, fmt);
775     gmx_fatal_mpi_va(f_errno, file, line, bMaster, bFinalize, fmt, ap);
776     va_end(ap);
777 }