QUDA v0.4.0
A library for QCD on GPUs
quda/tests/layout_hyper.c
Go to the documentation of this file.
00001 /******** layout_hyper.c *********/
00002 /* adapted from SciDAC QDP Data Parallel API */
00003 /* Includes new entry "get_sites_on_node" */
00004 /* adapted from MIMD version 6 */
00005 
00006 /* ROUTINES WHICH DETERMINE THE DISTRIBUTION OF SITES ON NODES */
00007 
00008 /* This version divides the lattice by factors of prime numbers in any of the
00009    four directions.  It prefers to divide the longest dimensions,
00010    which mimimizes the area of the surfaces.  Similarly, it prefers
00011    to divide dimensions which have already been divided, thus not
00012    introducing more off-node directions.
00013 
00014         S. Gottlieb, May 18, 1999
00015         The code will start trying to divide with the largest prime factor
00016         and then work its way down to 2.  The current maximum prime is 53.
00017         The array of primes "prime[]" may be extended if necessary.
00018 
00019    This requires that the lattice volume be divisible by the number
00020    of nodes.  Each dimension must be divisible by a suitable factor
00021    such that the product of the four factors is the number of nodes.
00022 
00023    3/29/00 EVENFIRST is the rule now. CD.
00024    12/10/00 Fixed so k = MAXPRIMES-1 DT
00025 */
00026 
00027 /*
00028    setup_layout()  sets up layout
00029    node_number()   returns the node number on which a site lives
00030    node_index()    returns the index of the site on the node
00031    get_coords()    gives lattice coords from node & index
00032 */
00033 
00034 
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <qmp.h>
00038 #include <layout_hyper.h>
00039 
00040 //#include <qio_util.h>
00041 
00042 /* The following globals are required:
00043 
00044    QMP_get_logical_topology()
00045    QMP_logical_topology_is_declared()
00046    this_node
00047    QMP_abort()
00048 
00049 */
00050 
00051 static int *squaresize;   /* dimensions of hypercubes */
00052 static int *nsquares;     /* number of hypercubes in each direction */
00053 static int ndim;
00054 static int *size1[2], *size2;
00055 static int prime[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
00056 static int sites_on_node;
00057 static int *mcoord;
00058 
00059 #define MAXPRIMES (sizeof(prime)/sizeof(int))
00060 
00061 // MAC this function assumes that the QMP geometry has been predetermined
00062 static void setup_qmp_fixed(int len[], int nd, int numnodes) {
00063   int i;
00064 
00065   for (i=0; i<ndim; i++) {
00066     nsquares[i] = QMP_get_logical_dimensions()[i];
00067     squaresize[i] = len[i]/nsquares[i];
00068   }
00069 
00070 }
00071 
00072 static void setup_qmp_grid(int len[], int nd, int numnodes){
00073   int ndim2, i;
00074   const int *nsquares2;
00075 
00076   ndim2 = QMP_get_allocated_number_of_dimensions();
00077   nsquares2 = QMP_get_allocated_dimensions();
00078   for(i=0; i<ndim; i++) {
00079     if(i<ndim2) nsquares[i] = nsquares2[i];
00080     else nsquares[i] = 1;
00081   }
00082 
00083   for(i=0; i<ndim; i++) {
00084     if(len[i]%nsquares[i] != 0) {
00085       printf("LATTICE SIZE DOESN'T FIT GRID\n");
00086       QMP_abort(0);
00087     }
00088     squaresize[i] = len[i]/nsquares[i];
00089   }
00090 }
00091 
00092 static void setup_hyper_prime(int len[], int nd, int numnodes)
00093 {
00094   int i, j, k, n;
00095 
00096   /* Figure out dimensions of rectangle */
00097   for(i=0; i<ndim; ++i) {
00098     squaresize[i] = len[i];
00099     nsquares[i] = 1;
00100   }
00101 
00102   n = numnodes; /* remaining number of nodes to be factored */
00103   k = MAXPRIMES-1;
00104   while(n>1) {
00105     /* figure out which prime to divide by starting with largest */
00106     while( (n%prime[k]!=0) && (k>0) ) --k;
00107 
00108     /* figure out which direction to divide */
00109     /* find largest divisible dimension of h-cubes */
00110     /* if one direction with largest dimension has already been
00111        divided, divide it again.  Otherwise divide first direction
00112        with largest dimension. */
00113     j = -1;
00114     for(i=0; i<ndim; i++) {
00115       if(squaresize[i]%prime[k]==0) {
00116         if( (j<0) || (squaresize[i]>squaresize[j]) ) {
00117           j = i;
00118         } else if(squaresize[i]==squaresize[j]) {
00119           if((nsquares[j]==1)&&(nsquares[i]!=1)) j = i;
00120         }
00121       }
00122     }
00123 
00124     /* This can fail if we run out of prime factors in the dimensions */
00125     if(j<0) {
00126       if(this_node==0) {
00127         fprintf(stderr, "LAYOUT: Not enough prime factors in lattice dimensions\n");
00128       }
00129       QMP_abort(1);
00130       exit(1);
00131     }
00132 
00133     /* do the surgery */
00134     n /= prime[k];
00135     squaresize[j] /= prime[k];
00136     nsquares[j] *= prime[k];
00137   }
00138 }
00139 
00140 int setup_layout(int len[], int nd, int numnodes){
00141   int i;
00142 
00143   ndim = nd;
00144   squaresize = (int *) malloc(ndim*sizeof(int));
00145   nsquares = (int *) malloc(ndim*sizeof(int));
00146   mcoord = (int *) malloc(ndim*sizeof(int));
00147 
00148   /*
00149    MAC: The miniminum surface area partitioning is disabled and QUDA
00150    expects it to be determined by the user or calling application, but
00151    this functionality is included for possible future use.
00152   */
00153 
00154 #if 0
00155   if(QMP_get_msg_passing_type()==QMP_GRID) {
00156     printf("grid\n");
00157     setup_qmp_grid(len, ndim, numnodes);
00158   }  else {
00159     printf("prime\n");    setup_hyper_prime(len, ndim, numnodes);
00160   }
00161 #else
00162   setup_qmp_fixed(len, ndim, numnodes); // use the predetermined geometry
00163 #endif
00164 
00165   /* setup QMP logical topology */
00166   if(!QMP_logical_topology_is_declared()) {
00167     if(QMP_declare_logical_topology(nsquares, ndim)!=0)
00168       return 1;
00169   }
00170 
00171   sites_on_node = 1;
00172   for(i=0; i<ndim; ++i) {
00173     sites_on_node *= squaresize[i];
00174   }
00175 
00176   size1[0] = (int*)malloc(2*(ndim+1)*sizeof(int));
00177   size1[1] = size1[0] + ndim + 1;
00178   size2 = (int*)malloc((ndim+1)*sizeof(int));
00179 
00180   size1[0][0] = 1;
00181   size1[1][0] = 0;
00182   size2[0] = 1;
00183   for(i=1; i<=ndim; i++) {
00184     size1[0][i] = size2[i-1]*(squaresize[i-1]/2)
00185                 + size1[0][i-1]*(squaresize[i-1]%2);
00186     size1[1][i] = size2[i-1]*(squaresize[i-1]/2)
00187                 + size1[1][i-1]*(squaresize[i-1]%2);
00188     size2[i] = size1[0][i] + size1[1][i];
00189     //printf("%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
00190   }
00191   return 0;
00192 }
00193 
00194 int node_number(const int x[])
00195 {
00196   int i;
00197 
00198   for(i=0; i<ndim; i++) {
00199     mcoord[i] = x[i]/squaresize[i];
00200   }
00201   return QMP_get_node_number_from(mcoord);
00202 }
00203 
00204 int node_index(const int x[])
00205 {
00206   int i, r=0, p=0;
00207 
00208   for(i=ndim-1; i>=0; --i) {
00209     r = r*squaresize[i] + (x[i]%squaresize[i]);
00210     p += x[i];
00211   }
00212 
00213   if( p%2==0 ) { /* even site */
00214     r /= 2;
00215   } else {
00216     r = (r+sites_on_node)/2;
00217   }
00218   return r;
00219 }
00220 
00221 void get_coords(int x[], int node, int index)
00222 {
00223   int i, s, si;
00224   int *m;
00225 
00226   si = index;
00227 
00228   m = QMP_get_logical_coordinates_from(node);
00229 
00230   s = 0;
00231   for(i=0; i<ndim; ++i) {
00232     x[i] = m[i] * squaresize[i];
00233     s += x[i];
00234   }
00235   s &= 1;
00236 
00237   if(index>=size1[s][ndim]) {
00238     index -= size1[s][ndim];
00239     s ^= 1;
00240   }
00241 
00242   for(i=ndim-1; i>0; i--) {
00243     x[i] += 2*(index/size2[i]);
00244     index %= size2[i];
00245     if(index>=size1[s][i]) {
00246       index -= size1[s][i];
00247       s ^= 1;
00248       x[i]++;
00249     }
00250   }
00251   x[0] += 2*index + s;
00252 
00253   free(m);
00254 
00255   /* Check the result */
00256   if(node_index(x)!=si) {
00257     if(this_node==0) {
00258       fprintf(stderr,"get_coords: error in layout!\n");
00259       for(i=0; i<ndim; i++) {
00260         fprintf(stderr,"%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
00261       }
00262       fprintf(stderr,"%i\t%i", node, si);
00263       for(i=0; i<ndim; i++) fprintf(stderr,"\t%i", x[i]);
00264       fprintf(stderr,"\n");
00265     }
00266     QMP_abort(1);
00267     exit(1);
00268   }
00269 }
00270 
00271 /* The number of sites on the specified node */
00272 int num_sites(int node){
00273   return sites_on_node;
00274 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines