su2hmc
Loading...
Searching...
No Matches
MPI functions

Functions

int Par_begin (int argc, char *argv[])
 Initialises the MPI configuration.
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.
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.
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_dsum (double *dval)
 Performs a reduction on a double dval to get a sum which is then distributed to all ranks.
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_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_icopy (int *ival)
 Broadcasts an integer to the other processes.
int Par_dcopy (double *dval)
 Broadcasts a double to the other processes.
int Par_fcopy (float *fval)
 Broadcasts a float to the other processes.
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 ZHalo_swap_all (Complex *z, int ncpt)
 Calls the functions to send data to both the up and down halos.
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 CHalo_swap_all (Complex_f *c, int ncpt)
 Calls the functions to send data to both the up and down halos.
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 DHalo_swap_all (double *d, int ncpt)
 Calls the functions to send data to both the up and down halos.
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 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 Trial_Exchange (Complex *ut[2], Complex_f *ut_f[2])
 Exchanges the trial fields.

Detailed Description

Function Documentation

◆ CHalo_swap_all()

int CHalo_swap_all ( Complex_f * c,
int ncpt )

Calls the functions to send data to both the up and down halos.

Parameters
[in,out]cThe data being sent
[in]ncptNumber of components being sent
Returns
Zero on success, integer error code otherwise
Postcondition
Halo terms of c updated

References Complex_f.

Here is the caller graph for this function:

◆ CHalo_swap_dir()

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.

Parameters
[in,out]cThe data being moved about. It should be an array of dimension [kvol+halo][something else]
[in]ncptNumber of components being sent
[in]idirThe axis being moved along in C Indexing
[in]layerEither DOWN (0) or UP (1)
Returns
Zero on success, Integer Error code otherwise
Postcondition
Halo terms of c updated in direction idir and layer layer

References Complex_f.

Here is the caller graph for this function:

◆ DHalo_swap_all()

int DHalo_swap_all ( double * d,
int ncpt )

Calls the functions to send data to both the up and down halos.

Parameters
[in,out]dThe data being sent
[in]ncptNumber of components being sent
Returns
Zero on success, integer error code otherwise
Postcondition
Halo terms of d updated

◆ DHalo_swap_dir()

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.

Parameters
[in,out]dThe data being moved about. It should be an array of dimension [kvol+halo][something else]
[in]ncptNumber of components being sent
[in]idirThe axis being moved along in C Indexing
[in]layerEither DOWN (0) or UP (1)
Returns
Zero on success, Integer Error code otherwise
Postcondition
Halo terms of d updated in direction idir and layer layer
Here is the caller graph for this function:

◆ Par_begin()

int Par_begin ( int argc,
char * argv[] )

Initialises the MPI configuration.

Parameters
[in]argcNumber of arguments given to the programme
[in]argvArray of arguments
Returns
Zero on success, integer error code otherwise.
Postcondition
MPI communicator configured, processor and sublattice topology determined

Definition at line 24 of file par_mpi.c.

24 {
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}
#define NO_MPI_SIZE
Failed to get the number of ranks.
Definition errorcodes.h:89
#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 NO_MPI_INIT
Failed to initialise MPI.
Definition errorcodes.h:85
int pu[ndim]
Processors in the up direction.
Definition par_mpi.c:21
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
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 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 npz
Processor grid z extent.
Definition sizes.h:122
#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 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

References AVX, ksizet, ksizex, ksizey, ksizez, ndim, NO_MPI_INIT, NO_MPI_RANK, NO_MPI_SIZE, nproc, npt, npx, npy, npz, nt, nx, ny, nz, pcoord, pd, pstart, pstop, pu, rank, size, and SIZEPROC.

Here is the caller graph for this function:

◆ Par_ccopy()

int Par_ccopy ( Complex * cval)

Broadcasts a complex float to the other processes.

Parameters
[in,out]cvalComplex float being broadcast
Returns
Zero on success, integer error code otherwise
Postcondition
All ranks not broadcasting have their value of cval overwritten

