QUDA  0.9.0
layout_hyper.c
Go to the documentation of this file.
1 /******** layout_hyper.c *********/
2 /* adapted from SciDAC QDP Data Parallel API */
3 /* Includes new entry "get_sites_on_node" */
4 /* adapted from MIMD version 6 */
5 
6 /* ROUTINES WHICH DETERMINE THE DISTRIBUTION OF SITES ON NODES */
7 
8 /* This version divides the lattice by factors of prime numbers in any of the
9  four directions. It prefers to divide the longest dimensions,
10  which mimimizes the area of the surfaces. Similarly, it prefers
11  to divide dimensions which have already been divided, thus not
12  introducing more off-node directions.
13 
14  S. Gottlieb, May 18, 1999
15  The code will start trying to divide with the largest prime factor
16  and then work its way down to 2. The current maximum prime is 53.
17  The array of primes "prime[]" may be extended if necessary.
18 
19  This requires that the lattice volume be divisible by the number
20  of nodes. Each dimension must be divisible by a suitable factor
21  such that the product of the four factors is the number of nodes.
22 
23  3/29/00 EVENFIRST is the rule now. CD.
24  12/10/00 Fixed so k = MAXPRIMES-1 DT
25 */
26 
27 /*
28  setup_layout() sets up layout
29  node_number() returns the node number on which a site lives
30  node_index() returns the index of the site on the node
31  get_coords() gives lattice coords from node & index
32 */
33 
34 
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <qmp.h>
38 #include <layout_hyper.h>
39 
40 //#include <qio_util.h>
41 
42 /* The following globals are required:
43 
44  QMP_get_logical_topology()
45  QMP_logical_topology_is_declared()
46  this_node
47  QMP_abort()
48 
49 */
50 
51 static int *squaresize; /* dimensions of hypercubes */
52 static int *nsquares; /* number of hypercubes in each direction */
53 static int ndim;
54 static int *size1[2], *size2;
55 static int prime[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
56 static int sites_on_node;
57 static int *mcoord;
58 
59 #define MAXPRIMES (sizeof(prime)/sizeof(int))
60 
61 // MAC this function assumes that the QMP geometry has been predetermined
62 static void setup_qmp_fixed(int len[], int nd, int numnodes) {
63  int i;
64 
65  //Added by M. Cheng to fix seg fault on single-node case where
66  //QMP topology is not yet declared.
67 
68  if(QMP_get_number_of_nodes() == 1) {
69  for (i=0; i<ndim; i++) {
70  nsquares[i] = 1;
71  squaresize[i] = len[i]/nsquares[i];
72  }
73  } else {
74  for (i=0; i<ndim; i++) {
75  nsquares[i] = QMP_get_logical_dimensions()[i];
76  squaresize[i] = len[i]/nsquares[i];
77  }
78  }
79 
80 }
81 
82 static void setup_qmp_grid(int len[], int nd, int numnodes){
83  int ndim2, i;
84  const int *nsquares2;
85 
86  ndim2 = QMP_get_allocated_number_of_dimensions();
87  nsquares2 = QMP_get_allocated_dimensions();
88  for(i=0; i<ndim; i++) {
89  if(i<ndim2) nsquares[i] = nsquares2[i];
90  else nsquares[i] = 1;
91  }
92 
93  for(i=0; i<ndim; i++) {
94  if(len[i]%nsquares[i] != 0) {
95  printf("LATTICE SIZE DOESN'T FIT GRID\n");
96  QMP_abort(0);
97  }
98  squaresize[i] = len[i]/nsquares[i];
99  }
100 }
101 
102 static void setup_hyper_prime(int len[], int nd, int numnodes)
103 {
104  int i, j, k, n;
105 
106  /* Figure out dimensions of rectangle */
107  for(i=0; i<ndim; ++i) {
108  squaresize[i] = len[i];
109  nsquares[i] = 1;
110  }
111 
112  n = numnodes; /* remaining number of nodes to be factored */
113  k = MAXPRIMES-1;
114  while(n>1) {
115  /* figure out which prime to divide by starting with largest */
116  while( (n%prime[k]!=0) && (k>0) ) --k;
117 
118  /* figure out which direction to divide */
119  /* find largest divisible dimension of h-cubes */
120  /* if one direction with largest dimension has already been
121  divided, divide it again. Otherwise divide first direction
122  with largest dimension. */
123  j = -1;
124  for(i=0; i<ndim; i++) {
125  if(squaresize[i]%prime[k]==0) {
126  if( (j<0) || (squaresize[i]>squaresize[j]) ) {
127  j = i;
128  } else if(squaresize[i]==squaresize[j]) {
129  if((nsquares[j]==1)&&(nsquares[i]!=1)) j = i;
130  }
131  }
132  }
133 
134  /* This can fail if we run out of prime factors in the dimensions */
135  if(j<0) {
136  if(this_node==0) {
137  fprintf(stderr, "LAYOUT: Not enough prime factors in lattice dimensions\n");
138  }
139  QMP_abort(1);
140  exit(1);
141  }
142 
143  /* do the surgery */
144  n /= prime[k];
145  squaresize[j] /= prime[k];
146  nsquares[j] *= prime[k];
147  }
148 }
149 
150 int setup_layout(int len[], int nd, int numnodes){
151  int i;
152 
153  ndim = nd;
154  squaresize = (int *) malloc(ndim*sizeof(int));
155  nsquares = (int *) malloc(ndim*sizeof(int));
156  mcoord = (int *) malloc(ndim*sizeof(int));
157 
158  /*
159  MAC: The miniminum surface area partitioning is disabled and QUDA
160  expects it to be determined by the user or calling application, but
161  this functionality is included for possible future use.
162  */
163 
164  int create_geom = 0;
165  if (create_geom) {
166  if(QMP_get_msg_passing_type()==QMP_GRID) {
167  printf("grid\n");
168  setup_qmp_grid(len, ndim, numnodes);
169  } else {
170  printf("prime\n"); setup_hyper_prime(len, ndim, numnodes);
171  }
172  } else {
173  setup_qmp_fixed(len, ndim, numnodes); // use the predetermined geometry
174  }
175 
176  /* setup QMP logical topology */
177  if(!QMP_logical_topology_is_declared()) {
178  if(QMP_declare_logical_topology(nsquares, ndim)!=0)
179  return 1;
180  }
181 
182  sites_on_node = 1;
183  for(i=0; i<ndim; ++i) {
185  }
186 
187  size1[0] = (int*)malloc(2*(ndim+1)*sizeof(int));
188  size1[1] = size1[0] + ndim + 1;
189  size2 = (int*)malloc((ndim+1)*sizeof(int));
190 
191  size1[0][0] = 1;
192  size1[1][0] = 0;
193  size2[0] = 1;
194  for(i=1; i<=ndim; i++) {
195  size1[0][i] = size2[i-1]*(squaresize[i-1]/2)
196  + size1[0][i-1]*(squaresize[i-1]%2);
197  size1[1][i] = size2[i-1]*(squaresize[i-1]/2)
198  + size1[1][i-1]*(squaresize[i-1]%2);
199  size2[i] = size1[0][i] + size1[1][i];
200  //printf("%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
201  }
202  return 0;
203 }
204 
205 int node_number(const int x[])
206 {
207  int i;
208 
209  for(i=0; i<ndim; i++) {
210  mcoord[i] = x[i]/squaresize[i];
211  }
212  return QMP_get_node_number_from(mcoord);
213 }
214 
215 int node_index(const int x[])
216 {
217  int i, r=0, p=0;
218 
219  for(i=ndim-1; i>=0; --i) {
220  r = r*squaresize[i] + (x[i]%squaresize[i]);
221  p += x[i];
222  }
223 
224  if( p%2==0 ) { /* even site */
225  r /= 2;
226  } else {
227  r = (r+sites_on_node)/2;
228  }
229  return r;
230 }
231 
232 void get_coords(int x[], int node, int index)
233 {
234  int i, s, si;
235  int *m;
236 
237  si = index;
238 
239  m = QMP_get_logical_coordinates_from(node);
240 
241  s = 0;
242  for(i=0; i<ndim; ++i) {
243  x[i] = m[i] * squaresize[i];
244  s += x[i];
245  }
246  s &= 1;
247 
248  if(index>=size1[s][ndim]) {
249  index -= size1[s][ndim];
250  s ^= 1;
251  }
252 
253  for(i=ndim-1; i>0; i--) {
254  x[i] += 2*(index/size2[i]);
255  index %= size2[i];
256  if(index>=size1[s][i]) {
257  index -= size1[s][i];
258  s ^= 1;
259  x[i]++;
260  }
261  }
262  x[0] += 2*index + s;
263 
264  free(m);
265 
266  /* Check the result */
267  if(node_index(x)!=si) {
268  if(this_node==0) {
269  fprintf(stderr,"get_coords: error in layout!\n");
270  for(i=0; i<ndim; i++) {
271  fprintf(stderr,"%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
272  }
273  fprintf(stderr,"%i\t%i", node, si);
274  for(i=0; i<ndim; i++) fprintf(stderr,"\t%i", x[i]);
275  fprintf(stderr,"\n");
276  }
277  QMP_abort(1);
278  exit(1);
279  }
280 }
281 
282 /* The number of sites on the specified node */
283 int num_sites(int node){
284  return sites_on_node;
285 }
static int * mcoord
Definition: layout_hyper.c:57
void free(void *)
#define MAXPRIMES
Definition: layout_hyper.c:59
void get_coords(int x[], int node, int index)
Definition: layout_hyper.c:232
static void setup_hyper_prime(int len[], int nd, int numnodes)
Definition: layout_hyper.c:102
int this_node
Definition: qio_field.cpp:9
static void setup_qmp_fixed(int len[], int nd, int numnodes)
Definition: layout_hyper.c:62
void exit(int) __attribute__((noreturn))
char * index(const char *, int)
static int ndim
Definition: layout_hyper.c:53
static int * size2
Definition: layout_hyper.c:54
void * malloc(size_t __size) __attribute__((__warn_unused_result__)) __attribute__((alloc_size(1)))
int printf(const char *,...) __attribute__((__format__(__printf__
static int sites_on_node
Definition: layout_hyper.c:56
static __inline__ size_t p
static int * nsquares
Definition: layout_hyper.c:52
static int * size1[2]
Definition: layout_hyper.c:54
int fprintf(FILE *, const char *,...) __attribute__((__format__(__printf__
int setup_layout(int len[], int nd, int numnodes)
Definition: layout_hyper.c:150
int node_index(const int x[])
Definition: layout_hyper.c:215
int node_number(const int x[])
Definition: layout_hyper.c:205
static int prime[]
Definition: layout_hyper.c:55
static int * squaresize
Definition: layout_hyper.c:51
int num_sites(int node)
Definition: layout_hyper.c:283
static void setup_qmp_grid(int len[], int nd, int numnodes)
Definition: layout_hyper.c:82