su2hmc
Loading...
Searching...
No Matches
Bosonic Observables
Collaboration diagram for Bosonic Observables:

Functions

int Average_Plaquette (double *hg, double *avplaqs, double *avplaqt, Complex_f *ut[2], unsigned int *iu, float beta)
 Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.
int SU2plaq (Complex_f *ut[2], Complex_f Sigma[2], unsigned int *iu, int i, int mu, int nu)
 Calculates the plaquette at site i in the \(\mu--\nu\) direction.
double Polyakov (Complex_f *ut[2])
 Calculate the Polyakov loop (no prizes for guessing that one...).
void cuAverage_Plaquette (double *hgs, double *hgt, Complex_f *u11t, Complex_f *u12t, unsigned int *iu, dim3 dimGrid, dim3 dimBlock)
 Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.
void cuPolyakov (Complex_f *Sigma[2], Complex_f *ut[2], dim3 dimGrid, dim3 dimBlock)
 Calculate the Polyakov loop (no prizes for guessing that one...).
__device__ void Device::cuSU2plaq (Complex_f *u11t, Complex_f *u12t, Complex_f *Sigma11, Complex_f *Sigma12, unsigned int *iu, const unsigned int i, const unsigned short mu, const unsigned short nu)
 Calculates the SU2 plaquette.
__global__ void Kernels::Average_Plaquette (float *hgs_d, float *hgt_d, Complex_f *u11t, Complex_f *u12t, unsigned int *iu)
 Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.
__global__ void Kernels::Polyakov (Complex_f *Sigma11, Complex_f *Sigma12, Complex_f *u11t, Complex_f *u12t)
 Calculate the Polyakov loop (no prizes for guessing that one...).

Detailed Description

Function Documentation

◆ Average_Plaquette() [1/2]

int Average_Plaquette ( double * hg,
double * avplaqs,
double * avplaqt,
Complex_f * ut[2],
unsigned int * iu,
float beta )

Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.

Parameters
[out]hgGauge component of Hamilton
[out]avplaqsAverage spacial Plaquette
[out]avplaqtAverage Temporal Plaquette
[in]utThe trial fields
[in]iuUpper halo indices
[in]betaInverse gauge coupling
Returns
Zero on success, integer error code otherwise
Postcondition
Contents of hg, avplaqs and avplaqt replaced with output

Definition at line 14 of file bosonic.c.

14 {
15 const char funcname[] = "Average_Plaquette";
16 /*There was a halo exchange here but moved it outside
17 The FORTRAN code used several consecutive loops to get the plaquette
18 Instead we'll just make the arrays variables and do everything in one loop
19 Should work since in the FORTRAN Sigma11[i] only depends on i components for example
20 Since the \nu loop doesn't get called for \mu=0 we'll start at \mu=1
21 */
22#ifdef USE_GPU
23 __managed__ double hgs = 0; __managed__ double hgt = 0;
24 cuAverage_Plaquette(&hgs, &hgt, ut[0], ut[1], iu,dimGrid,dimBlock);
25#else
26 double hgs = 0; double hgt = 0;
27 for(int mu=1;mu<ndim;mu++)
28 for(int nu=0;nu<mu;nu++)
29 //Don't merge into a single loop. Makes vectorisation easier?
30 //Or merge into a single loop and dispense with the a arrays?
31#pragma omp parallel for simd reduction(+:hgs,hgt)
32 for(int i=0;i<kvol;i++){
33 Complex_f Sigma[2];
34 SU2plaq(ut,Sigma,iu,i,mu,nu);
35 switch(mu){
36 //Time component
37 case(ndim-1): hgt -= creal(Sigma[0]);
38 break;
39 //Space component
40 default: hgs -= creal(Sigma[0]);
41 break;
42 }
43 }
44#endif
45#if(nproc>1)
46 Par_dsum(&hgs); Par_dsum(&hgt);
47#endif
48 *avplaqs=-hgs/(3.0*gvol); *avplaqt=-hgt/(gvol*3.0);
49 *hg=(hgs+hgt)*beta;
50#ifdef _DEBUG
51 if(!rank)
52 printf("hgs=%e hgt=%e hg=%e\n", hgs, hgt, *hg);
53#endif
54 return 0;
55}
int SU2plaq(Complex_f *ut[2], Complex_f Sigma[2], unsigned int *iu, int i, int mu, int nu)
Calculates the plaquette at site i in the direction.
void cuAverage_Plaquette(double *hgs, double *hgt, Complex_f *u11t, Complex_f *u12t, unsigned int *iu, dim3 dimGrid, dim3 dimBlock)
Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in som...
Definition cubosonic.cu:120
int Par_dsum(double *dval)
Performs a reduction on a double dval to get a sum which is then distributed to all ranks.
int rank
The MPI rank.
Definition par_mpi.c:20
#define kvol
Sublattice volume.
Definition sizes.h:163
#define gvol
Lattice volume.
Definition sizes.h:98
#define Complex_f
Single precision complex number.
Definition sizes.h:62
dim3 dimGrid
Default grid size. First component is normally nt. Second and third depend whatever is needed to get ...
Definition cusu2hmc.cu:27
#define ndim
Dimensions.
Definition sizes.h:188
dim3 dimBlock
Default block size. Usually 128.
Definition cusu2hmc.cu:25
#define creal(z)
Extract Real Component using C standard notation.

