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