References Complex.

◆ Par_csum()

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.

Parameters
[in,out]cvalThe pointer to the element being summed, and the container for said sum.
Postcondition
Reduced sum stored in cval
Returns
Zero on success. Integer error code otherwise.

References Complex_f.

◆ Par_dcopy()

int Par_dcopy ( double * dval)

Broadcasts a double to the other processes.

Parameters
[in,out]dvaldouble being broadcast
Returns
Zero on success, integer error code otherwise
Postcondition
All ranks not broadcasting have their value of dval overwritten
Here is the caller graph for this function:

◆ Par_dsum()

int Par_dsum ( double * dval)

Performs a reduction on a double dval to get a sum which is then distributed to all ranks.

Parameters
[in,out]dvalThe pointer to the element being summed, and the container for said sum.
Returns
Zero on success. Integer error code otherwise.
Postcondition
Reduced sum stored in dval
Here is the caller graph for this function:

◆ Par_fcopy()

int Par_fcopy ( float * fval)

Broadcasts a float to the other processes.

Parameters
[in,out]fvalfloat being broadcast
Returns
Zero on success, integer error code otherwise
Postcondition
All ranks not broadcasting have their value of fval overwritten
Here is the caller graph for this function:

◆ Par_fsum()

int Par_fsum ( float * dval)

Performs a reduction on a float dval to get a sum which is then distributed to all ranks.

Parameters
[in,out]dvalThe pointer to the element being summed, and the container for said sum.
Returns
Zero on success. Integer error code otherwise.
Postcondition
Reduced sum stored in dval
Here is the caller graph for this function:

◆ Par_icopy()

int Par_icopy ( int * ival)

Broadcasts an integer to the other processes.

Parameters
[in,out]ivalInteger being broadcast
Returns
Zero on success, integer error code otherwise
Postcondition
All ranks not broadcasting have their value of ival overwritten
Here is the caller graph for this function:

◆ Par_isum()

int Par_isum ( int * ival)

Performs a reduction on an integer ival to get a sum which is then distributed to all ranks.

Parameters
[in,out]ivalThe pointer to the element being summed, and the container for said sum.
Returns
Zero on success. Integer error code otherwise.
Postcondition
Reduced sum stored in ival

◆ Par_sread()

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.

Parameters
[in]ireadConfiguration to read in
[in]betaInverse gauge coupling
[in]fmuChemical potential
[in]akappaHopping parameter
[in]ajqDiquark source
[in]c_swClover coefficient
[out]u11,u12Gauge fields
[out]u11t,u12tTrial fields
Returns
Zero on success, integer error code otherwise
Postcondition
Contents of gauge fields replaced with read in values

Definition at line 114 of file par_mpi.c.

115 {
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}
#define NUMELEM
Failed to evaluate the number of elements.
Definition errorcodes.h:93
#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
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
#define masterproc
The main rank. Used for serial tasks.
Definition par_mpi.h:42
unsigned long seed
RANLUX seed.
Definition random.c:18
#define kvol
Sublattice volume.
Definition sizes.h:163
#define Complex
Double precision complex number.
Definition sizes.h:64
#define gvol
Lattice volume.
Definition sizes.h:98
#define FILELEN
Default file name length.
Definition sizes.h:68
#define kvolHalo
Subvolume + halo size.
Definition sizes.h:234
#define creal(z)
Extract Real Component using C standard notation.

References AVX, CANTRECV, CANTSEND, Complex, Complex_f, Coord2gindex(), creal, DIFNPROC, FILELEN, gvol, kvol, kvolHalo, masterproc, ndim, nproc, nt, NUMELEM, nx, OPENERROR, pstart, pstop, rank, seed, and size.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Par_swrite()

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.

Modified from an original version of swrite in FORTRAN

Parameters
[in]itrajTrajectory to write
[in]icheckNot currently used but haven't gotten around to removing it
[in]betaInverse gauge coupling
[in]fmuChemical potential
[in]akappaHopping parameter
[in]ajqDiquark source
[in]c_swClover coefficient
[in]u11,u12Gauge fields
Returns
Zero on success, integer error code otherwise
Postcondition
Gauge fields saved to file

