su2hmc
Loading...
Searching...
No Matches
par_mpi.c
Go to the documentation of this file.
1
6#include <su2hmc.h>
7
8//NOTE: In FORTRAN code everything was capitalised (despite being case insensitive)
9//C is case sensitive, so the equivalent C command has the case format MPI_Xyz_abc
10//Non-commands (like MPI_COMM_WORLD) don't always change
11
12#if(nproc>1)
13MPI_Comm comm = MPI_COMM_WORLD;
14MPI_Request request;
15#endif
16
17int *pcoord;
18int pstart[ndim][nproc] __attribute__((aligned(AVX)));
19int pstop [ndim][nproc] __attribute__((aligned(AVX)));
21int pu[ndim] __attribute__((aligned(AVX)));
22int pd[ndim] __attribute__((aligned(AVX)));
23
24int Par_begin(int argc, char *argv[]){
25 //TODO: Remove as much non-MPI stuff from here as possible
26 const char funcname[] = "Par_begin";
27 int size;
28#if(nproc>1)
29 if(MPI_Init(&argc, &argv)){
30 fprintf(stderr, "Error %i in %s: Failed to initialise MPI\nExiting\n\n", NO_MPI_INIT, funcname);
31 MPI_Abort(comm,NO_MPI_INIT);
32 exit(NO_MPI_INIT);
33 }
34
35 if(MPI_Comm_rank(comm, &rank)){
36 fprintf(stderr, "Error %i in %s: Failed to find rank.\nExiting...\n\n", NO_MPI_RANK, funcname);
37 MPI_Abort(comm,NO_MPI_RANK);
38 }
39 if(MPI_Comm_size(comm, &size)){
40 fprintf(stderr, "Error %i in %s: Failed to find size\nExiting...\n\n", NO_MPI_SIZE, funcname);
41 MPI_Abort(comm,NO_MPI_SIZE);
42 }
43#else
44 size=1; rank=0;
45#endif
46 //If size isn't the same as the max allowed number of processes, then there's a problem somewhere.
47 if(size!=nproc){
48 fprintf(stderr, "Error %i in %s: For process %i, size %i is not equal to nproc %i.\n"
49 "Exiting...\n\n", SIZEPROC, funcname, rank, size, nproc);
50#if(nproc>1)
51 MPI_Abort(comm,SIZEPROC);
52#else
53 exit(SIZEPROC);
54#endif
55 }
56 //gsize is the size of the system, lsize is the size of each MPI Grid
57 int gsize[4], lsize[4];
58 gsize[0]=nx; gsize[1]=ny; gsize[2]=nz; gsize[3]=nt;
59 lsize[0]=ksizex; lsize[1]=ksizey; lsize[2]=ksizez; lsize[3]=ksizet;
60
61 //Topology layout
62 int cartsize[ndim] __attribute__((aligned(AVX)));
63 cartsize[0]=npx; cartsize[1]=npy; cartsize[2]=npz; cartsize[3]=npt;
64
65 //For the topology, says if each dimension is periodic or not
66 //Probably for us everything will be but using the four vector
67 //gives the choice at least
68 int periods[ndim] __attribute__((aligned(AVX)));
69#pragma unroll
70 for(int i=0; i<ndim; i++)
71 periods[i] = true;
72 //Not going to change the rank order
73 int reorder = false;
74 //Declare the topology
75#if(nproc>1)
76 MPI_Comm commcart;
77 MPI_Cart_create(comm, ndim, cartsize, periods, reorder, &commcart);
78#endif
79
80 //Get nearest neighbours of processors
81#if(nproc>1)
82#pragma unroll
83 for(int i= 0; i<ndim; i++)
84 MPI_Cart_shift(commcart, i, 1, &pd[i], &pu[i]);
85#endif
86 //Get coordinates of processors in the grid
87 pcoord = (int*)malloc(ndim*nproc*sizeof(int));
88 memset(pcoord,0,sizeof(int)*ndim*nproc);
89#if(nproc>1)
90 for(int iproc = 0; iproc<nproc; iproc++){
91 MPI_Cart_coords(commcart, iproc, ndim, pcoord+iproc*ndim);
92#pragma omp simd aligned(pcoord:AVX)
93 for(int idim = 0; idim<ndim; idim++){
94 pstart[idim][iproc] = pcoord[idim+ndim*iproc]*lsize[idim];
95 pstop[idim][iproc] = pstart[idim][iproc] + lsize[idim];
96 }
97 }
98#else
99 //Set iproc=0 because we only have one proc
100 for(int idim = 0; idim<ndim; idim++){
101 pstart[idim][0] = 0;
102 pstop[idim][0] = lsize[idim];
103 }
104#endif
105#ifdef _DEBUG
106 if(!rank)
107 printf("Running on %i processors.\nGrid layout is %ix%ix%ix%i\n",
108 nproc, npx,npy,npz,npt);
109 printf("Rank: %i pu: %i %i %i %i pd: %i %i %i %i\n", rank, pu[0], pu[1], pu[2], pu[3],
110 pd[0], pd[1], pd[2], pd[3]);
111#endif
112 return 0;
113}
114int Par_sread(const int iread, const float beta, const float fmu, const float akappa, const Complex_f ajq,\
115 const float c_sw, Complex *u11, Complex *u12, Complex *u11t, Complex *u12t){
116 const char funcname[] = "Par_sread";
117#if(nproc>1)
118 MPI_Status status;
119 //For sending the seeds later
120 MPI_Datatype MPI_SEED_TYPE = (sizeof(seed)==sizeof(int)) ? MPI_INT:MPI_LONG;
121#endif
122 //We shall allow the almighty master thread to open the file
123 Complex *u1buff = (Complex *)aligned_alloc(AVX,kvol*sizeof(Complex));
124 Complex *u2buff = (Complex *)aligned_alloc(AVX,kvol*sizeof(Complex));
125 if(!rank){
126 //Containers for input. Only needed by the master rank
127 Complex *u11Read = (Complex *)aligned_alloc(AVX,ndim*gvol*sizeof(Complex));
128 Complex *u12Read = (Complex *)aligned_alloc(AVX,ndim*gvol*sizeof(Complex));
129 char gauge_file[FILELEN]="config.";
130 int buffer; char buff2[7];
131 //Add script for extracting correct mu, j etc.
132 buffer = (int)round(100*beta);
133 sprintf(buff2,"b%03d",buffer);
134 strcat(gauge_file,buff2);
135 //κ
136 buffer = (int)round(10000*akappa);
137 sprintf(buff2,"k%04d",buffer);
138 strcat(gauge_file,buff2);
139 //μ
140 buffer = (int)round(1000*fmu);
141 sprintf(buff2,"mu%04d",buffer);
142 strcat(gauge_file,buff2);
143 //J
144 buffer = (int)round(1000*creal(ajq));
145 sprintf(buff2,"j%03d",buffer);
146 strcat(gauge_file,buff2);
147 //c_sw
148 if(c_sw!=0){
149 buffer = (int)round(100*c_sw);
150 sprintf(buff2,"c%02d",buffer);
151 strcat(gauge_file,buff2);
152 }
153 //nx
154 sprintf(buff2,"s%02d",nx);
155 strcat(gauge_file,buff2);
156 //nt
157 sprintf(buff2,"t%02d",nt);
158 strcat(gauge_file,buff2);
159 //nconfig
160 char c[8];
161 sprintf(c,".%06d", iread);
162 strcat(gauge_file, c);
163
164 char *fileop = "rb";
165 printf("Opening gauge file on processor: %i\n",rank);
166 FILE *con;
167 if(!(con = fopen(gauge_file, fileop))){
168 fprintf(stderr, "Error %i in %s: Failed to open %s for %s.\
169 \nExiting...\n\n", OPENERROR, funcname, gauge_file, fileop);
170#if(nproc>1)
171 MPI_Abort(comm,OPENERROR);
172#endif
173 exit(OPENERROR);
174 }
175 //TODO: SAFETY CHECKS FOR EACH READ OPERATION
176 int old_nproc;
177 //What was previously the FORTRAN integer is now used to store the number of processors used to
178 //generate the configuration
179 fread(&old_nproc, sizeof(int), 1, con);
180 if(old_nproc!=nproc)
181 fprintf(stderr, "Warning %i in %s: Previous run was done on %i processors, current run uses %i.\n",\
182 DIFNPROC,funcname,old_nproc,nproc);
183 fread(u11Read, ndim*gvol*sizeof(Complex), 1, con);
184 fread(u12Read, ndim*gvol*sizeof(Complex), 1, con);
185 //The seed array will be used to gather and sort the seeds from each rank so they can be in a continuation run
186 //If less processors are used then only nproc seeds are used (breaking the Markov Chain)
187 //If more processors are used then we use the first seed to generate the rest as in Par_ranset
188#ifdef __RANLUX__
189 unsigned long *seed_array=(unsigned long*)calloc(nproc,sizeof(seed));
190#elif defined __USE_MKL__ && !defined USE_RAN2
191 int *seed_array=(int *)calloc(nproc,sizeof(seed));
192#else
193 long *seed_array=(long*)calloc(nproc,sizeof(seed));
194#endif
195 for(int i=0; i<fmin(old_nproc,nproc);i++)
196 fread(seed_array+i, sizeof(seed), 1, con);
197 fclose(con);
198 //Any remaining processors get their initial value set as is done in Par_ranset
199 for(int i=old_nproc; i<nproc; i++)
200 seed_array[i] = seed_array[0]*(1.0f+8.0f*(float)i/(float)(size-1));
201 if(!rank)
202 seed=seed_array[0];
203#if(nproc>1)
204 for(int iproc = 1; iproc<nproc; iproc++)
205 if(MPI_Send(&seed_array[iproc], 1, MPI_SEED_TYPE,iproc, 1, comm)){
206 fprintf(stderr, "Error %i in %s: Failed to send seed to process %i.\nExiting...\n\n",
207 CANTSEND, funcname, iproc);
208 MPI_Abort(comm,CANTSEND);
209 }
210#endif
211
212 for(int iproc = 0; iproc < nproc; iproc++)
213 for(int idim = 0; idim < ndim; idim++){
214 int i = 0;
215 //Index order is reversed from FORTRAN for performance
216 //Going to split up assigning icoord[i] to reduce the
217 //number of assignments.
218 //We're weaving our way through the memory here, converting
219 //between lattice and memory coordinates
220 for(int it=pstart[3][iproc]; it<pstop[3][iproc]; it++)
221 for(int iz=pstart[2][iproc]; iz<pstop[2][iproc]; iz++)
222 for(int iy=pstart[1][iproc]; iy<pstop[1][iproc]; iy++)
223 for(int ix=pstart[0][iproc]; ix<pstop[0][iproc]; ix++){
224 //j is the relative memory index of icoord
225 int j = Coord2gindex(ix,iy,iz,it);
226 //TODO: Don't change this for SoA. We can use this to flip the memory layout without calling a
227 //transpose
228 u1buff[i]=u11Read[idim*gvol+j];
229 u2buff[i]=u12Read[idim*gvol+j];
230 //C starts counting from zero, not 1 so increment afterwards or start at int i=-1
231 i++;
232 }
233 if(i!=kvol){
234 fprintf(stderr, "Error %i in %s: Number of elements %i is not equal to\
235 kvol %i.\nExiting...\n\n", NUMELEM, funcname, i, kvol);
236#if(nproc>1)
237 MPI_Abort(comm,NUMELEM);
238#else
239 exit(NUMELEM);
240#endif
241 }
242 if(!iproc){
243#ifdef USE_GPU
244 cudaMemcpy(u11+idim*kvol,u1buff,kvol*sizeof(Complex),cudaMemcpyDefault);
245 cudaMemcpy(u12+idim*kvol,u2buff,kvol*sizeof(Complex),cudaMemcpyDefault);
246#else
247 memcpy(u11+idim*kvol,u1buff,kvol*sizeof(Complex));
248 memcpy(u12+idim*kvol,u2buff,kvol*sizeof(Complex));
249#endif
250 }
251#if(nproc>1)
252 else{
253 //The master thread did all the hard work, the minions just need to receive their
254 //data and go.
255 if(MPI_Send(u1buff, kvol, MPI_C_DOUBLE_COMPLEX,iproc, 2*idim, comm)){
256 fprintf(stderr, "Error %i in %s: Failed to send ubuff to process %i.\nExiting...\n\n",
257 CANTSEND, funcname, iproc);
258#if(nproc>1)
259 MPI_Abort(comm,CANTSEND);
260#else
261 exit(CANTSEND);
262#endif
263 }
264 if(MPI_Send(u2buff, kvol, MPI_C_DOUBLE_COMPLEX,iproc, 2*idim+1, comm)){
265 fprintf(stderr, "Error %i in %s: Failed to send ubuff to process %i.\nExiting...\n\n",
266 CANTSEND, funcname, iproc);
267#if(nproc>1)
268 MPI_Abort(comm,CANTSEND);
269#else
270 exit(CANTSEND);
271#endif
272 }
273 }
274#endif
275 }
276 free(u11Read); free(u12Read);
277 free(seed_array);
278 }
279#if(nproc>1)
280 else{
281 if(MPI_Recv(&seed, 1, MPI_SEED_TYPE, masterproc, 1, comm, &status)){
282 fprintf(stderr, "Error %i in %s: Falied to receive seed on process %i.\nExiting...\n\n",
283 CANTRECV, funcname, rank);
284#if(nproc>1)
285 MPI_Abort(comm,CANTRECV);
286#else
287 exit(CANTRECV);
288#endif
289 }
290 for(int idim = 0; idim<ndim; idim++){
291 //Receiving the data from the master threads.
292 if(MPI_Recv(u1buff, kvol, MPI_C_DOUBLE_COMPLEX, masterproc, 2*idim, comm, &status)){
293 fprintf(stderr, "Error %i in %s: Falied to receive u11 on process %i.\nExiting...\n\n",
294 CANTRECV, funcname, rank);
295 MPI_Abort(comm,CANTRECV);
296 }
297 if(MPI_Recv(u2buff, kvol, MPI_C_DOUBLE_COMPLEX, masterproc, 2*idim+1, comm, &status)){
298 fprintf(stderr, "Error %i in %s: Falied to receive u12 on process %i.\nExiting...\n\n",
299 CANTRECV, funcname, rank);
300 MPI_Abort(comm,CANTRECV);
301 }
302#ifdef USE_GPU
303 cudaMemcpy(u11+idim*kvol,u1buff,kvol*sizeof(Complex),cudaMemcpyDefault);
304 cudaMemcpy(u12+idim*kvol,u2buff,kvol*sizeof(Complex),cudaMemcpyDefault);
305#else
306 memcpy(u11+idim*kvol,u1buff,kvol*sizeof(Complex));
307 memcpy(u12+idim*kvol,u2buff,kvol*sizeof(Complex));
308#endif
309 }
310 }
311#endif
312 free(u1buff); free(u2buff);
313 for(unsigned short mu=0;mu<ndim;mu++){
314#ifdef USE_GPU
315 cudaMemcpy(u11t+kvolHalo*mu, u11+kvol*mu, kvol*sizeof(Complex),cudaMemcpyDefault);
316 cudaMemcpy(u12t+kvolHalo*mu, u12+kvol*mu, kvol*sizeof(Complex),cudaMemcpyDefault);
317#else
318 memcpy(u11t+kvolHalo*mu, u11+kvol*mu, kvol*sizeof(Complex));
319 memcpy(u12t+kvolHalo*mu, u12+kvol*mu, kvol*sizeof(Complex));
320#endif
321 }
322 return 0;
323}
324int Par_swrite(const int itraj, const int icheck, const float beta, const float fmu, const float akappa,
325 const Complex_f ajq, const float c_sw, Complex *u11, Complex *u12){
326 const char funcname[] = "par_swrite";
327#if (nproc>1)
328 MPI_Status status;
329 //Used for seed array later on
330 MPI_Datatype MPI_SEED_TYPE = (sizeof(seed)==sizeof(int)) ? MPI_INT:MPI_LONG;
331#endif
332 Complex *u1buff = (Complex *)aligned_alloc(AVX,kvol*sizeof(Complex));
333 Complex *u2buff = (Complex *)aligned_alloc(AVX,kvol*sizeof(Complex));
334#ifdef _DEBUG
335 char dump_prefix[FILELEN]="u11.";
336 char dump_buff[32];
337 sprintf(dump_buff,"r%01d_c%06d",rank,itraj);
338 strcat(dump_prefix,dump_buff);
339 FILE *gauge_dump=fopen(dump_prefix,"wb");
340 //Print the local trial field in the order it is stored in memory.
341 //This is not the same order as it is stored in secondary storage
342 fwrite(u11,ndim*kvol*sizeof(Complex),1,gauge_dump);
343 fclose(gauge_dump);
344#endif
345#ifdef __RANLUX__
346 seed=gsl_rng_get(ranlux_instd);
347#endif
348 if(!rank){
349 //Array to store the seeds. nth index is the nth processor
350#ifdef __RANLUX__
351 unsigned long *seed_array=(unsigned long*)calloc(nproc,sizeof(seed));
352#elif defined __USE_MKL__ && !defined USE_RAN2
353 int *seed_array=(int *)calloc(nproc,sizeof(seed));
354#else
355 long *seed_array=(long*)calloc(nproc,sizeof(seed));
356#endif
357 seed_array[0]=seed;
358#if(nproc>1)
359 for(int iproc = 1; iproc<nproc; iproc++)
360 if(MPI_Recv(&seed_array[iproc], 1, MPI_SEED_TYPE,iproc, 1, comm, &status)){
361 fprintf(stderr, "Error %i in %s: Failed to receive seed from process %i.\nExiting...\n\n",
362 CANTRECV, funcname, iproc);
363 MPI_Abort(comm,CANTRECV);
364 }
365#endif
366 Complex *u11Write = (Complex *)aligned_alloc(AVX,ndim*gvol*sizeof(Complex));
367 Complex *u12Write = (Complex *)aligned_alloc(AVX,ndim*gvol*sizeof(Complex));
368 //Get correct parts of u11read etc from remote processors
369 for(int iproc=0;iproc<nproc;iproc++)
370 for(int idim=0;idim<ndim;idim++){
371#if(nproc>1)
372 if(iproc){
373 if(MPI_Recv(u1buff, kvol, MPI_C_DOUBLE_COMPLEX, iproc, 2*idim, comm, &status)){
374 fprintf(stderr, "Error %i in %s: Falied to receive u11 from process %i.\nExiting...\n\n",
375 CANTRECV, funcname, iproc);
376 MPI_Abort(comm,CANTRECV);
377 }
378 if(MPI_Recv(u2buff, kvol, MPI_C_DOUBLE_COMPLEX, iproc, 2*idim+1, comm, &status)){
379 fprintf(stderr, "Error %i in %s: Falied to receive u12 from process %i.\nExiting...\n\n",
380 CANTRECV, funcname, iproc);
381 MPI_Abort(comm,CANTRECV);
382 }
383 }
384 else{
385#endif
386 //No need to do MPI Send/Receive on the master rank
387 //Array looping is slow so we use memcpy instead
388#ifdef USE_GPU
389 cudaMemcpy(u1buff,u11+idim*kvol,kvol*sizeof(Complex),cudaMemcpyDefault);
390 cudaMemcpy(u2buff,u12+idim*kvol,kvol*sizeof(Complex),cudaMemcpyDefault);
391#else
392 memcpy(u1buff,u11+idim*kvol,kvol*sizeof(Complex));
393 memcpy(u2buff,u12+idim*kvol,kvol*sizeof(Complex));
394#endif
395#ifdef _DEBUG
396 char part_dump[FILELEN]="";
397 strcat(part_dump,dump_prefix);
398 sprintf(dump_buff,"_d%d",idim);
399 strcat(part_dump,dump_buff);
400 FILE *pdump=fopen(part_dump,"wb");
401 fwrite(u1buff,kvol*sizeof(Complex),1,pdump);
402 fclose(pdump);
403#endif
404#if(nproc>1)
405 }
406#endif
407 int i=0;
408 for(int it=pstart[3][iproc]; it<pstop[3][iproc]; it++)
409 for(int iz=pstart[2][iproc]; iz<pstop[2][iproc]; iz++)
410 for(int iy=pstart[1][iproc]; iy<pstop[1][iproc]; iy++)
411 for(int ix=pstart[0][iproc]; ix<pstop[0][iproc]; ix++){
412 //j is the relative memory index of icoord
413 int j = Coord2gindex(ix, iy, iz, it);
414 u11Write[idim*gvol+j] = u1buff[i];
415 u12Write[idim*gvol+j] = u2buff[i];
416 //C starts counting from zero, not 1 so increment afterwards or start at int i=-1
417 i++;
418 }
419 if(i!=kvol){
420 fprintf(stderr, "Error %i in %s: Number of elements %i is not equal to\
421 kvol %i.\nExiting...\n\n", NUMELEM, funcname, i, kvol);
422#if(nproc>1)
423 MPI_Abort(comm,NUMELEM);
424#else
425 exit(NUMELEM);
426#endif
427 }
428 }
429 free(u1buff); free(u2buff);
430
431 char gauge_title[FILELEN]="config.";
432 int buffer; char buff2[7];
433 //Add script for extracting correct mu, j etc.
434 buffer = (int)round(100*beta);
435 sprintf(buff2,"b%03d",buffer);
436 strcat(gauge_title,buff2);
437 //κ
438 buffer = (int)round(10000*akappa);
439 sprintf(buff2,"k%04d",buffer);
440 strcat(gauge_title,buff2);
441 //μ
442 buffer = (int)round(1000*fmu);
443 sprintf(buff2,"mu%04d",buffer);
444 strcat(gauge_title,buff2);
445 //J
446 buffer = (int)round(1000*creal(ajq));
447 sprintf(buff2,"j%03d",buffer);
448 strcat(gauge_title,buff2);
449 //c_sw
450 if(c_sw!=0){
451 buffer = (int)round(100*c_sw);
452 sprintf(buff2,"c%02d",buffer);
453 strcat(gauge_title,buff2);
454 }
455 //nx
456 sprintf(buff2,"s%02d",nx);
457 strcat(gauge_title,buff2);
458 //nt
459 sprintf(buff2,"t%02d",nt);
460 strcat(gauge_title,buff2);
461
462 char gauge_file[FILELEN];
463 strcpy(gauge_file,gauge_title);
464 char c[8];
465 sprintf(c,".%06d", itraj);
466 strcat(gauge_file, c);
467 printf("Gauge file name is %s\n", gauge_file);
468 printf("Writing the gauge file on processor %i.\n", rank);
469 FILE *con;
470 char *fileop = "wb";
471 if(!(con=fopen(gauge_file, fileop))){
472 fprintf(stderr, "Error %i in %s: Failed to open %s for %s.\
473 \nExiting...\n\n", OPENERROR, funcname, gauge_file, fileop);
474#if(nproc>1)
475 MPI_Abort(comm,OPENERROR);
476#else
477 exit(OPENERROR);
478#endif
479 }
480 //TODO: SAFETY CHECKS FOR EACH WRITE OPERATION
481 //Write the number of processors used in the previous run. This takes the place of the FORTRAN integer rather nicely
482#if(nproc==1)
483 int size=nproc;
484#endif
485 fwrite(&size,sizeof(int),1,con);
486 fwrite(u11Write, ndim*gvol*sizeof(Complex), 1, con);
487 fwrite(u12Write, ndim*gvol*sizeof(Complex), 1, con);
488 //TODO
489 //Make a seed array, where the nth component is the seed on the nth rank for continuation runs.
490 fwrite(seed_array, nproc*sizeof(seed), 1, con);
491 fclose(con);
492 free(u11Write); free(u12Write);
493 free(seed_array);
494 }
495#if(nproc>1)
496 else{
497 if(MPI_Send(&seed, 1, MPI_SEED_TYPE, masterproc, 1, comm)){
498 fprintf(stderr, "Error %i in %s: Falied to send u11 from process %i.\nExiting...\n\n",
499 CANTSEND, funcname, rank);
500 MPI_Abort(comm,CANTSEND);
501 }
502 for(int idim = 0; idim<ndim; idim++){
503#ifdef USE_GPU
504 cudaMemcpy(u1buff,u11+idim*kvol,kvol*sizeof(Complex),cudaMemcpyDefault);
505 cudaMemcpy(u2buff,u12+idim*kvol,kvol*sizeof(Complex),cudaMemcpyDefault);
506#else
507 memcpy(u1buff,u11+idim*kvol,kvol*sizeof(Complex));
508 memcpy(u2buff,u12+idim*kvol,kvol*sizeof(Complex));
509#endif
510#ifdef _DEBUG
511 char part_dump[FILELEN]="";
512 strcat(part_dump,dump_prefix);
513 sprintf(dump_buff,"_d%d",idim);
514 strcat(part_dump,dump_buff);
515 FILE *pdump=fopen(part_dump,"wb");
516 fwrite(u1buff,kvol*sizeof(Complex),1,pdump);
517 fclose(pdump);
518#endif
519 int i=0;
520 if(MPI_Send(u1buff, kvol, MPI_C_DOUBLE_COMPLEX, masterproc, 2*idim, comm)){
521 fprintf(stderr, "Error %i in %s: Falied to send u11 from process %i.\nExiting...\n\n",
522 CANTSEND, funcname, rank);
523 MPI_Abort(comm,CANTSEND);
524 }
525 if(MPI_Send(u2buff, kvol, MPI_C_DOUBLE_COMPLEX, masterproc, 2*idim+1, comm)){
526 fprintf(stderr, "Error %i in %s: Falied to send u12 from process %i.\nExiting...\n\n",
527 CANTSEND, funcname, rank);
528 MPI_Abort(comm,CANTSEND);
529 }
530 }
531 free(u1buff); free(u2buff);
532 }
533#endif
534 return 0;
535}
536//To be lazy, we've got modules to help us do reductions and broadcasts with a single argument
537//rather than type them all every single time
538#if(nproc>1)
539inline int Par_isum(int *ival){
540 const char funcname[] = "Par_isum";
541 //Container to receive data.
542 int *itmp;
543
544 if(MPI_Allreduce(ival, itmp, 1, MPI_INTEGER, MPI_SUM, comm)){
545 fprintf(stderr,"Error %i in %s: Couldn't complete reduction for %i.\nExiting...\n\n", REDUCERR, funcname, *ival);
546 MPI_Abort(comm,REDUCERR);
547 }
548 return 0;
549}
550inline int Par_dsum(double *dval){
551 const char funcname[] = "Par_dsum";
552 //Container to receive data.
553 double dtmp;
554
555 if(MPI_Allreduce(dval, &dtmp, 1, MPI_DOUBLE, MPI_SUM, comm)){
556 fprintf(stderr,"Error %i in %s: Couldn't complete reduction for %f.\nExiting...\n\n", REDUCERR, funcname, *dval);
557 MPI_Abort(comm,REDUCERR);
558 }
559 *dval = dtmp;
560 return 0;
561}
562inline int Par_fsum(float *fval){
563 const char funcname[] = "far_dsum";
564 //Container to receive data.
565 float ftmp;
566
567 if(MPI_Allreduce(fval, &ftmp, 1, MPI_FLOAT, MPI_SUM, comm)){
568 fprintf(stderr,"Error %i in %s: Couldn't complete reduction for %f.\nExiting...\n\n", REDUCERR, funcname, *fval);
569 MPI_Abort(comm,REDUCERR);
570 }
571 *fval = ftmp;
572 return 0;
573}
574inline int Par_csum(Complex_f *cval){
575 const char funcname[] = "Par_csum";
576 //Container to receive data.
577 Complex_f ctmp;
578
579 if(MPI_Allreduce(cval, &ctmp, 1, MPI_C_FLOAT_COMPLEX, MPI_SUM, comm)){
580#ifndef USE_GPU
581 fprintf(stderr, "Error %i in %s: Couldn't complete reduction for %f+%f i.\nExiting...\n\n",
582 REDUCERR, funcname, creal(*cval), cimag(*cval));
583#endif
584 MPI_Abort(comm,REDUCERR);
585 }
586 *cval = ctmp;
587 return 0;
588}
589inline int Par_zsum(Complex *zval){
590 const char funcname[] = "Par_zsum";
591 //Container to receive data.
592 Complex ztmp;
593
594 if(MPI_Allreduce(zval, &ztmp, 1, MPI_C_DOUBLE_COMPLEX, MPI_SUM, comm)){
595#ifndef USE_GPU
596 fprintf(stderr, "Error %i in %s: Couldn't complete reduction for %f+%f i.\nExiting...\n\n",
597 REDUCERR, funcname, creal(*zval), cimag(*zval));
598#endif
599 MPI_Abort(comm,REDUCERR);
600 }
601 *zval = ztmp;
602 return 0;
603}
604inline int Par_icopy(int *ival){
605 const char funcname[] = "Par_icopy";
606 if(MPI_Bcast(ival,1,MPI_INT,masterproc,comm)){
607 fprintf(stderr, "Error %i in %s: Failed to broadcast %i from %i.\nExiting...\n\n",
608 BROADERR, funcname, *ival, rank);
609 MPI_Abort(comm,BROADERR);
610 }
611 return 0;
612}
613inline int Par_dcopy(double *dval){
614 const char funcname[] = "Par_dcopy";
615 if(MPI_Bcast(dval,1,MPI_DOUBLE,masterproc,comm)){
616 fprintf(stderr, "Error %i in %s: Failed to broadcast %f from %i.\nExiting...\n\n",
617 BROADERR, funcname, *dval, rank);
618 MPI_Abort(comm,BROADERR);
619 }
620 return 0;
621}
622inline int Par_fcopy(float *fval){
623 const char funcname[] = "Par_dfopy";
624 if(MPI_Bcast(fval,1,MPI_FLOAT,masterproc,comm)){
625 fprintf(stderr, "Error %i in %s: Failed to broadcast %f from %i.\nExiting...\n\n",
626 BROADERR, funcname, *fval, rank);
627 MPI_Abort(comm,BROADERR);
628 }
629 return 0;
630}
631inline int Par_ccopy(Complex *cval){
632 const char funcname[] = "Par_ccopy";
633 if(MPI_Bcast(cval,1,MPI_C_FLOAT_COMPLEX,masterproc,comm)){
634#ifndef USE_GPU
635 fprintf(stderr, "Error %i in %s: Failed to broadcast %f+i%f from %i.\nExiting...\n\n",
636 BROADERR, funcname, creal(*cval), cimag(*cval), rank);
637#endif
638 MPI_Abort(comm,BROADERR);
639 }
640 return 0;
641}
642inline int Par_zcopy(Complex *zval){
643 const char funcname[] = "Par_zcopy";
644 if(MPI_Bcast(zval,1,MPI_C_DOUBLE_COMPLEX,masterproc,comm)){
645#ifndef USE_GPU
646 fprintf(stderr, "Error %i in %s: Failed to broadcast %f+i%f from %i.\nExiting...\n\n",
647 BROADERR, funcname, creal(*zval), cimag(*zval), rank);
648#endif
649 MPI_Abort(comm,BROADERR);
650 }
651 return 0;
652}
653
654/* Code for swapping halos.
655 * In the original FORTRAN there were separate subroutines for up and down halos
656 * To make code maintenance easier I'm going to implement this with switches
657 * and common functions
658 * We will define in su2hmc UP and DOWN. And add a parameter called layer to
659 * functions. layer will be used to tell us if we wanted to call the up FORTRAN
660 * function or DOWN FORTRAN function
661 */
662inline int ZHalo_swap_all(Complex *z, int ncpt){
663 const char funcname[] = "ZHalo_swap_all";
664
665 //FORTRAN called zdnhaloswapall and zuphaloswapall here
666 //Those functions looped over the directions and called zXXhaloswapdir
667 //As the only place they are called in the FORTRAN code is right here,
668 //I'm going to omit them entirely and just put the direction loop here
669 //instead
670 //Unrolling the loop so we can have pre-processor directives for each dimension
671#if(npx>1)
672 ZHalo_swap_dir(z, ncpt, 0, DOWN);
673 ZHalo_swap_dir(z, ncpt, 0, UP);
674#endif
675#if(npy>1)
676 ZHalo_swap_dir(z, ncpt, 1, DOWN);
677 ZHalo_swap_dir(z, ncpt, 1, UP);
678#endif
679#if(npz>1)
680 ZHalo_swap_dir(z, ncpt, 2, DOWN);
681 ZHalo_swap_dir(z, ncpt, 2, UP);
682#endif
683#if(npt>1)
684 ZHalo_swap_dir(z, ncpt, 3, DOWN);
685 ZHalo_swap_dir(z, ncpt, 3, UP);
686#endif
687 return 0;
688}
689int ZHalo_swap_dir(Complex *z, int ncpt, int idir, int layer){
690 const char funcname[] = "ZHalo_swap_dir";
691 if(layer!=DOWN && layer!=UP){
692 fprintf(stderr, "Error %i in %s: Cannot swap in the direction given by %i.\nExiting...\n\n",
693 LAYERROR, funcname, layer);
694 MPI_Abort(comm,BROADERR);
695 }
696 //How big is the data being sent and received
697 //#pragma omp parallel for
698 for(unsigned short icpt=0;icpt<ncpt;icpt++){
699#ifdef _DEBUG_MPI
700 printf("Rank %d: Function %s: dir: %d icpt= %d of %d\n",rank, funcname, idir, icpt,ncpt);
701#endif
702 MPI_Request req; MPI_Status stat;
703 Complex *sendbuff = (Complex *)aligned_alloc(AVX,halosize[idir]*sizeof(Complex));
704 switch(layer){
705 case(DOWN):
706 if(halosize[idir]+h1u[idir]>kvol+halo){
707 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
708 "a memory leak on rank %i.\nExiting...\n\n"
709 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1u[idir], rank);
710 MPI_Abort(comm,BOUNDERROR);
711 }
712#pragma omp simd aligned(sendbuff,z:AVX)
713 //In each case we set up the data being sent then do the exchange
714 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
715 sendbuff[ihalo]=z[hd[ndim*ihalo+idir]+kvolHalo*icpt];
716 //For the zdnhaloswapdir we send off the down halo and receive into the up halo
717 if(MPI_Isend(sendbuff, halosize[idir], MPI_C_DOUBLE_COMPLEX, pd[idir], icpt, comm, &req)){
718 fprintf(stderr,"Error %i in %s: Failed to send off the down halo from rank %i to rank %i.\nExiting...\n"
719 ,CANTSEND, funcname, rank, pd[idir]);
720 MPI_Abort(comm,CANTSEND);
721 }
722 if(MPI_Recv(z+h1u[idir]+kvolHalo*icpt, halosize[idir], MPI_C_DOUBLE_COMPLEX, pu[idir], icpt, comm, &stat)){
723 fprintf(stderr,"Error %i in %s: Rank %i failed to receive into up halo from rank %i.\nExiting...\n",
724 CANTRECV, funcname, rank, pu[idir]);
725 MPI_Abort(comm,CANTRECV);
726 }
727 break;
728 case(UP):
729 if(halosize[idir]+h1d[idir]>kvol+halo){
730 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
731 "a memory leak on rank %i.\nExiting...\n\n"
732 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1d[idir], rank);
733 MPI_Abort(comm,BOUNDERROR);
734 }
735#pragma omp simd aligned(sendbuff,z:AVX)
736 //In each case we set up the data being sent then do the exchange
737 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
738 sendbuff[ihalo]=z[hu[ndim*ihalo+idir]+kvolHalo*icpt];
739 //For the zuphaloswapdir we send off the up halo and receive into the down halo
740 if(MPI_Isend(sendbuff, halosize[idir], MPI_C_DOUBLE_COMPLEX, pu[idir], icpt, comm, &req)){
741 fprintf(stderr,"Error %i in %s: Failed to send off the up halo from rank %i to rank %i.\nExiting...\n",
742 CANTSEND, funcname, rank, pu[idir]);
743 MPI_Abort(comm,CANTSEND);
744 }
745 if(MPI_Recv(z+h1d[idir]+kvolHalo*icpt, halosize[idir], MPI_C_DOUBLE_COMPLEX, pd[idir], icpt, comm, &stat)){
746 fprintf(stderr,"Error %i in %s: Rank %i failed to receive into doww halo from rank %i.\nExiting...\n",
747 CANTRECV, funcname, rank, pd[idir]);
748 MPI_Abort(comm,CANTRECV);
749 }
750 break;
751 }
752 MPI_Wait(&req, &stat);
753 free(sendbuff);
754 }
755 return 0;
756}
757inline int CHalo_swap_all(Complex_f *c, int ncpt){
758 const char funcname[] = "CHalo_swap_all";
759
760 //FORTRAN called zdnhaloswapall and zuphaloswapall here
761 //Those functions looped over the directions and called zXXhaloswapdir
762 //As the only place they are called in the FORTRAN code is right here,
763 //I'm going to omit them entirely and just put the direction loop here
764 //instead
765 //Unrolling the loop so we can have pre-processor directives for each dimension
766#if(npx>1)
767 CHalo_swap_dir(c, ncpt, 0, DOWN);
768 CHalo_swap_dir(c, ncpt, 0, UP);
769#endif
770#if(npy>1)
771 CHalo_swap_dir(c, ncpt, 1, DOWN);
772 CHalo_swap_dir(c, ncpt, 1, UP);
773#endif
774#if(npz>1)
775 CHalo_swap_dir(c, ncpt, 2, DOWN);
776 CHalo_swap_dir(c, ncpt, 2, UP);
777#endif
778#if(npt>1)
779 CHalo_swap_dir(c, ncpt, 3, DOWN);
780 CHalo_swap_dir(c, ncpt, 3, UP);
781#endif
782 return 0;
783}
784int CHalo_swap_dir(Complex_f *c, int ncpt, int idir, int layer){
785 const char funcname[] = "CHalo_swap_dir";
786 if(layer!=DOWN && layer!=UP){
787 fprintf(stderr, "Error %i in %s: Cannot swap in the direction given by %i.\nExiting...\n\n",
788 LAYERROR, funcname, layer);
789 MPI_Abort(comm,LAYERROR);
790 }
791 //#pragma omp parallel for
792 for(unsigned short icpt=0;icpt<ncpt;icpt++){
793#ifdef _DEBUG_MPI
794 printf("Rank %d: Function %s: dir: %d icpt= %d of %d\n",rank, funcname, idir, icpt,ncpt);
795#endif
796 MPI_Request req; MPI_Status stat;
797 Complex_f *sendbuff = (Complex_f *)aligned_alloc(AVX,halosize[idir]*sizeof(Complex_f));
798 switch(layer){
799 case(DOWN):
800 if(halosize[idir]+h1u[idir]>kvol+halo){
801 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
802 "a memory leak on rank %i.\nExiting...\n\n"
803 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1u[idir], rank);
804 MPI_Abort(comm,BOUNDERROR);
805 }
806 //In each case we set up the data being sent then do the exchange
807#pragma omp simd aligned(sendbuff,c:AVX)
808 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
809 sendbuff[ihalo]=c[hd[ndim*ihalo+idir]+kvolHalo*icpt];
810 //For the cdnhaloswapdir we send off the down halo and receive into the up halo
811 if(MPI_Isend(sendbuff, halosize[idir], MPI_C_FLOAT_COMPLEX, pd[idir], icpt, comm, &req)){
812 fprintf(stderr,"Error %i in %s: Failed to send off the down halo from rank %i to rank %i.\nExiting...\n"
813 ,CANTSEND, funcname, rank, pd[idir]);
814 MPI_Abort(comm,CANTSEND);
815 }
816 if(MPI_Recv(c+h1u[idir]+kvolHalo*icpt, halosize[idir], MPI_C_FLOAT_COMPLEX, pu[idir], icpt, comm, &stat)){
817 fprintf(stderr,"Error %i in %s: Rank %i failed to receive into up halo from rank %i.\nExiting...\n",
818 CANTRECV, funcname, rank, pu[idir]);
819 MPI_Abort(comm,CANTRECV);
820 }
821 break;
822 case(UP):
823 if(halosize[idir]+h1d[idir]>kvol+halo){
824 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
825 "a memory leak on rank %i.\nExiting...\n\n"
826 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1d[idir], rank);
827 MPI_Abort(comm,BOUNDERROR);
828 }
829#pragma omp simd aligned(sendbuff,c:AVX)
830 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
831 sendbuff[ihalo]=c[hu[ndim*ihalo+idir]+kvolHalo*icpt];
832 //For the cuphaloswapdir we send off the up halo and receive into the down halo
833 if(MPI_Isend(sendbuff, halosize[idir], MPI_C_FLOAT_COMPLEX, pu[idir], icpt, comm, &req)){
834 fprintf(stderr,"Error %i in %s: Failed to send off the up halo from rank %i to rank %i.\nExiting...\n",
835 CANTSEND, funcname, rank, pu[idir]);
836 MPI_Abort(comm,CANTSEND);
837 }
838 if(MPI_Recv(c+h1d[idir]+kvolHalo*icpt, halosize[idir], MPI_C_FLOAT_COMPLEX, pd[idir], icpt, comm, &stat)){
839 fprintf(stderr,"Error %i in %s: Rank %i failed to receive into doww halo from rank %i.\nExiting...\n",
840 CANTRECV, funcname, rank, pd[idir]);
841 MPI_Abort(comm,CANTRECV);
842 }
843 break;
844 }
845 MPI_Wait(&req, &stat);
846 free(sendbuff);
847 }
848 return 0;
849}
850inline int DHalo_swap_all(double *d, int ncpt){
851 const char funcname[] = "DHalo_swap_all";
852
853 //FORTRAN called zdnhaloswapall and zuphaloswapall here
854 //Those functions looped over the directions and called zXXhaloswapdir
855 //As the only place they are called in the FORTRAN code is right here,
856 //I'm going to omit them entirely and just put the direction loop here
857 //instead
858 //Unrolling the loop so we can have pre-processor directives for each dimension
859#if(npx>1)
860 DHalo_swap_dir(d, ncpt, 0, DOWN);
861 DHalo_swap_dir(d, ncpt, 0, UP);
862#endif
863#if(npy>1)
864 DHalo_swap_dir(d, ncpt, 1, DOWN);
865 DHalo_swap_dir(d, ncpt, 1, UP);
866#endif
867#if(npz>1)
868 DHalo_swap_dir(d, ncpt, 2, DOWN);
869 DHalo_swap_dir(d, ncpt, 2, UP);
870#endif
871#if(npt>1)
872 DHalo_swap_dir(d, ncpt, 3, DOWN);
873 DHalo_swap_dir(d, ncpt, 3, UP);
874#endif
875 return 0;
876}
877int DHalo_swap_dir(double *d, int ncpt, int idir, int layer){
878 const char funcname[] = "DHalo_swap_dir";
879 //How big is the data being sent and received
880 if(layer!=DOWN && layer!=UP){
881 fprintf(stderr, "Error %i in %s: Cannot swap in the direction given by %i.\nExiting...\n\n",
882 LAYERROR, funcname, layer);
883 MPI_Abort(comm,LAYERROR);
884 }
885 //#pragma omp parallel for
886 for(unsigned short icpt=0;icpt<ncpt;icpt++){
887#ifdef _DEBUG_MPI
888 printf("Rank %d: Function %s: dir: %d icpt= %d of %d\n",rank, funcname, idir, icpt,ncpt);
889#endif
890 //Implement the switch. The code is taken from the end of the dedicated functions in the FORTRAN code.
891 MPI_Request req; MPI_Status stat;
892 double *sendbuff = (double *)aligned_alloc(AVX,halosize[idir]*sizeof(double));
893 switch(layer){
894 case(DOWN):
895 if(halosize[idir]+h1u[idir]>kvol+halo){
896 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
897 "a memory leak on rank %i.\nExiting...\n\n"
898 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1u[idir], rank);
899 MPI_Abort(comm,BOUNDERROR);
900 }
901 //In each case we set up the data being sent then do the exchange
902#pragma omp simd aligned(sendbuff,d:AVX)
903 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
904 sendbuff[ihalo]=d[hd[ndim*ihalo+idir]+kvolHalo*icpt];
905 //For the ddnhaloswapdir we send off the down halo and receive into the up halo
906 if(MPI_Isend(sendbuff, halosize[idir], MPI_DOUBLE, pd[idir], icpt, comm, &req)){
907 fprintf(stderr, "Error %i in %s: Failed to send off the down halo from rank %i to rank %i.\nExiting...\n\n",
908 CANTSEND, funcname, rank, pd[idir]);
909 MPI_Abort(comm,CANTSEND);
910 }
911 if(MPI_Recv(d+h1u[idir]+kvolHalo*icpt, halosize[idir], MPI_DOUBLE, pu[idir], icpt, comm, &stat)){
912 fprintf(stderr, "Error %i in %s: Rank %i failed to receive into up halo from rank %i.\nExiting...\n\n",
913 CANTRECV, funcname, rank, pu[idir]);
914 MPI_Abort(comm,CANTRECV);
915 }
916 break;
917 case(UP):
918 if(halosize[idir]+h1d[idir]>kvol+halo){
919 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
920 "a memory leak on rank %i.\nExiting...\n\n"
921 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1d[idir], rank);
922 MPI_Abort(comm,BOUNDERROR);
923 }
924#pragma omp simd aligned(sendbuff,d:AVX)
925 //In each case we set up the data being sent then do the exchange
926 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
927 sendbuff[ihalo]=d[hu[ndim*ihalo+idir]+kvolHalo*icpt];
928 //For the duphaloswapdir we send off the up halo and receive into the down halo
929 if(MPI_Isend(sendbuff, halosize[idir], MPI_DOUBLE, pu[idir], icpt, comm, &req)){
930 fprintf(stderr,"Error %i in %s: Failed to send off the up halo from rank %i to rank %i.\nExiting...\n\n",
931 CANTSEND, funcname, rank, pu[idir]);
932 MPI_Abort(comm,CANTSEND);
933 }
934 if(MPI_Recv(d+h1d[idir]+kvolHalo*icpt, halosize[idir], MPI_DOUBLE, pd[idir], icpt, comm, &stat)){
935 fprintf(stderr, "Error %i in %s: Rank %i failed to receive into doww halo from rank %i.\nExiting...\n\n",
936 CANTRECV, funcname, rank, pd[idir]);
937 MPI_Abort(comm,CANTRECV);
938 }
939 break;
940 }
941 MPI_Wait(&req, &stat);
942 free(sendbuff);
943 }
944 return 0;
945}
946inline int SHalo_swap_all(float *d, int ncpt){
947 const char funcname[] = "SHalo_swap_all";
948
949 //FORTRAN called zdnhaloswapall and zuphaloswapall here
950 //Those functions looped over the directions and called zXXhaloswapdir
951 //As the only place they are called in the FORTRAN code is right here,
952 //I'm going to omit them entirely and just put the direction loop here
953 //instead
954 //Unrolling the loop so we can have pre-processor directives for each dimension
955#if(npx>1)
956 SHalo_swap_dir(d, ncpt, 0, DOWN);
957 SHalo_swap_dir(d, ncpt, 0, UP);
958#endif
959#if(npy>1)
960 SHalo_swap_dir(d, ncpt, 1, DOWN);
961 SHalo_swap_dir(d, ncpt, 1, UP);
962#endif
963#if(npz>1)
964 SHalo_swap_dir(d, ncpt, 2, DOWN);
965 SHalo_swap_dir(d, ncpt, 2, UP);
966#endif
967#if(npt>1)
968 SHalo_swap_dir(d, ncpt, 3, DOWN);
969 SHalo_swap_dir(d, ncpt, 3, UP);
970#endif
971 return 0;
972}
973int SHalo_swap_dir(float *d, int ncpt, int idir, int layer){
974 const char funcname[] = "SHalo_swap_dir";
975 //How big is the data being sent and received
976 if(layer!=DOWN && layer!=UP){
977 fprintf(stderr, "Error %i in %s: Cannot swap in the direction given by %i.\nExiting...\n\n",
978 LAYERROR, funcname, layer);
979 MPI_Abort(comm,LAYERROR);
980 }
981 //#pragma omp parallel for
982 for(unsigned short icpt=0;icpt<ncpt;icpt++){
983#ifdef _DEBUG_MPI
984 printf("Rank %d: Function %s: dir: %d icpt= %d of %d\n",rank, funcname, idir, icpt,ncpt);
985#endif
986 //Implement the switch. The code is taken from the end of the dedicated functions in the FORTRAN code.
987 MPI_Request req; MPI_Status stat;
988 float *sendbuff = (float *)aligned_alloc(AVX,halosize[idir]*sizeof(float));
989 switch(layer){
990 case(DOWN):
991 if(halosize[idir]+h1u[idir]>kvol+halo){
992 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
993 "a memory leak on rank %i.\nExiting...\n\n"
994 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1u[idir], rank);
995 MPI_Abort(comm,BOUNDERROR);
996 }
997 //In each case we set up the data being sent then do the exchange
998#pragma omp simd aligned(sendbuff,d:AVX)
999 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
1000 sendbuff[ihalo]=d[hd[ndim*ihalo+idir]+kvolHalo*icpt];
1001 //For the sdnhaloswapdir we send off the down halo and receive into the up halo
1002 if(MPI_Isend(sendbuff, halosize[idir], MPI_FLOAT, pd[idir], icpt, comm, &req)){
1003 fprintf(stderr, "Error %i in %s: Failed to send off the down halo from rank %i to rank %i.\nExiting...\n\n",
1004 CANTSEND, funcname, rank, pd[idir]);
1005 MPI_Abort(comm,CANTSEND);
1006 }
1007 if(MPI_Recv(d+h1u[idir]+kvolHalo*icpt, halosize[idir], MPI_FLOAT, pu[idir], icpt, comm, &stat)){
1008 fprintf(stderr, "Error %i in %s: Rank %i failed to receive into up halo from rank %i.\nExiting...\n\n",
1009 CANTRECV, funcname, rank, pu[idir]);
1010 MPI_Abort(comm,CANTRECV);
1011 }
1012 break;
1013 case(UP):
1014 if(halosize[idir]+h1d[idir]>kvol+halo){
1015 fprintf(stderr, "Error %i in %s: Writing a message of size %i to flattened index %i will cause "\
1016 "a memory leak on rank %i.\nExiting...\n\n"
1017 ,BOUNDERROR, funcname, halosize[idir], ncpt*h1d[idir], rank);
1018 MPI_Abort(comm,BOUNDERROR);
1019 }
1020#pragma omp simd aligned(sendbuff,d:AVX)
1021 //In each case we set up the data being sent then do the exchange
1022 for(int ihalo = 0; ihalo < halosize[idir]; ihalo++)
1023 sendbuff[ihalo]=d[hu[ndim*ihalo+idir]+kvolHalo*icpt];
1024 //For the suphaloswapdir we send off the up halo and receive into the down halo
1025 if(MPI_Isend(sendbuff, halosize[idir], MPI_FLOAT, pu[idir], icpt, comm, &req)){
1026 fprintf(stderr,"Error %i in %s: Failed to send off the up halo from rank %i to rank %i.\nExiting...\n\n",
1027 CANTSEND, funcname, rank, pu[idir]);
1028 MPI_Abort(comm,CANTSEND);
1029 }
1030 if(MPI_Recv(d+h1d[idir]+kvolHalo*icpt, halosize[idir], MPI_FLOAT, pd[idir], icpt, comm, &stat)){
1031 fprintf(stderr, "Error %i in %s: Rank %i failed to receive into doww halo from rank %i.\nExiting...\n\n",
1032 CANTRECV, funcname, rank, pd[idir]);
1033 MPI_Abort(comm,CANTRECV);
1034 }
1035 break;
1036 }
1037 MPI_Wait(&req, &stat);
1038 free(sendbuff);
1039 }
1040 return 0;
1041}
1042#endif
1043int Trial_Exchange(Complex *ut[2],Complex_f *ut_f[2]){
1044 /*
1045 * Exchanges the trial fields. I noticed that this halo exchange was happening
1046 * even though the trial fields hadn't been updated. To get around this
1047 * I'm making a function that does the halo exchange and only calling it after
1048 * the trial fields get updated.
1049 */
1050 const char *funchame = "Trial_Exchange";
1051 //Prefetch the trial fields from the GPU, halos come later
1052#if(nproc>1)
1053#ifdef USE_GPU
1054 int device=-1;
1055 cudaGetDevice(&device);
1056 Complex *z;
1057#ifdef _DEBUG
1058 cudaMallocManaged((void **)&z,kvolHalo*sizeof(Complex),cudaMemAttachGlobal);
1059#else
1060 cudaMallocAsync((void **)&z,kvolHalo*sizeof(Complex),streams[0]);
1061#endif
1063#else
1064 Complex *z = (Complex *)aligned_alloc(AVX,kvolHalo*sizeof(Complex));
1065#endif
1066 // ZHalo_swap_all(ut[0],ndim); ZHalo_swap_all(ut[1],ndim);
1067 //
1068 for(int mu=0;mu<ndim;mu++){
1069 //Copy the column from ut[0]
1070#ifdef USE_GPU
1071 cudaMemcpy(z,ut[0]+kvolHalo*mu,kvol*sizeof(Complex),cudaMemcpyDefault);
1072#else
1073 memcpy(z,ut[0]+kvolHalo*mu,kvol*sizeof(Complex));
1074#endif
1075
1076 //Halo exchange on that column
1077 ZHalo_swap_all(z, 1);
1078 //And the swap back/getting the next halo
1079#ifdef USE_GPU
1080 cudaMemcpy(ut[0]+kvolHalo*mu,z,kvolHalo*sizeof(Complex),cudaMemcpyDefault);
1081 cudaMemcpy(z,ut[1]+kvolHalo*mu,kvol*sizeof(Complex),cudaMemcpyDefault);
1082#else
1083 memcpy(ut[0]+kvolHalo*mu,z,kvolHalo*sizeof(Complex));
1084 memcpy(z,ut[1]+kvolHalo*mu,kvol*sizeof(Complex));
1085#endif
1086
1087 //Repeat
1088 ZHalo_swap_all(z, 1);
1089#ifdef USE_GPU
1090 cudaMemcpy(ut[1]+kvolHalo*mu,z,kvolHalo*sizeof(Complex),cudaMemcpyDefault);
1091#else
1092 memcpy(ut[1]+kvolHalo*mu,z,kvolHalo*sizeof(Complex));
1093#endif
1094 }
1095 //Now we prefetch the halo
1096 //And get the single precision gauge fields preppeed
1097 //Since we want the halos converted too set the stride to one
1098#ifdef USE_GPU
1099#ifdef _DEBUG
1100 cudaFree(z);
1101#else
1102 cudaFreeAsync(z,streams[0]);
1103#endif
1105#else
1106 free(z);
1107#endif
1108#endif
1109 ComplexConvert(ut_f[0],ut[0],ndim*kvolHalo,true,1);
1110 ComplexConvert(ut_f[1],ut[1],ndim*kvolHalo,true,1);
1111 return 0;
1112}
1113#if(npt>1)
1114int Par_tmul(Complex_f *z11, Complex_f *z12){
1115#ifdef __NVCC_
1116#error Par_tmul is not yet implimented in CUDA as Sigma12 in Polyakov is device only memory
1117#endif
1118 MPI_Status status;
1119 const char funcname[] = "Par_tmul";
1120 Complex_f *a11, *a12, *t11, *t12;
1121 int i, itime;
1122
1123 a11=(Complex_f *)aligned_alloc(AVX,kvol3*sizeof(Complex_f));
1124 a12=(Complex_f *)aligned_alloc(AVX,kvol3*sizeof(Complex_f));
1125 t11=(Complex_f *)aligned_alloc(AVX,kvol3*sizeof(Complex_f));
1126 t12=(Complex_f *)aligned_alloc(AVX,kvol3*sizeof(Complex_f));
1127 //Initialise for the first loop
1128 memcpy(a11, z11, kvol3*sizeof(Complex_f));
1129 memcpy(a12, z12, kvol3*sizeof(Complex_f));
1130
1131 //Since the index of the outer loop isn't used as an array index anywhere
1132 //I'm going format it exactly like the original FORTRAN
1133#ifdef _DEBUG
1134 if(!rank) printf("Sending between halos in the time direction. For rank %i pu[3]=%i and pd[3] = %i\n",
1135 rank, pu[3], pd[3]);
1136#endif
1137 for(itime=1;itime<npt; itime++){
1138 memcpy(t11, a11, kvol3*sizeof(Complex_f));
1139 memcpy(t12, a12, kvol3*sizeof(Complex_f));
1140#ifdef _DEBUG
1141 if(!rank) printf("t11 and t12 assigned. Getting ready to send to other processes.\n");
1142#endif
1143 //Send results to other processes down the line
1144 //What I don't quite get (except possibly avoiding race conditions) is
1145 //why we send t11 and not a11. Surely by eliminating the assignment of a11 to t11
1146 //and using a blocking send we would have one fewer loop to worry about and improve performance?
1147 if(MPI_Isend(t11, kvol3, MPI_C_FLOAT_COMPLEX, pd[3], tag, comm, &request)){
1148 fprintf(stderr, "Error %i in %s: Failed to send t11 to process %i.\nExiting...\n\n",
1149 CANTSEND, funcname, pd[3]);
1150 MPI_Abort(comm,CANTSEND);
1151 }
1152#ifdef _DEBUG
1153 printf("Sent t11 from rank %i to the down halo on rank %i\n", rank, pd[3]);
1154#endif
1155 if(MPI_Recv(a11, kvol3, MPI_C_FLOAT_COMPLEX, pu[3], tag, comm, &status)){
1156 fprintf(stderr, "Error %i in %s: Failed to receive a11 from process %i.\nExiting...\n\n",
1157 CANTSEND, funcname, pu[3]);
1158 MPI_Abort(comm,CANTSEND);
1159 }
1160#ifdef _DEBUG
1161 printf("Received t11 from rank %i in the up halo on rank %i\n", pu[3], rank);
1162#endif
1163 MPI_Wait(&request, &status);
1164 if(MPI_Isend(t12, kvol3, MPI_C_FLOAT_COMPLEX, pd[3], tag, comm, &request)){
1165 fprintf(stderr, "Error %i in %s: Failed to send t12 to process %i.\nExiting...\n\n",
1166 CANTSEND, funcname, pd[3]);
1167 MPI_Abort(comm,CANTSEND);
1168 }
1169 if(MPI_Recv(a12, kvol3, MPI_C_FLOAT_COMPLEX, pu[3], tag, comm, &status)){
1170 fprintf(stderr, "Error %i in %s: Failed to receive a12 from process %i.\nExiting...\n\n",
1171 CANTSEND, funcname, pu[3]);
1172 MPI_Abort(comm,CANTSEND);
1173 }
1174#ifdef _DEBUG
1175 printf("Finished sending and receiving on rank %i\n", rank);
1176#endif
1177 MPI_Wait(&request, &status);
1178
1179 //Post-multiply current loop by incoming one.
1180 //This is begging to be done in CUDA or BLAS
1181#pragma omp parallel for simd aligned(a11,a12,t11,t12,z11,z12:AVX)
1182 for(i=0;i<kvol3;i++){
1183 t11[i]=z11[i]*a11[i]-z12[i]*conj(a12[i]);
1184 t12[i]=z11[i]*a12[i]+z12[i]*conj(a11[i]);
1185 }
1186 memcpy(z11, t11, kvol3*sizeof(Complex_f));
1187 memcpy(z12, t12, kvol3*sizeof(Complex_f));
1188 }
1189 free(a11); free(a12); free(t11); free(t12);
1190 return 0;
1191}
1192#endif
unsigned int halosize[ndim]
Array containing the size of the halo in each direction.
Definition coord.c:12
unsigned int * hd
Down halo indices.
Definition coord.c:11
unsigned int * hu
Up halo indices.
Definition coord.c:11
unsigned int h1d[ndim]
Down halo starting element.
Definition coord.c:12
unsigned int h1u[ndim]
Up halo starting element.
Definition coord.c:12
#define NO_MPI_SIZE
Failed to get the number of ranks.
Definition errorcodes.h:89
#define NUMELEM
Failed to evaluate the number of elements.
Definition errorcodes.h:93
#define BROADERR
Couldn't broadcast to the processes.
Definition errorcodes.h:99
#define REDUCERR
Couldn't carry out a reduction operation.
Definition errorcodes.h:101
#define SIZEPROC
Communicator size does not match expected size.
Definition errorcodes.h:91
#define NO_MPI_RANK
Failed to get the rank of the process.
Definition errorcodes.h:87
#define LAYERROR
brief Can't access a layer of a halo
Definition errorcodes.h:115
#define BOUNDERROR
Accessing out of bounds element.
Definition errorcodes.h:62
#define DIFNPROC
Continuation run on different grid size.
Definition errorcodes.h:108
#define OPENERROR
Error opening file.
Definition errorcodes.h:32
#define CANTRECV
Couldn't receive from another process.
Definition errorcodes.h:97
#define CANTSEND
Couldn't send to another process.
Definition errorcodes.h:95
#define NO_MPI_INIT
Failed to initialise MPI.
Definition errorcodes.h:85
int ComplexConvert(Complex_f *a, Complex *b, const unsigned int len, const bool dtof, const unsigned short stride)
takes an array of complex float and double precision numbers and converts the precision
Definition coord.c:420
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
Definition cusu2hmc.cu:33
int Coord2gindex(int ix, int iy, int iz, int it)
Converts the coordinates of a global lattice point to its index in the computer memory.
Definition coord.c:365
int CHalo_swap_all(Complex_f *c, int ncpt)
Calls the functions to send data to both the up and down halos.
int Par_fcopy(float *fval)
Broadcasts a float to the other processes.
int ZHalo_swap_all(Complex *z, int ncpt)
Calls the functions to send data to both the up and down halos.
int Par_fsum(float *dval)
Performs a reduction on a float dval to get a sum which is then distributed to all ranks.
int Par_dcopy(double *dval)
Broadcasts a double to the other processes.
int Par_begin(int argc, char *argv[])
Initialises the MPI configuration.
Definition par_mpi.c:24
int Par_swrite(const int itraj, const int icheck, const float beta, const float fmu, const float akappa, const Complex_f ajq, const float c_sw, Complex *u11, Complex *u12)
Copies u11 and u12 into arrays without halos which then get written to output.
Definition par_mpi.c:324
int Par_isum(int *ival)
Performs a reduction on an integer ival to get a sum which is then distributed to all ranks.
int Par_icopy(int *ival)
Broadcasts an integer to the other processes.
int ZHalo_swap_dir(Complex *z, int ncpt, int idir, int layer)
Swaps the halos along the axis given by idir in the direction given by layer.
int Par_ccopy(Complex *cval)
Broadcasts a complex float to the other processes.
int Par_zcopy(Complex *zval)
Broadcasts a complex double to the other processes.
int DHalo_swap_all(double *d, int ncpt)
Calls the functions to send data to both the up and down halos.
int SHalo_swap_all(float *d, int ncpt)
Calls the functions to send data to both the up and down halos.
int SHalo_swap_dir(float *d, int ncpt, int idir, int layer)
Swaps the halos along the axis given by idir in the direction given by layer.
int CHalo_swap_dir(Complex_f *c, int ncpt, int idir, int layer)
Swaps the halos along the axis given by idir in the direction given by layer.
int Trial_Exchange(Complex *ut[2], Complex_f *ut_f[2])
Exchanges the trial fields.
Definition par_mpi.c:1043
int Par_csum(Complex_f *cval)
Performs a reduction on a complex float cval to get a sum which is then distributed to all ranks.
int Par_zsum(Complex *zval)
Performs a reduction on a complex double zval to get a sum which is then distributed to all ranks.
int Par_sread(const int iread, const float beta, const float fmu, const float akappa, const Complex_f ajq, const float c_sw, Complex *u11, Complex *u12, Complex *u11t, Complex *u12t)
Reads and assigns the gauges from file.
Definition par_mpi.c:114
int DHalo_swap_dir(double *d, int ncpt, int idir, int layer)
Swaps the halos along the axis given by idir in the direction given by layer.
int Par_dsum(double *dval)
Performs a reduction on a double dval to get a sum which is then distributed to all ranks.
int pu[ndim]
Processors in the up direction.
Definition par_mpi.c:21
#define UP
Flag for send up.
Definition par_mpi.h:39
#define DOWN
Flag for send down.
Definition par_mpi.h:37
int pd[ndim]
Processors in the down direction.
Definition par_mpi.c:22
int size
The number of MPI ranks in total.
Definition par_mpi.c:20
int rank
The MPI rank.
Definition par_mpi.c:20
int pstop[ndim][nproc]
The final lattice site on each sublattice in a given direction.
Definition par_mpi.c:19
#define masterproc
The main rank. Used for serial tasks.
Definition par_mpi.h:42
int pstart[ndim][nproc]
The initial lattice site on each sublattice in a given direction.
Definition par_mpi.c:18
int * pcoord
The processor grid.
Definition par_mpi.c:17
#define tag
default MPI tag
Definition par_mpi.h:45
unsigned long seed
RANLUX seed.
Definition random.c:18
gsl_rng * ranlux_instd
RANLUX instance.
Definition random.c:16
#define ksizex
Sublattice x extent.
Definition sizes.h:148
#define AVX
Alignment of arrays. 64 for AVX-512, 32 for AVX/AVX2. 16 for SSE. Since AVX is standard on modern x86...
Definition sizes.h:279
#define nt
Lattice temporal extent. This also corresponds to the inverse temperature.
Definition sizes.h:92
#define nproc
Number of processors for MPI.
Definition sizes.h:138
#define nx
Lattice x extent.
Definition sizes.h:72
#define ksizet
Sublattice t extent.
Definition sizes.h:158
#define npx
Processor grid x extent. This must be a divisor of nx.
Definition sizes.h:103
#define kvol
Sublattice volume.
Definition sizes.h:163
#define Complex
Double precision complex number.
Definition sizes.h:64
#define npz
Processor grid z extent.
Definition sizes.h:122
#define cudaDeviceSynchronise()
Get rid of that bastardised yankee English.
Definition sizes.h:53
#define gvol
Lattice volume.
Definition sizes.h:98
#define FILELEN
Default file name length.
Definition sizes.h:68
#define kvol3
Sublattice spatial volume.
Definition sizes.h:165
#define halo
Total Halo size.
Definition sizes.h:231
#define Complex_f
Single precision complex number.
Definition sizes.h:62
#define ksizez
Sublattice z extent.
Definition sizes.h:152
#define npy
Processor grid y extent.
Definition sizes.h:114
#define ndim
Dimensions.
Definition sizes.h:188
#define npt
Processor grid t extent.
Definition sizes.h:130
#define kvolHalo
Subvolume + halo size.
Definition sizes.h:234
#define ksizey
Sublattice y extent.
Definition sizes.h:150
#define nz
Lattice z extent. We normally use cubic lattices so this is the same as nx.
Definition sizes.h:86
#define ny
Lattice y extent. We normally use cubic lattices so this is the same as nx.
Definition sizes.h:80
Function declarations for most of the routines.
cudaStream_t streams[ndirac *ndim *nadj]
An array of concurrent GPU streams to keep it busy.
Definition cusu2hmc.cu:29
#define creal(z)
Extract Real Component using C standard notation.
#define cimag(z)
Extract Imaginary Component using C standard notation.