QUDA  v0.7.0
A library for QCD on GPUs
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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  for (i=0; i<ndim; i++) {
66  nsquares[i] = QMP_get_logical_dimensions()[i];
67  squaresize[i] = len[i]/nsquares[i];
68  }
69 
70 }
71 
72 static void setup_qmp_grid(int len[], int nd, int numnodes){
73  int ndim2, i;
74  const int *nsquares2;
75 
76  ndim2 = QMP_get_allocated_number_of_dimensions();
77  nsquares2 = QMP_get_allocated_dimensions();
78  for(i=0; i<ndim; i++) {
79  if(i<ndim2) nsquares[i] = nsquares2[i];
80  else nsquares[i] = 1;
81  }
82 
83  for(i=0; i<ndim; i++) {
84  if(len[i]%nsquares[i] != 0) {
85  printf("LATTICE SIZE DOESN'T FIT GRID\n");
86  QMP_abort(0);
87  }
88  squaresize[i] = len[i]/nsquares[i];
89  }
90 }
91 
92 static void setup_hyper_prime(int len[], int nd, int numnodes)
93 {
94  int i, j, k, n;
95 
96  /* Figure out dimensions of rectangle */
97  for(i=0; i<ndim; ++i) {
98  squaresize[i] = len[i];
99  nsquares[i] = 1;
100  }
101 
102  n = numnodes; /* remaining number of nodes to be factored */
103  k = MAXPRIMES-1;
104  while(n>1) {
105  /* figure out which prime to divide by starting with largest */
106  while( (n%prime[k]!=0) && (k>0) ) --k;
107 
108  /* figure out which direction to divide */
109  /* find largest divisible dimension of h-cubes */
110  /* if one direction with largest dimension has already been
111  divided, divide it again. Otherwise divide first direction
112  with largest dimension. */
113  j = -1;
114  for(i=0; i<ndim; i++) {
115  if(squaresize[i]%prime[k]==0) {
116  if( (j<0) || (squaresize[i]>squaresize[j]) ) {
117  j = i;
118  } else if(squaresize[i]==squaresize[j]) {
119  if((nsquares[j]==1)&&(nsquares[i]!=1)) j = i;
120  }
121  }
122  }
123 
124  /* This can fail if we run out of prime factors in the dimensions */
125  if(j<0) {
126  if(this_node==0) {
127  fprintf(stderr, "LAYOUT: Not enough prime factors in lattice dimensions\n");
128  }
129  QMP_abort(1);
130  exit(1);
131  }
132 
133  /* do the surgery */
134  n /= prime[k];
135  squaresize[j] /= prime[k];
136  nsquares[j] *= prime[k];
137  }
138 }
139 
140 int setup_layout(int len[], int nd, int numnodes){
141  int i;
142 
143  ndim = nd;
144  squaresize = (int *) malloc(ndim*sizeof(int));
145  nsquares = (int *) malloc(ndim*sizeof(int));
146  mcoord = (int *) malloc(ndim*sizeof(int));
147 
148  /*
149  MAC: The miniminum surface area partitioning is disabled and QUDA
150  expects it to be determined by the user or calling application, but
151  this functionality is included for possible future use.
152  */
153 
154 #if 0
155  if(QMP_get_msg_passing_type()==QMP_GRID) {
156  printf("grid\n");
157  setup_qmp_grid(len, ndim, numnodes);
158  } else {
159  printf("prime\n"); setup_hyper_prime(len, ndim, numnodes);
160  }
161 #else
162  setup_qmp_fixed(len, ndim, numnodes); // use the predetermined geometry
163 #endif
164 
165  /* setup QMP logical topology */
166  if(!QMP_logical_topology_is_declared()) {
167  if(QMP_declare_logical_topology(nsquares, ndim)!=0)
168  return 1;
169  }
170 
171  sites_on_node = 1;
172  for(i=0; i<ndim; ++i) {
173  sites_on_node *= squaresize[i];
174  }
175 
176  size1[0] = (int*)malloc(2*(ndim+1)*sizeof(int));
177  size1[1] = size1[0] + ndim + 1;
178  size2 = (int*)malloc((ndim+1)*sizeof(int));
179 
180  size1[0][0] = 1;
181  size1[1][0] = 0;
182  size2[0] = 1;
183  for(i=1; i<=ndim; i++) {
184  size1[0][i] = size2[i-1]*(squaresize[i-1]/2)
185  + size1[0][i-1]*(squaresize[i-1]%2);
186  size1[1][i] = size2[i-1]*(squaresize[i-1]/2)
187  + size1[1][i-1]*(squaresize[i-1]%2);
188  size2[i] = size1[0][i] + size1[1][i];
189  //printf("%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
190  }
191  return 0;
192 }
193 
194 int node_number(const int x[])
195 {
196  int i;
197 
198  for(i=0; i<ndim; i++) {
199  mcoord[i] = x[i]/squaresize[i];
200  }
201  return QMP_get_node_number_from(mcoord);
202 }
203 
204 int node_index(const int x[])
205 {
206  int i, r=0, p=0;
207 
208  for(i=ndim-1; i>=0; --i) {
209  r = r*squaresize[i] + (x[i]%squaresize[i]);
210  p += x[i];
211  }
212 
213  if( p%2==0 ) { /* even site */
214  r /= 2;
215  } else {
216  r = (r+sites_on_node)/2;
217  }
218  return r;
219 }
220 
221 void get_coords(int x[], int node, int index)
222 {
223  int i, s, si;
224  int *m;
225 
226  si = index;
227 
228  m = QMP_get_logical_coordinates_from(node);
229 
230  s = 0;
231  for(i=0; i<ndim; ++i) {
232  x[i] = m[i] * squaresize[i];
233  s += x[i];
234  }
235  s &= 1;
236 
237  if(index>=size1[s][ndim]) {
238  index -= size1[s][ndim];
239  s ^= 1;
240  }
241 
242  for(i=ndim-1; i>0; i--) {
243  x[i] += 2*(index/size2[i]);
244  index %= size2[i];
245  if(index>=size1[s][i]) {
246  index -= size1[s][i];
247  s ^= 1;
248  x[i]++;
249  }
250  }
251  x[0] += 2*index + s;
252 
253  free(m);
254 
255  /* Check the result */
256  if(node_index(x)!=si) {
257  if(this_node==0) {
258  fprintf(stderr,"get_coords: error in layout!\n");
259  for(i=0; i<ndim; i++) {
260  fprintf(stderr,"%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
261  }
262  fprintf(stderr,"%i\t%i", node, si);
263  for(i=0; i<ndim; i++) fprintf(stderr,"\t%i", x[i]);
264  fprintf(stderr,"\n");
265  }
266  QMP_abort(1);
267  exit(1);
268  }
269 }
270 
271 /* The number of sites on the specified node */
272 int num_sites(int node){
273  return sites_on_node;
274 }
#define MAXPRIMES
Definition: layout_hyper.c:59
void get_coords(int x[], int node, int index)
Definition: layout_hyper.c:221
int x[4]
int this_node
Definition: gauge_qio.cpp:9
int setup_layout(int len[], int nd, int numnodes)
Definition: layout_hyper.c:140
int node_index(const int x[])
Definition: layout_hyper.c:204
int node_number(const int x[])
Definition: layout_hyper.c:194
VOLATILE spinorFloat * s
int num_sites(int node)
Definition: layout_hyper.c:272