Code beautification with uncrustify
[alexxy/gromacs.git] / src / gromacs / gmxlib / thread_mpi / topology.c
1 /*
2    This source code file is part of thread_mpi.
3    Written by Sander Pronk, Erik Lindahl, and possibly others.
4
5    Copyright (c) 2009, Sander Pronk, Erik Lindahl.
6    All rights reserved.
7
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions are met:
10    1) Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    2) Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15    3) Neither the name of the copyright holders nor the
16    names of its contributors may be used to endorse or promote products
17    derived from this software without specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22    DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30    If you want to redistribute modifications, please consider that
31    scientific software is very special. Version control is crucial -
32    bugs must be traceable. We will be happy to consider code for
33    inclusion in the official distribution, but derived work should not
34    be called official thread_mpi. Details are found in the README & COPYING
35    files.
36  */
37
38 #ifdef HAVE_TMPI_CONFIG_H
39 #include "tmpi_config.h"
40 #endif
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <stdarg.h>
55 #include <string.h>
56
57
58 #include "impl.h"
59
60
61 /* topology functions */
62 int tMPI_Topo_test(tMPI_Comm comm, int *status)
63 {
64 #ifdef TMPI_TRACE
65     tMPI_Trace_print("tMPI_Topo_test(%p, %p)", comm, status);
66 #endif
67
68     if (!comm)
69     {
70         return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
71     }
72
73     if (comm->cart)
74     {
75         *status = TMPI_CART;
76     }
77     /*else if (comm->graph)
78         status=MPI_GRAPH;*/
79     else
80     {
81         *status = TMPI_UNDEFINED;
82     }
83
84     return TMPI_SUCCESS;
85 }
86
87 int tMPI_Cartdim_get(tMPI_Comm comm, int *ndims)
88 {
89 #ifdef TMPI_TRACE
90     tMPI_Trace_print("tMPI_Cartdim_get(%p, %p)", comm, ndims);
91 #endif
92     if (!comm)
93     {
94         return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
95     }
96     if (!comm->cart || comm->cart->ndims == 0)
97     {
98         return TMPI_SUCCESS;
99     }
100     *ndims = comm->cart->ndims;
101     return TMPI_SUCCESS;
102 }
103
104
105 int tMPI_Cart_get(tMPI_Comm comm, int maxdims, int *dims, int *periods,
106                   int *coords)
107 {
108     int i;
109     int myrank = tMPI_Comm_seek_rank(comm, tMPI_Get_current());
110
111 #ifdef TMPI_TRACE
112     tMPI_Trace_print("tMPI_Cart_get(%p, %d, %p, %p, %p)", comm, maxdims,
113                      dims, periods, coords);
114 #endif
115     if (!comm)
116     {
117         return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
118     }
119     if (!comm->cart || comm->cart->ndims == 0)
120     {
121         return TMPI_SUCCESS;
122     }
123
124     tMPI_Cart_coords(comm, myrank, maxdims, coords);
125
126     for (i = 0; i < comm->cart->ndims; i++)
127     {
128         if (i >= maxdims)
129         {
130             return tMPI_Error(comm, TMPI_ERR_DIMS);
131         }
132         dims[i]    = comm->cart->dims[i];
133         periods[i] = comm->cart->periods[i];
134     }
135
136     return TMPI_SUCCESS;
137 }
138
139 int tMPI_Cart_rank(tMPI_Comm comm, int *coords, int *rank)
140 {
141     int i, mul = 1, ret = 0;
142
143 #ifdef TMPI_TRACE
144     tMPI_Trace_print("tMPI_Cart_get(%p, %p, %p)", comm, coords, rank);
145 #endif
146     if (!comm)
147     {
148         return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
149     }
150     if (!comm->cart || comm->cart->ndims == 0)
151     {
152         return TMPI_SUCCESS;
153     }
154
155     /* because of row-major ordering, we count the dimensions down */
156     for (i = comm->cart->ndims-1; i >= 0; i--)
157     {
158         int rcoord = coords[i];
159         if (comm->cart->periods[i])
160         {
161             /* apply periodic boundary conditions */
162             rcoord = rcoord % comm->cart->dims[i];
163             if (rcoord < 0)
164             {
165                 rcoord += comm->cart->dims[i];
166             }
167         }
168         else
169         {
170             if (rcoord < 0 || rcoord >= comm->cart->dims[i])
171             {
172                 return tMPI_Error(comm, TMPI_ERR_DIMS);
173             }
174         }
175         ret += mul*rcoord;
176         mul *= comm->cart->dims[i];
177     }
178     *rank = ret;
179     return TMPI_SUCCESS;
180 }
181
182 int tMPI_Cart_coords(tMPI_Comm comm, int rank, int maxdims, int *coords)
183 {
184     int i;
185     int rank_left = rank;
186
187 #ifdef TMPI_TRACE
188     tMPI_Trace_print("tMPI_Cart_coords(%p, %d, %d, %p)", comm, rank, maxdims,
189                      coords);
190 #endif
191     if (!comm)
192     {
193         return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
194     }
195     if (!comm->cart || comm->cart->ndims == 0)
196     {
197         return TMPI_SUCCESS;
198     }
199     if (maxdims < comm->cart->ndims)
200     {
201         return tMPI_Error(comm, TMPI_ERR_DIMS);
202     }
203
204     /* again, row-major ordering */
205     for (i = comm->cart->ndims-1; i >= 0; i--)
206     {
207         coords[i]  = rank_left%comm->cart->dims[i];
208         rank_left /= comm->cart->dims[i];
209     }
210
211     return TMPI_SUCCESS;
212 }
213
214
215
216 int tMPI_Cart_map(tMPI_Comm comm, int ndims, int *dims, int *periods,
217                   int *newrank)
218 {
219     /* this function doesn't actually do anything beyond returning the current
220        rank (or TMPI_UNDEFINED if it doesn't fit in the new topology */
221     int myrank = tMPI_Comm_seek_rank(comm, tMPI_Get_current());
222     int Ntot   = 1;
223     int i;
224
225 #ifdef TMPI_TRACE
226     tMPI_Trace_print("tMPI_Cart_map(%p, %d, %p, %p, %p)", comm, ndims, dims,
227                      periods, newrank);
228 #endif
229     if (!comm)
230     {
231         return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
232     }
233     if (!periods)
234     {
235         return tMPI_Error(comm, TMPI_ERR_DIMS);
236     }
237
238     /* calculate the total number of procs in cartesian comm */
239     for (i = 0; i < ndims; i++)
240     {
241         Ntot *= dims[i];
242     }
243
244     if (myrank >= Ntot)
245     {
246         *newrank = TMPI_UNDEFINED;
247     }
248     else
249     {
250         *newrank = myrank;
251     }
252
253     return TMPI_SUCCESS;
254 }
255
256
257 /* initialize Cartesian topology info in comm. If ndims==0, dims and periods
258    are not referenced */
259 static void tMPI_Cart_init(tMPI_Comm *comm_cart, int ndims, int *dims,
260                            int *periods)
261 {
262     int newrank = -1;
263     int i;
264
265     if (*comm_cart)
266     {
267         tMPI_Comm_rank(*comm_cart, &newrank);
268     }
269
270     if (newrank == 0)
271     {
272         (*comm_cart)->cart = (struct cart_topol*)tMPI_Malloc(
273                     sizeof(struct cart_topol));
274         (*comm_cart)->cart->dims    = (int*)tMPI_Malloc(ndims*sizeof(int));
275         (*comm_cart)->cart->periods = (int*)tMPI_Malloc(ndims*sizeof(int));
276         (*comm_cart)->cart->ndims   = ndims;
277         for (i = 0; i < ndims; i++)
278         {
279             (*comm_cart)->cart->dims[i]    = dims[i];
280             (*comm_cart)->cart->periods[i] = periods[i];
281         }
282     }
283
284     /* and we add a barrier to make sure the cart object is seen by
285        every thread that is part of the new communicator */
286     if (*comm_cart)
287     {
288         tMPI_Barrier_wait( &( (*comm_cart)->barrier) );
289     }
290 }
291
292 void tMPI_Cart_destroy(struct cart_topol *cart)
293 {
294     if (cart)
295     {
296         free(cart->dims);
297         free(cart->periods);
298     }
299 }
300
301 int tMPI_Cart_create(tMPI_Comm comm_old, int ndims, int *dims, int *periods,
302                      int reorder, tMPI_Comm *comm_cart)
303 {
304     int myrank = tMPI_Comm_seek_rank(comm_old, tMPI_Get_current());
305     int key    = myrank;
306     int color  = 0;
307     int Ntot   = 1;
308     int i;
309
310
311 #ifdef TMPI_TRACE
312     tMPI_Trace_print("tMPI_Cart_create(%p, %d, %p, %p, %d, %p)", comm_old,
313                      ndims, dims, periods, reorder, comm_cart);
314 #endif
315     if (!comm_old)
316     {
317         return tMPI_Error(comm_old, TMPI_ERR_COMM);
318     }
319     /* calculate the total number of procs in cartesian comm */
320     for (i = 0; i < ndims; i++)
321     {
322         Ntot *= dims[i];
323     }
324     /* refuse to create if there's not enough procs */
325     if (comm_old->grp.N < Ntot)
326     {
327         *comm_cart = TMPI_COMM_NULL;
328 #if 1
329         return tMPI_Error(comm_old, TMPI_ERR_CART_CREATE_NPROCS);
330 #endif
331     }
332
333     if (key >= Ntot)
334     {
335         key = TMPI_UNDEFINED;
336     }
337
338     if (reorder)
339     {
340         tMPI_Cart_map(comm_old, ndims, dims, periods, &key);
341     }
342
343     if (key == TMPI_UNDEFINED)
344     {
345         color = TMPI_UNDEFINED;
346     }
347
348     tMPI_Comm_split(comm_old, color, key, comm_cart);
349
350     tMPI_Cart_init(comm_cart, ndims, dims, periods);
351
352     return TMPI_SUCCESS;
353 }
354
355
356 int tMPI_Cart_sub(tMPI_Comm comm, int *remain_dims, tMPI_Comm *newcomm)
357 {
358     int  myrank;
359     int  ndims     = 0;
360     int *dims      = NULL;
361     int *periods   = NULL;
362     int *oldcoords = NULL;
363     int  i;
364     int  ndims_notused = 1;
365     int  color_notused = 0;
366
367 #ifdef TMPI_TRACE
368     tMPI_Trace_print("tMPI_Cart_sub(%p, %p, %p)", comm, remain_dims, newcomm);
369 #endif
370     tMPI_Comm_rank(comm, &myrank);
371     if (comm->cart)
372     {
373         oldcoords = (int*)tMPI_Malloc(sizeof(int)*comm->cart->ndims);
374         dims      = (int*)tMPI_Malloc(sizeof(int)*comm->cart->ndims);
375         periods   = (int*)tMPI_Malloc(sizeof(int)*comm->cart->ndims);
376
377         /* get old coordinates */
378         tMPI_Cart_coords(comm, myrank, comm->cart->ndims, oldcoords);
379
380         for (i = 0; i < comm->cart->ndims; i++)
381         {
382             if (remain_dims[i])
383             {
384                 /* for the remaining dimensions, copy dimensionality data */
385                 dims[ndims]    = comm->cart->dims[i];
386                 periods[ndims] = comm->cart->periods[i];
387                 ndims++;
388             }
389             else
390             {
391                 /* base color on not used coordinates. We keep a
392                    ndims_notused index multiplier.*/
393                 color_notused += oldcoords[i]*ndims_notused;
394                 ndims_notused *= comm->cart->dims[i];
395             }
396         }
397     }
398
399     /* key=myrank, because we want the order to remain the same */
400     tMPI_Comm_split(comm, color_notused, myrank, newcomm);
401     tMPI_Cart_init(newcomm, ndims, dims, periods);
402
403     if (oldcoords)
404     {
405         free(oldcoords);
406     }
407     if (dims)
408     {
409         free(dims);
410     }
411     if (periods)
412     {
413         free(periods);
414     }
415
416     return TMPI_SUCCESS;
417 }