Definition at line 324 of file par_mpi.c.

325 {
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}
gsl_rng * ranlux_instd
RANLUX instance.
Definition random.c:16

References AVX, CANTRECV, CANTSEND, Complex, Complex_f, Coord2gindex(), creal, FILELEN, gvol, kvol, masterproc, ndim, nproc, nt, NUMELEM, nx, OPENERROR, pstart, pstop, rank, ranlux_instd, seed, and size.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Par_zcopy()

int Par_zcopy ( Complex * zval)

Broadcasts a complex double to the other processes.

Parameters
[in,out]zvalComplex double being broadcast
Returns
Zero on success, integer error code otherwise
Postcondition
All ranks not broadcasting have their value of zval overwritten

References Complex.

◆ Par_zsum()

int Par_zsum ( Complex * zval)

Performs a reduction on a complex double zval to get a sum which is then distributed to all ranks.

Parameters
[in,out]zvalThe pointer to the element being summed, and the container for said sum.
Returns
Zero on success. Integer error code otherwise.
Postcondition
Reduced sum stored in zval

References Complex.

◆ SHalo_swap_all()

int SHalo_swap_all ( float * d,
int ncpt )

Calls the functions to send data to both the up and down halos.

Parameters
[in,out]dThe data being sent
[in]ncptNumber of components being sent
Returns
Zero on success, integer error code otherwise
Postcondition
Halo terms of d updated
Here is the caller graph for this function:

◆ SHalo_swap_dir()

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.

Parameters
[in,out]dThe data being moved about. It should be an array of dimension [kvol+halo][something else]
[in]ncptNumber of components being sent
[in]idirThe axis being moved along in C Indexing
[in]layerEither DOWN (0) or UP (1)
Returns
Zero on success, Integer Error code otherwise
Postcondition
Halo terms of d updated in direction idir and layer layer

References Complex, and Complex_f.

◆ Trial_Exchange()

int Trial_Exchange ( Complex * ut[2],
Complex_f * ut_f[2] )

Exchanges the trial fields.

I noticed that this halo exchange was happening even though the trial fields hadn't been updated. To get around this I'm making a function that does the halo exchange and only calling it after the trial fields get updated.

Parameters
[in,out]utDouble precision trial fields
[out]ut_fSingle precision trial fields
Returns
Zero on success, Integer Error code otherwise
Postcondition
Halos of ut updated. ut_f overwritten with single precision values of ut

Definition at line 1043 of file par_mpi.c.

1043 {
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}
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
int ZHalo_swap_all(Complex *z, int ncpt)
Calls the functions to send data to both the up and down halos.
#define cudaDeviceSynchronise()
Get rid of that bastardised yankee English.
Definition sizes.h:53
cudaStream_t streams[ndirac *ndim *nadj]
An array of concurrent GPU streams to keep it busy.
Definition cusu2hmc.cu:29

References AVX, Complex, Complex_f, ComplexConvert(), cudaDeviceSynchronise, kvol, kvolHalo, ndim, streams, and ZHalo_swap_all().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ZHalo_swap_all()

int ZHalo_swap_all ( Complex * z,
int ncpt )

Calls the functions to send data to both the up and down halos.

Parameters
[in,out]zThe data being sent
[in]ncptNumber of components being sent
Returns
Zero on success, integer error code otherwise
Postcondition
Halo terms of z updated

References Complex.

Here is the caller graph for this function:

◆ ZHalo_swap_dir()

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.

Parameters
[in,out]zThe data being moved about. It should be an array of dimension [kvol+halo][something else]
[in]ncptNumber of components being sent
[in]idirThe axis being moved along in C Indexing
[in]layerEither DOWN (0) or UP (1)
Returns
Zero on success, Integer Error code otherwise
Postcondition
Halo terms of z updated in direction idir and layer layer

References Complex.

Here is the caller graph for this function: