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