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