References Complex_f, creal, cuAverage_Plaquette(), dimBlock, dimGrid, gvol, kvol, ndim, Par_dsum(), rank, and SU2plaq().

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

◆ Average_Plaquette() [2/2]

__global__ void Kernels::Average_Plaquette ( float * hgs_d,
float * hgt_d,
Complex_f * u11t,
Complex_f * u12t,
unsigned int * iu )

Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.

Parameters
[out]hgs_d,hgt_dGauge component of Hamilton
[in]u11t,u12tGauge fields
[in]iuUpper halo indices

Definition at line 59 of file cubosonic.cu.

59 {
60 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
61 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
62 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
63 const unsigned int threadId= blockId * bsize+(threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
64 Complex_f Sigma11=0; Complex_f Sigma12=0;
65 //TODO: Check if μ and ν loops inside of site loop is faster. I suspect it is due to memory locality.
66 for(unsigned int i=threadId;i<kvol;i+=bsize*gsize){
67 float hg_c[2];
68 hg_c[0]=0; hg_c[1]=0;
69
70 for(unsigned short mu=1;mu<ndim;mu++)
71 for(unsigned short nu=0;nu<mu;nu++){
72 //This is threadsafe as the μ and ν loops are not distributed across threads
73 cuSU2plaq(u11t,u12t,&Sigma11,&Sigma12,iu,i,mu,nu);
74 switch(mu){
75 //Time component
76 case(ndim-1):
77 hg_c[0] -= creal(Sigma11);
78 break;
79 //Space component
80 default:
81 hg_c[1] -= creal(Sigma11);
82 break;
83 }
84 }
85 hgt_d[i]=hg_c[0]; hgs_d[i]=hg_c[1];
86 }
87 }
__device__ void cuSU2plaq(Complex_f *u11t, Complex_f *u12t, Complex_f *Sigma11, Complex_f *Sigma12, unsigned int *iu, const unsigned int i, const unsigned short mu, const unsigned short nu)
Calculates the SU2 plaquette.
Definition cubosonic.cu:26

References Complex_f, creal, Device::cuSU2plaq(), kvol, and ndim.

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

◆ cuAverage_Plaquette()

void cuAverage_Plaquette ( double * hgs,
double * hgt,
Complex_f * u11t,
Complex_f * u12t,
unsigned int * iu,
dim3 dimGrid,
dim3 dimBlock )

Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.

Calling wrappers.

Parameters
[out]hgs,hgtGauge component of Hamilton
[in]u11t,u12tGauge fields
[in]iuUpper halo indices
[in]dimGridCUDA grid dimensions
[in]dimBlockCUDA block dimensions
Postcondition
Contents of hgs and hgt replaced with the results

Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in some QED3 code.

Definition at line 120 of file cubosonic.cu.

120 {
121 // float *hgs_d, *hgt_d;
122 int device=-1;
123 cudaGetDevice(&device);
124 float *hgs_d, *hgt_d;
125 //Thrust want things in a weird format for the reduction, thus we oblige
126 cudaMallocAsync((void **)&hgs_d,kvol*sizeof(float),NULL);
127 thrust::device_ptr<float> hgs_T = thrust::device_pointer_cast(hgs_d);
128 cudaMallocAsync((void **)&hgt_d,kvol*sizeof(float),NULL);
129 thrust::device_ptr<float> hgt_T = thrust::device_pointer_cast(hgt_d);
130
131 Kernels::Average_Plaquette<<<dimGrid,dimBlock,0,NULL>>>(hgs_d, hgt_d, u11t, u12t, iu);
133
134 *hgs= (double)thrust::reduce(hgs_T,hgs_T+kvol,(float)0);
135 *hgt= (double)thrust::reduce(hgt_T,hgt_T+kvol,(float)0);
137
138 cudaFreeAsync(hgs_d,streams[0]); cudaFreeAsync(hgt_d,streams[1]);
139}
__global__ void Average_Plaquette(float *hgs_d, float *hgt_d, Complex_f *u11t, Complex_f *u12t, unsigned int *iu)
Calculates the gauge action using new (how new?) lookup table Follows a routine called qedplaq in som...
Definition cubosonic.cu:59
#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 Kernels::Average_Plaquette(), Complex_f, cudaDeviceSynchronise, dimBlock, dimGrid, kvol, and streams.

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

◆ cuPolyakov()

void cuPolyakov ( Complex_f * Sigma[2],
Complex_f * ut[2],
dim3 dimGrid,
dim3 dimBlock )

Calculate the Polyakov loop (no prizes for guessing that one...).

Parameters
[out]SigmaComponents of the Polyakov loop
[in]utThe gauge fields
[in]dimGridCUDA grid dimensions
[in]dimBlockCUDA block dimensions
Postcondition
Contents of Sigma replaced with the Polyakov loop values

Definition at line 140 of file cubosonic.cu.

140 {
141 int device=-1;
142 cudaGetDevice(&device);
143 cudaMallocManaged((void **)&Sigma[0],kvol3*sizeof(Complex_f),cudaMemAttachGlobal);
144#ifdef _DEBUG
145 cudaMallocManaged((void **)&Sigma[1],kvol3*sizeof(Complex_f),cudaMemAttachGlobal);
146#else
147 cudaMallocAsync((void **)&Sigma[1],kvol3*sizeof(Complex_f),streams[0]);
148#endif
149 //Extract the time component from each site and save in corresponding Sigma
150 cublasCcopy(cublas_handle,kvol3, (cuComplex *)(ut[0])+3*kvolHalo, 1, (cuComplex *)Sigma[0], 1);
151 cublasCcopy(cublas_handle,kvol3, (cuComplex *)(ut[1])+3*kvolHalo, 1, (cuComplex *)Sigma[1], 1);
152
154 Kernels::Polyakov<<<dimGrid,dimBlock>>>(Sigma[0],Sigma[1],ut[0],ut[1]);
155 //cudaMemPrefetchAsync(Sigma[0],kvol3*sizeof(Complex_f),cudaCpuDeviceId,streams[0]);
156#ifdef _DEBUG
157 cudaFree(Sigma[1]);
158#else
159 cudaFreeAsync(Sigma[1],streams[1]);
160#endif
162}
__global__ void Polyakov(Complex_f *Sigma11, Complex_f *Sigma12, Complex_f *u11t, Complex_f *u12t)
Calculate the Polyakov loop (no prizes for guessing that one...).
Definition cubosonic.cu:97
cublasHandle_t cublas_handle
Handle for cuBLAS.
Definition main.c:47
#define kvol3
Sublattice spatial volume.
Definition sizes.h:165
#define kvolHalo
Subvolume + halo size.
Definition sizes.h:234

References Complex_f, cublas_handle, cudaDeviceSynchronise, dimBlock, dimGrid, kvol3, kvolHalo, Kernels::Polyakov(), and streams.

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

◆ cuSU2plaq()

__device__ void Device::cuSU2plaq ( Complex_f * u11t,
Complex_f * u12t,
Complex_f * Sigma11,
Complex_f * Sigma12,
unsigned int * iu,
const unsigned int i,
const unsigned short mu,
const unsigned short nu )

Calculates the SU2 plaquette.

Parameters
[in]u11t,u12tGauge fields
[out]Sigma11,Sigma12Plaquette entries
[in]iuSite indices in the up direction
[in]iSite
[in]mu,nuPlaquette direction
Postcondition
Contents of Sigma11 and Sigma12 replaced with plaquettes.

Definition at line 26 of file cubosonic.cu.

27 {
28 const unsigned int uidm = iu[i+kvol*mu];
29 unsigned int ind=i+kvol*mu;
30 //Need a second index in the nu direction for the first step
31 unsigned int indn=uidm+kvol*nu;
32 *Sigma11=u11t[ind]*u11t[indn]-u12t[ind]*conj(u12t[indn]);
33 *Sigma12=u11t[ind]*u12t[indn]+u12t[ind]*conj(u11t[indn]);
34
35 const int uidn = iu[i+kvol*nu];
36 ind=uidn+kvol*mu;
37 Complex_f a11=*Sigma11*conj(u11t[ind])+*Sigma12*conj(u12t[ind]);
38 Complex_f a12=-*Sigma11*u12t[ind]+*Sigma12*u11t[ind];
39
40 ind=i+kvol*nu;
41 *Sigma11=a11*conj(u11t[ind])+a12*conj(u12t[ind]);
42 *Sigma12=-a11*u12t[ind]+a12*u11t[ind];
43 return;
44 }
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
Definition cusu2hmc.cu:33

References Complex_f, conj(), and kvol.

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

◆ Polyakov() [1/2]

__global__ void Kernels::Polyakov ( Complex_f * Sigma11,
Complex_f * Sigma12,
Complex_f * u11t,
Complex_f * u12t )

Calculate the Polyakov loop (no prizes for guessing that one...).

Parameters
[out]Sigma11,Sigma12Components of the Polyakov loop
[in]u11t,u12tThe gauge fields

Definition at line 97 of file cubosonic.cu.

97 {
98 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
99 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
100 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
101 const unsigned int threadId= blockId * bsize+(threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
102 for(unsigned int i=threadId;i<kvol3;i+=gsize*bsize){
103 Complex_f Sig[2]; Sig[0]=Sigma11[i]; Sig[1]=Sigma12[i];
104 Complex_f u[2];
105 for(unsigned int it=1;it<ksizet;it++){
106 const unsigned int indexu=it*kvol3+i;
107 u[0]=u11t[indexu+3*kvol];u[1]=u12t[indexu+3*kvol];
108 Complex_f a11=Sig[0]*u[0]-Sig[1]*conj(u[1]);
109 //Instead of having to store a second buffer just assign it directly
110 Sig[1]=Sig[0]*u[1]+Sig[1]*conj(u[0]);
111 Sig[0]=a11;
112 }
113 Sigma11[i]=Sig[0]; Sigma12[i]=Sig[1];
114 }
115 }
#define ksizet
Sublattice t extent.
Definition sizes.h:158

References Complex_f, conj(), ksizet, kvol, and kvol3.

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

◆ Polyakov() [2/2]

double Polyakov ( Complex_f * ut[2])

Calculate the Polyakov loop (no prizes for guessing that one...).

Parameters
[in]utThe gauge fields
Returns
Double corresponding to the polyakov loop

Definition at line 74 of file bosonic.c.

74 {
75 const char funcname[] = "Polyakov";
76 double poly = 0;
77 Complex_f *Sigma[2];
78#ifdef USE_GPU
79 cuPolyakov(Sigma,ut,dimGrid,dimBlock);
80#else
81 Sigma[0] = (Complex_f *)aligned_alloc(AVX,kvol3*sizeof(Complex_f));
82 Sigma[1] = (Complex_f *)aligned_alloc(AVX,kvol3*sizeof(Complex_f));
83
84 //Extract the time component from each site and save in corresponding Sigma
85 memcpy(Sigma[0],ut[0]+3*kvolHalo,kvol3*sizeof(Complex_f));
86 memcpy(Sigma[1],ut[1]+3*kvolHalo,kvol3*sizeof(Complex_f));
87 /* Some Fortran commentary
88 Changed this routine.
89 ut[0] and ut[1] now defined as normal ie (kvol+halo,4).
90 Copy of Sigma[0] and Sigma[1] is changed so that it copies
91 in blocks of ksizet.
92 Variable indexu also used to select correct element of ut[0] and ut[1]
93 in loop 10 below.
94
95 Change the order of multiplication so that it can
96 be done in parallel. Start at t=1 and go up to t=T:
97 previously started at t+T and looped back to 1, 2, ... T-1
98 Buffers
99 There is a dependency. Can only parallelise the inner loop
100 */
101#pragma unroll
102 for(int it=1;it<ksizet;it++)
103#pragma omp parallel for simd
104 for(int i=0;i<kvol3;i++){
105 //Seems a bit more efficient to increment indexu instead of reassigning
106 //it every single loop
107 int indexu=it*kvol3+i;
108 Complex_f a11=Sigma[0][i]*ut[0][indexu+kvol*3]-Sigma[1][i]*conj(ut[1][indexu+kvol*3]);
109 //Instead of having to store a second buffer just assign it directly
110 Sigma[1][i]=Sigma[0][i]*ut[1][indexu+kvol*3]+Sigma[1][i]*conj(ut[0][indexu+kvol*3]);
111 Sigma[0][i]=a11;
112 }
113#endif
114
115 //Multiply this partial loop with the contributions of the other cores in the
116 //Time-like dimension
117 //
118 //Par_tmul does nothing if there is only a single processor in the time direction. So we only compile
119 //its call if it is required
120#if (npt>1)
121#ifdef __NVCC_
122#error Par_tmul is not yet implimented in CUDA as Sigma[1] is device only memory
123#endif
124#ifdef _DEBUG
125 printf("Multiplying with MPI\n");
126#endif
127 Par_tmul(Sigma[0], Sigma[1]);
128 //end of #if(npt>1)
129#endif
130 /*Now all cores have the value for the complete Polyakov line at all spacial sites
131 We need to globally sum over spacial processors but not across time as these
132 are duplicates. So we zero the value for all but t=0
133 This is (according to the FORTRAN code) a bit of a hack
134 I will expand on this hack and completely avoid any work
135 for this case rather than calculating everything just to set it to zero
136 */
137 if(!pcoord[3+rank*ndim])
138#pragma omp parallel for simd reduction(+:poly)
139 for(unsigned int i=0;i<kvol3;i++)
140 poly+=creal(Sigma[0][i]);
141#ifdef USE_GPU
142 cudaFree(Sigma[0]);
143#else
144 free(Sigma[0]);
145 free(Sigma[1]);
146#endif
147
148#if(nproc>1)
149 Par_dsum(&poly);
150#endif
151 poly/=gvol3;
152 return poly;
153}
void cuPolyakov(Complex_f *Sigma[2], Complex_f *ut[2], dim3 dimGrid, dim3 dimBlock)
Calculate the Polyakov loop (no prizes for guessing that one...).
Definition cubosonic.cu:140
int * pcoord
The processor grid.
Definition par_mpi.c:17
#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 gvol3
Lattice spatial volume.
Definition sizes.h:100

References AVX, Complex_f, conj(), creal, cuPolyakov(), dimBlock, dimGrid, gvol3, ksizet, kvol, kvol3, kvolHalo, ndim, Par_dsum(), pcoord, and rank.

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

◆ SU2plaq()

int SU2plaq ( Complex_f * ut[2],
Complex_f Sigma[2],
unsigned int * iu,
int i,
int mu,
int nu )

Calculates the plaquette at site i in the \(\mu--\nu\) direction.

Parameters
[in]utTrial fields
[out]SigmaPlaquette components
[in]iLattice site
[in]iuUpper halo indices
[in]mu,nuPlaquette direction. Note that mu and nu can be negative to facilitate calculating plaquettes for Clover terms. No sanity checks are conducted on them in this routine.
Returns
Zero on success, integer error code otherwise
Postcondition
Plaquettes written into Sigma

References Complex, Complex_f, dimBlock, dimGrid, hd, hu, nadj, ndim, ndirac, and streams.

Here is the caller graph for this function: