Merge branch release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / gmxlib / network.c
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <string.h>
40 #include "gmx_fatal.h"
41 #include "main.h"
42 #include "smalloc.h"
43 #include "network.h"
44 #include "copyrite.h"
45 #include "statutil.h"
46 #include <ctype.h>
47 #include "macros.h"
48
49 #include "gromacs/utility/gmxmpi.h"
50
51
52 /* The source code in this file should be thread-safe.
53       Please keep it that way. */
54
55 gmx_bool gmx_mpi_initialized(void)
56 {
57     int n;
58 #ifndef GMX_MPI
59     return 0;
60 #else
61     MPI_Initialized(&n);
62
63     return n;
64 #endif
65 }
66
67 void gmx_fill_commrec_from_mpi(t_commrec *cr)
68 {
69 #ifndef GMX_MPI
70     gmx_call("gmx_fill_commrec_from_mpi");
71 #else
72     if (!gmx_mpi_initialized())
73     {
74         gmx_comm("MPI has not been initialized properly");
75     }
76
77     cr->nnodes           = gmx_node_num();
78     cr->nodeid           = gmx_node_rank();
79     cr->sim_nodeid       = cr->nodeid;
80     cr->mpi_comm_mysim   = MPI_COMM_WORLD;
81     cr->mpi_comm_mygroup = MPI_COMM_WORLD;
82
83 #endif
84 }
85
86 t_commrec *init_commrec()
87 {
88     t_commrec    *cr;
89
90     snew(cr, 1);
91
92 #ifdef GMX_LIB_MPI
93     gmx_fill_commrec_from_mpi(cr);
94 #else
95     cr->mpi_comm_mysim   = NULL;
96     cr->mpi_comm_mygroup = NULL;
97     cr->nnodes           = 1;
98     cr->sim_nodeid       = 0;
99     cr->nodeid           = cr->sim_nodeid;
100 #endif
101
102     // TODO cr->duty should not be initialized here
103     cr->duty = (DUTY_PP | DUTY_PME);
104
105 #if defined GMX_LIB_MPI && !defined MPI_IN_PLACE_EXISTS
106     /* initialize the MPI_IN_PLACE replacement buffers */
107     snew(cr->mpb, 1);
108     cr->mpb->ibuf        = NULL;
109     cr->mpb->libuf       = NULL;
110     cr->mpb->fbuf        = NULL;
111     cr->mpb->dbuf        = NULL;
112     cr->mpb->ibuf_alloc  = 0;
113     cr->mpb->libuf_alloc = 0;
114     cr->mpb->fbuf_alloc  = 0;
115     cr->mpb->dbuf_alloc  = 0;
116 #endif
117
118     return cr;
119 }
120
121 t_commrec *reinitialize_commrec_for_this_thread(const t_commrec *cro)
122 {
123 #ifdef GMX_THREAD_MPI
124     t_commrec *cr;
125
126     /* make a thread-specific commrec */
127     snew(cr, 1);
128     /* now copy the whole thing, so settings like the number of PME nodes
129        get propagated. */
130     *cr = *cro;
131
132     /* and we start setting our own thread-specific values for things */
133     gmx_fill_commrec_from_mpi(cr);
134
135     // TODO cr->duty should not be initialized here
136     cr->duty             = (DUTY_PP | DUTY_PME);
137
138     return cr;
139 #else
140     return NULL;
141 #endif
142 }
143
144 int  gmx_node_num(void)
145 {
146 #ifndef GMX_MPI
147     return 1;
148 #else
149     int i;
150     (void) MPI_Comm_size(MPI_COMM_WORLD, &i);
151     return i;
152 #endif
153 }
154
155 int gmx_node_rank(void)
156 {
157 #ifndef GMX_MPI
158     return 0;
159 #else
160     int i;
161     (void) MPI_Comm_rank(MPI_COMM_WORLD, &i);
162     return i;
163 #endif
164 }
165
166 #if defined GMX_LIB_MPI && defined GMX_IS_BGQ
167 #include <spi/include/kernel/location.h>
168 #endif
169
170 int gmx_hostname_num()
171 {
172 #ifndef GMX_MPI
173     return 0;
174 #else
175 #ifdef GMX_THREAD_MPI
176     /* thread-MPI currently puts the thread number in the process name,
177      * we might want to change this, as this is inconsistent with what
178      * most MPI implementations would do when running on a single node.
179      */
180     return 0;
181 #else
182     int  resultlen, hostnum, i, j;
183     char mpi_hostname[MPI_MAX_PROCESSOR_NAME], hostnum_str[MPI_MAX_PROCESSOR_NAME];
184
185     MPI_Get_processor_name(mpi_hostname, &resultlen);
186 #ifdef GMX_IS_BGQ
187     Personality_t personality;
188     Kernel_GetPersonality(&personality, sizeof(personality));
189     /* Each MPI rank has a unique coordinate in a 6-dimensional space
190        (A,B,C,D,E,T), with dimensions A-E corresponding to different
191        physical nodes, and T within each node. Each node has sixteen
192        physical cores, each of which can have up to four hardware
193        threads, so 0 <= T <= 63 (but the maximum value of T depends on
194        the confituration of ranks and OpenMP threads per
195        node). However, T is irrelevant for computing a suitable return
196        value for gmx_hostname_num().
197      */
198     hostnum  = personality.Network_Config.Acoord;
199     hostnum *= personality.Network_Config.Bnodes;
200     hostnum += personality.Network_Config.Bcoord;
201     hostnum *= personality.Network_Config.Cnodes;
202     hostnum += personality.Network_Config.Ccoord;
203     hostnum *= personality.Network_Config.Dnodes;
204     hostnum += personality.Network_Config.Dcoord;
205     hostnum *= personality.Network_Config.Enodes;
206     hostnum += personality.Network_Config.Ecoord;
207 #else
208     /* This procedure can only differentiate nodes with host names
209      * that end on unique numbers.
210      */
211     i = 0;
212     j = 0;
213     /* Only parse the host name up to the first dot */
214     while (i < resultlen && mpi_hostname[i] != '.')
215     {
216         if (isdigit(mpi_hostname[i]))
217         {
218             hostnum_str[j++] = mpi_hostname[i];
219         }
220         i++;
221     }
222     hostnum_str[j] = '\0';
223     if (j == 0)
224     {
225         hostnum = 0;
226     }
227     else
228     {
229         /* Use only the last 9 decimals, so we don't overflow an int */
230         hostnum = strtol(hostnum_str + max(0, j-9), NULL, 10);
231     }
232 #endif
233
234     if (debug)
235     {
236         fprintf(debug, "In gmx_hostname_num: hostname '%s', hostnum %d\n",
237                 mpi_hostname, hostnum);
238 #ifdef GMX_IS_BGQ
239         fprintf(debug,
240                 "Torus ID A: %d / %d B: %d / %d C: %d / %d D: %d / %d E: %d / %d\nNode ID T: %d / %d core: %d / %d hardware thread: %d / %d\n",
241                 personality.Network_Config.Acoord,
242                 personality.Network_Config.Anodes,
243                 personality.Network_Config.Bcoord,
244                 personality.Network_Config.Bnodes,
245                 personality.Network_Config.Ccoord,
246                 personality.Network_Config.Cnodes,
247                 personality.Network_Config.Dcoord,
248                 personality.Network_Config.Dnodes,
249                 personality.Network_Config.Ecoord,
250                 personality.Network_Config.Enodes,
251                 Kernel_ProcessorCoreID(),
252                 16,
253                 Kernel_ProcessorID(),
254                 64,
255                 Kernel_ProcessorThreadID(),
256                 4);
257 #endif
258     }
259     return hostnum;
260 #endif
261 #endif
262 }
263
264 void gmx_setup_nodecomm(FILE gmx_unused *fplog, t_commrec *cr)
265 {
266     gmx_nodecomm_t *nc;
267     int             n, rank, hostnum, ng, ni;
268
269     /* Many MPI implementations do not optimize MPI_Allreduce
270      * (and probably also other global communication calls)
271      * for multi-core nodes connected by a network.
272      * We can optimize such communication by using one MPI call
273      * within each node and one between the nodes.
274      * For MVAPICH2 and Intel MPI this reduces the time for
275      * the global_stat communication by 25%
276      * for 2x2-core 3 GHz Woodcrest connected by mixed DDR/SDR Infiniband.
277      * B. Hess, November 2007
278      */
279
280     nc = &cr->nc;
281
282     nc->bUse = FALSE;
283 #ifndef GMX_THREAD_MPI
284 #ifdef GMX_MPI
285     MPI_Comm_size(cr->mpi_comm_mygroup, &n);
286     MPI_Comm_rank(cr->mpi_comm_mygroup, &rank);
287
288     hostnum = gmx_hostname_num();
289
290     if (debug)
291     {
292         fprintf(debug, "In gmx_setup_nodecomm: splitting communicator of size %d\n", n);
293     }
294
295
296     /* The intra-node communicator, split on node number */
297     MPI_Comm_split(cr->mpi_comm_mygroup, hostnum, rank, &nc->comm_intra);
298     MPI_Comm_rank(nc->comm_intra, &nc->rank_intra);
299     if (debug)
300     {
301         fprintf(debug, "In gmx_setup_nodecomm: node rank %d rank_intra %d\n",
302                 rank, nc->rank_intra);
303     }
304     /* The inter-node communicator, split on rank_intra.
305      * We actually only need the one for rank=0,
306      * but it is easier to create them all.
307      */
308     MPI_Comm_split(cr->mpi_comm_mygroup, nc->rank_intra, rank, &nc->comm_inter);
309     /* Check if this really created two step communication */
310     MPI_Comm_size(nc->comm_inter, &ng);
311     MPI_Comm_size(nc->comm_intra, &ni);
312     if (debug)
313     {
314         fprintf(debug, "In gmx_setup_nodecomm: groups %d, my group size %d\n",
315                 ng, ni);
316     }
317
318     if (getenv("GMX_NO_NODECOMM") == NULL &&
319         ((ng > 1 && ng < n) || (ni > 1 && ni < n)))
320     {
321         nc->bUse = TRUE;
322         if (fplog)
323         {
324             fprintf(fplog, "Using two step summing over %d groups of on average %.1f processes\n\n",
325                     ng, (real)n/(real)ng);
326         }
327         if (nc->rank_intra > 0)
328         {
329             MPI_Comm_free(&nc->comm_inter);
330         }
331     }
332     else
333     {
334         /* One group or all processes in a separate group, use normal summing */
335         MPI_Comm_free(&nc->comm_inter);
336         MPI_Comm_free(&nc->comm_intra);
337         if (debug)
338         {
339             fprintf(debug, "In gmx_setup_nodecomm: not unsing separate inter- and intra-node communicators.\n");
340         }
341     }
342 #endif
343 #else
344     /* tMPI runs only on a single node so just use the nodeid */
345     nc->rank_intra = cr->nodeid;
346 #endif
347 }
348
349 void gmx_init_intranode_counters(t_commrec *cr)
350 {
351     /* counters for PP+PME and PP-only processes on my physical node */
352     int nrank_intranode, rank_intranode;
353     int nrank_pp_intranode, rank_pp_intranode;
354     /* thread-MPI is not initialized when not running in parallel */
355 #if defined GMX_MPI && !defined GMX_THREAD_MPI
356     int nrank_world, rank_world;
357     int i, mynum, *num, *num_s, *num_pp, *num_pp_s;
358
359     MPI_Comm_size(MPI_COMM_WORLD, &nrank_world);
360     MPI_Comm_rank(MPI_COMM_WORLD, &rank_world);
361
362     /* Get the node number from the hostname to identify the nodes */
363     mynum = gmx_hostname_num();
364
365     /* We can't rely on MPI_IN_PLACE, so we need send and receive buffers */
366     snew(num,   nrank_world);
367     snew(num_s, nrank_world);
368     snew(num_pp,   nrank_world);
369     snew(num_pp_s, nrank_world);
370
371     num_s[rank_world]    = mynum;
372     num_pp_s[rank_world] = (cr->duty & DUTY_PP) ? mynum : -1;
373
374     MPI_Allreduce(num_s,    num,    nrank_world, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
375     MPI_Allreduce(num_pp_s, num_pp, nrank_world, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
376
377     nrank_intranode    = 0;
378     rank_intranode     = 0;
379     nrank_pp_intranode = 0;
380     rank_pp_intranode  = 0;
381     for (i = 0; i < nrank_world; i++)
382     {
383         if (num[i] == mynum)
384         {
385             nrank_intranode++;
386             if (i < rank_world)
387             {
388                 rank_intranode++;
389             }
390         }
391         if ((cr->duty & DUTY_PP) && num_pp[i] == mynum)
392         {
393             nrank_pp_intranode++;
394             if (i < rank_world)
395             {
396                 rank_pp_intranode++;
397             }
398         }
399     }
400     sfree(num);
401     sfree(num_s);
402     sfree(num_pp);
403     sfree(num_pp_s);
404 #else
405     /* Serial or thread-MPI code: we run within a single physical node */
406     nrank_intranode    = cr->nnodes;
407     rank_intranode     = cr->sim_nodeid;
408     nrank_pp_intranode = cr->nnodes - cr->npmenodes;
409     rank_pp_intranode  = cr->nodeid;
410 #endif
411
412     if (debug)
413     {
414         char sbuf[STRLEN];
415         if (cr->duty & DUTY_PP && cr->duty & DUTY_PME)
416         {
417             sprintf(sbuf, "PP+PME");
418         }
419         else
420         {
421             sprintf(sbuf, "%s", cr->duty & DUTY_PP ? "PP" : "PME");
422         }
423         fprintf(debug, "On %3s node %d: nrank_intranode=%d, rank_intranode=%d, "
424                 "nrank_pp_intranode=%d, rank_pp_intranode=%d\n",
425                 sbuf, cr->sim_nodeid,
426                 nrank_intranode, rank_intranode,
427                 nrank_pp_intranode, rank_pp_intranode);
428     }
429
430     cr->nrank_intranode    = nrank_intranode;
431     cr->rank_intranode     = rank_intranode;
432     cr->nrank_pp_intranode = nrank_pp_intranode;
433     cr->rank_pp_intranode  = rank_pp_intranode;
434 }
435
436
437 void gmx_barrier(const t_commrec *cr)
438 {
439 #ifndef GMX_MPI
440     gmx_call("gmx_barrier");
441 #else
442     MPI_Barrier(cr->mpi_comm_mygroup);
443 #endif
444 }
445
446 void gmx_abort(int gmx_unused noderank, int gmx_unused nnodes, int gmx_unused errorno)
447 {
448 #ifndef GMX_MPI
449     gmx_call("gmx_abort");
450 #else
451 #ifdef GMX_THREAD_MPI
452     fprintf(stderr, "Halting program %s\n", ShortProgram());
453     gmx_thanx(stderr);
454     exit(1);
455 #else
456     if (nnodes > 1)
457     {
458         fprintf(stderr, "Halting parallel program %s on CPU %d out of %d\n",
459                 ShortProgram(), noderank, nnodes);
460     }
461     else
462     {
463         fprintf(stderr, "Halting program %s\n", ShortProgram());
464     }
465
466     gmx_thanx(stderr);
467     MPI_Abort(MPI_COMM_WORLD, errorno);
468     exit(1);
469 #endif
470 #endif
471 }
472
473 void gmx_bcast(int nbytes, void *b, const t_commrec *cr)
474 {
475 #ifndef GMX_MPI
476     gmx_call("gmx_bast");
477 #else
478     MPI_Bcast(b, nbytes, MPI_BYTE, MASTERRANK(cr), cr->mpi_comm_mygroup);
479 #endif
480 }
481
482 void gmx_bcast_sim(int nbytes, void *b, const t_commrec *cr)
483 {
484 #ifndef GMX_MPI
485     gmx_call("gmx_bast");
486 #else
487     MPI_Bcast(b, nbytes, MPI_BYTE, MASTERRANK(cr), cr->mpi_comm_mysim);
488 #endif
489 }
490
491 void gmx_sumd(int nr, double r[], const t_commrec *cr)
492 {
493 #ifndef GMX_MPI
494     gmx_call("gmx_sumd");
495 #else
496 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
497     if (cr->nc.bUse)
498     {
499         if (cr->nc.rank_intra == 0)
500         {
501             /* Use two step summing. */
502             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM, 0,
503                        cr->nc.comm_intra);
504             /* Sum the roots of the internal (intra) buffers. */
505             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM,
506                           cr->nc.comm_inter);
507         }
508         else
509         {
510             /* This is here because of the silly MPI specification
511                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
512             MPI_Reduce(r, NULL, nr, MPI_DOUBLE, MPI_SUM, 0, cr->nc.comm_intra);
513         }
514         MPI_Bcast(r, nr, MPI_DOUBLE, 0, cr->nc.comm_intra);
515     }
516     else
517     {
518         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM,
519                       cr->mpi_comm_mygroup);
520     }
521 #else
522     int i;
523
524     if (nr > cr->mpb->dbuf_alloc)
525     {
526         cr->mpb->dbuf_alloc = nr;
527         srenew(cr->mpb->dbuf, cr->mpb->dbuf_alloc);
528     }
529     if (cr->nc.bUse)
530     {
531         /* Use two step summing */
532         MPI_Allreduce(r, cr->mpb->dbuf, nr, MPI_DOUBLE, MPI_SUM, cr->nc.comm_intra);
533         if (cr->nc.rank_intra == 0)
534         {
535             /* Sum with the buffers reversed */
536             MPI_Allreduce(cr->mpb->dbuf, r, nr, MPI_DOUBLE, MPI_SUM,
537                           cr->nc.comm_inter);
538         }
539         MPI_Bcast(r, nr, MPI_DOUBLE, 0, cr->nc.comm_intra);
540     }
541     else
542     {
543         MPI_Allreduce(r, cr->mpb->dbuf, nr, MPI_DOUBLE, MPI_SUM,
544                       cr->mpi_comm_mygroup);
545         for (i = 0; i < nr; i++)
546         {
547             r[i] = cr->mpb->dbuf[i];
548         }
549     }
550 #endif
551 #endif
552 }
553
554 void gmx_sumf(int nr, float r[], const t_commrec *cr)
555 {
556 #ifndef GMX_MPI
557     gmx_call("gmx_sumf");
558 #else
559 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
560     if (cr->nc.bUse)
561     {
562         /* Use two step summing.  */
563         if (cr->nc.rank_intra == 0)
564         {
565             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, 0,
566                        cr->nc.comm_intra);
567             /* Sum the roots of the internal (intra) buffers */
568             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM,
569                           cr->nc.comm_inter);
570         }
571         else
572         {
573             /* This is here because of the silly MPI specification
574                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
575             MPI_Reduce(r, NULL, nr, MPI_FLOAT, MPI_SUM, 0, cr->nc.comm_intra);
576         }
577         MPI_Bcast(r, nr, MPI_FLOAT, 0, cr->nc.comm_intra);
578     }
579     else
580     {
581         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, cr->mpi_comm_mygroup);
582     }
583 #else
584     int i;
585
586     if (nr > cr->mpb->fbuf_alloc)
587     {
588         cr->mpb->fbuf_alloc = nr;
589         srenew(cr->mpb->fbuf, cr->mpb->fbuf_alloc);
590     }
591     if (cr->nc.bUse)
592     {
593         /* Use two step summing */
594         MPI_Allreduce(r, cr->mpb->fbuf, nr, MPI_FLOAT, MPI_SUM, cr->nc.comm_intra);
595         if (cr->nc.rank_intra == 0)
596         {
597             /* Sum with the buffers reversed */
598             MPI_Allreduce(cr->mpb->fbuf, r, nr, MPI_FLOAT, MPI_SUM,
599                           cr->nc.comm_inter);
600         }
601         MPI_Bcast(r, nr, MPI_FLOAT, 0, cr->nc.comm_intra);
602     }
603     else
604     {
605         MPI_Allreduce(r, cr->mpb->fbuf, nr, MPI_FLOAT, MPI_SUM,
606                       cr->mpi_comm_mygroup);
607         for (i = 0; i < nr; i++)
608         {
609             r[i] = cr->mpb->fbuf[i];
610         }
611     }
612 #endif
613 #endif
614 }
615
616 void gmx_sumi(int nr, int r[], const t_commrec *cr)
617 {
618 #ifndef GMX_MPI
619     gmx_call("gmx_sumi");
620 #else
621 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
622     if (cr->nc.bUse)
623     {
624         /* Use two step summing */
625         if (cr->nc.rank_intra == 0)
626         {
627             MPI_Reduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, 0, cr->nc.comm_intra);
628             /* Sum with the buffers reversed */
629             MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, cr->nc.comm_inter);
630         }
631         else
632         {
633             /* This is here because of the silly MPI specification
634                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
635             MPI_Reduce(r, NULL, nr, MPI_INT, MPI_SUM, 0, cr->nc.comm_intra);
636         }
637         MPI_Bcast(r, nr, MPI_INT, 0, cr->nc.comm_intra);
638     }
639     else
640     {
641         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, cr->mpi_comm_mygroup);
642     }
643 #else
644     int i;
645
646     if (nr > cr->mpb->ibuf_alloc)
647     {
648         cr->mpb->ibuf_alloc = nr;
649         srenew(cr->mpb->ibuf, cr->mpb->ibuf_alloc);
650     }
651     if (cr->nc.bUse)
652     {
653         /* Use two step summing */
654         MPI_Allreduce(r, cr->mpb->ibuf, nr, MPI_INT, MPI_SUM, cr->nc.comm_intra);
655         if (cr->nc.rank_intra == 0)
656         {
657             /* Sum with the buffers reversed */
658             MPI_Allreduce(cr->mpb->ibuf, r, nr, MPI_INT, MPI_SUM, cr->nc.comm_inter);
659         }
660         MPI_Bcast(r, nr, MPI_INT, 0, cr->nc.comm_intra);
661     }
662     else
663     {
664         MPI_Allreduce(r, cr->mpb->ibuf, nr, MPI_INT, MPI_SUM, cr->mpi_comm_mygroup);
665         for (i = 0; i < nr; i++)
666         {
667             r[i] = cr->mpb->ibuf[i];
668         }
669     }
670 #endif
671 #endif
672 }
673
674 void gmx_sumli(int nr, gmx_large_int_t r[], const t_commrec *cr)
675 {
676 #ifndef GMX_MPI
677     gmx_call("gmx_sumli");
678 #else
679 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
680     if (cr->nc.bUse)
681     {
682         /* Use two step summing */
683         if (cr->nc.rank_intra == 0)
684         {
685             MPI_Reduce(MPI_IN_PLACE, r, nr, GMX_MPI_LARGE_INT, MPI_SUM, 0,
686                        cr->nc.comm_intra);
687             /* Sum with the buffers reversed */
688             MPI_Allreduce(MPI_IN_PLACE, r, nr, GMX_MPI_LARGE_INT, MPI_SUM,
689                           cr->nc.comm_inter);
690         }
691         else
692         {
693             /* This is here because of the silly MPI specification
694                 that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
695             MPI_Reduce(r, NULL, nr, GMX_MPI_LARGE_INT, MPI_SUM, 0, cr->nc.comm_intra);
696         }
697         MPI_Bcast(r, nr, GMX_MPI_LARGE_INT, 0, cr->nc.comm_intra);
698     }
699     else
700     {
701         MPI_Allreduce(MPI_IN_PLACE, r, nr, GMX_MPI_LARGE_INT, MPI_SUM, cr->mpi_comm_mygroup);
702     }
703 #else
704     int i;
705
706     if (nr > cr->mpb->libuf_alloc)
707     {
708         cr->mpb->libuf_alloc = nr;
709         srenew(cr->mpb->libuf, cr->mpb->libuf_alloc);
710     }
711     if (cr->nc.bUse)
712     {
713         /* Use two step summing */
714         MPI_Allreduce(r, cr->mpb->libuf, nr, GMX_MPI_LARGE_INT, MPI_SUM,
715                       cr->nc.comm_intra);
716         if (cr->nc.rank_intra == 0)
717         {
718             /* Sum with the buffers reversed */
719             MPI_Allreduce(cr->mpb->libuf, r, nr, GMX_MPI_LARGE_INT, MPI_SUM,
720                           cr->nc.comm_inter);
721         }
722         MPI_Bcast(r, nr, GMX_MPI_LARGE_INT, 0, cr->nc.comm_intra);
723     }
724     else
725     {
726         MPI_Allreduce(r, cr->mpb->libuf, nr, GMX_MPI_LARGE_INT, MPI_SUM,
727                       cr->mpi_comm_mygroup);
728         for (i = 0; i < nr; i++)
729         {
730             r[i] = cr->mpb->libuf[i];
731         }
732     }
733 #endif
734 #endif
735 }
736
737
738
739 #ifdef GMX_MPI
740 void gmx_sumd_comm(int nr, double r[], MPI_Comm mpi_comm)
741 {
742 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
743     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM, mpi_comm);
744 #else
745     /* this function is only used in code that is not performance critical,
746        (during setup, when comm_rec is not the appropriate communication
747        structure), so this isn't as bad as it looks. */
748     double *buf;
749     int     i;
750
751     snew(buf, nr);
752     MPI_Allreduce(r, buf, nr, MPI_DOUBLE, MPI_SUM, mpi_comm);
753     for (i = 0; i < nr; i++)
754     {
755         r[i] = buf[i];
756     }
757     sfree(buf);
758 #endif
759 }
760 #endif
761
762 #ifdef GMX_MPI
763 void gmx_sumf_comm(int nr, float r[], MPI_Comm mpi_comm)
764 {
765 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
766     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, mpi_comm);
767 #else
768     /* this function is only used in code that is not performance critical,
769        (during setup, when comm_rec is not the appropriate communication
770        structure), so this isn't as bad as it looks. */
771     float *buf;
772     int    i;
773
774     snew(buf, nr);
775     MPI_Allreduce(r, buf, nr, MPI_FLOAT, MPI_SUM, mpi_comm);
776     for (i = 0; i < nr; i++)
777     {
778         r[i] = buf[i];
779     }
780     sfree(buf);
781 #endif
782 }
783 #endif
784
785 void gmx_sumd_sim(int nr, double r[], const gmx_multisim_t *ms)
786 {
787 #ifndef GMX_MPI
788     gmx_call("gmx_sumd_sim");
789 #else
790     gmx_sumd_comm(nr, r, ms->mpi_comm_masters);
791 #endif
792 }
793
794 void gmx_sumf_sim(int nr, float r[], const gmx_multisim_t *ms)
795 {
796 #ifndef GMX_MPI
797     gmx_call("gmx_sumf_sim");
798 #else
799     gmx_sumf_comm(nr, r, ms->mpi_comm_masters);
800 #endif
801 }
802
803 void gmx_sumi_sim(int nr, int r[], const gmx_multisim_t *ms)
804 {
805 #ifndef GMX_MPI
806     gmx_call("gmx_sumi_sim");
807 #else
808 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
809     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, ms->mpi_comm_masters);
810 #else
811     /* this is thread-unsafe, but it will do for now: */
812     int i;
813
814     if (nr > ms->mpb->ibuf_alloc)
815     {
816         ms->mpb->ibuf_alloc = nr;
817         srenew(ms->mpb->ibuf, ms->mpb->ibuf_alloc);
818     }
819     MPI_Allreduce(r, ms->mpb->ibuf, nr, MPI_INT, MPI_SUM, ms->mpi_comm_masters);
820     for (i = 0; i < nr; i++)
821     {
822         r[i] = ms->mpb->ibuf[i];
823     }
824 #endif
825 #endif
826 }
827
828 void gmx_sumli_sim(int nr, gmx_large_int_t r[], const gmx_multisim_t *ms)
829 {
830 #ifndef GMX_MPI
831     gmx_call("gmx_sumli_sim");
832 #else
833 #if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREAD_MPI)
834     MPI_Allreduce(MPI_IN_PLACE, r, nr, GMX_MPI_LARGE_INT, MPI_SUM,
835                   ms->mpi_comm_masters);
836 #else
837     /* this is thread-unsafe, but it will do for now: */
838     int i;
839
840     if (nr > ms->mpb->libuf_alloc)
841     {
842         ms->mpb->libuf_alloc = nr;
843         srenew(ms->mpb->libuf, ms->mpb->libuf_alloc);
844     }
845     MPI_Allreduce(r, ms->mpb->libuf, nr, GMX_MPI_LARGE_INT, MPI_SUM,
846                   ms->mpi_comm_masters);
847     for (i = 0; i < nr; i++)
848     {
849         r[i] = ms->mpb->libuf[i];
850     }
851 #endif
852 #endif
853 }