8#pragma omp declare simd
14 a[0] = -cimagf(a[1])-crealf(a[1])*
I;
15 a[1] = cimagf(tmp)+crealf(tmp)*
I;
24 a[0] = -cimagf(a[0])+crealf(a[0])*
I;
25 a[1] = -cimagf(a[1])+crealf(a[1])*
I;
30#pragma omp declare simd
36 a[0] = -cimagf(a[1])+crealf(a[1])*
I;
37 a[1] = -cimagf(tmp)+ crealf(tmp)*
I;
45 a[0] = -cimagf(a[0])+crealf(a[0])*
I;
46 a[1] = cimagf(a[1])-crealf(a[1])*
I;
69#pragma omp declare simd
71 unsigned int *
id,
const unsigned int i,
const unsigned short mu,
const unsigned short nu,
const unsigned short leaf){
89 const unsigned int uin_didm=iu[nu*
kvol+uidm];
91 Leaves[0]=a[0]*conjf(ut[0][uin_didm+
kvolHalo*mu])+a[1]*conjf(ut[1][uin_didm+
kvolHalo*mu]);
92 Leaves[1]=-a[0]*ut[1][uin_didm+
kvolHalo*mu]+a[1]*ut[0][uin_didm+
kvolHalo*mu];
109 uidm =
id[i+
kvol*mu];
113 const unsigned int din_didm=
id[nu*
kvol+uidm];
116 Leaves[0]=a[0]*conjf(ut[0][din_didm+
kvolHalo*nu])+a[1]*conjf(ut[1][din_didm+
kvolHalo*nu]);
117 Leaves[1]=-a[0]*ut[1][din_didm+
kvolHalo*nu]+a[1]*ut[0][din_didm+
kvolHalo*nu];
123 const unsigned short mu,
const unsigned short nu){
125#pragma omp parallel for simd collapse(2)
126 for(
unsigned short leaf=0;leaf<
ndim;leaf++)
127 for(
unsigned int i=0;i<
kvol;i++){
129 Half_Leaf(Leaves,ut,a,iu,
id,i,mu,nu,leaf);
130 hLeaves[0][i+
kvol*leaf]=Leaves[0]; hLeaves[1][i+
kvol*leaf]=Leaves[1];
134#pragma omp declare simd
136 const unsigned short mu,
const unsigned short nu,
const unsigned short leaf){
138 Half_Leaf(Leaves,ut,a,iu,
id,i,mu,nu,leaf);
139 unsigned int didm,didn,uidm;
143 unsigned int uidn = iu[nu*
kvol+i];
145 a[0]=Leaves[0]*conjf(ut[0][uidn+
kvolHalo*mu])+Leaves[1]*conjf(ut[1][uidn+
kvolHalo*mu]);
149 Leaves[0]=a[0]*conjf(ut[0][i+
kvolHalo*nu])+a[1]*conjf(ut[1][i+
kvolHalo*nu]);
157 didm =
id[mu*
kvol+i];
160 a[0]=Leaves[0]*conjf(ut[0][didm+
kvolHalo*nu])+Leaves[1]*conjf(ut[1][didm+
kvolHalo*nu]);
171 didn =
id[nu*
kvol+i];
172 unsigned int uim_didn=iu[mu*
kvol+didn];
174 a[0]=Leaves[0]*ut[0][uim_didn+
kvolHalo*nu]-Leaves[1]*conjf(ut[1][uim_didn+
kvolHalo*nu]);
175 a[1]=Leaves[0]*ut[1][uim_didn+
kvolHalo*nu]+Leaves[1]*conjf(ut[0][uim_didn+
kvolHalo*nu]);
178 Leaves[0]=a[0]*conjf(ut[0][i+
kvolHalo*mu])+a[1]*conjf(ut[1][i+
kvolHalo*mu]);
186 didn =
id[nu*
kvol+i];
187 unsigned int din_didm=
id[mu*
kvol+didn];
190 a[0]=Leaves[0]*ut[0][din_didm+
kvolHalo*mu]-Leaves[1]*conjf(ut[1][din_didm+
kvolHalo*mu]);
191 a[1]=Leaves[0]*ut[1][din_didm+
kvolHalo*mu]+Leaves[1]*conjf(ut[0][din_didm+
kvolHalo*mu]);
204 const char funcname[]=
"Full_Clover";
210 for(
unsigned short mu=0;mu<
ndim-1;mu++)
211 for(
unsigned short nu=mu+1;nu<
ndim;nu++)
214 unsigned short clov = (mu==0) ? nu-1 :mu+nu;
215#pragma omp parallel for
216 for(
unsigned int i=0;i<
kvol;i++){
217 clover[0][i+clov*
kvol]=0;
218 clover[1][i+clov*
kvol]=0;
220 for(
unsigned short leaf=0;leaf<
ndim;leaf++)
222 Leaf(Leaves,ut,iu,
id,i,mu,nu,leaf);
223 clover[0][i+clov*
kvol]+=Leaves[0]; clover[1][i+clov*
kvol]+=Leaves[1];
232 clover[0][i+clov*
kvol]=cimagf(clover[0][i+clov*
kvol]); clover[0][i+clov*
kvol]*=(1.0f/4.0f);
234 clover[1][i+clov*
kvol]+=clover[1][i+clov*
kvol]; clover[1][i+clov*
kvol]*=(-
I/8.0f);
245 cuByClover(phi,r,clover,sigval,akappa,sigin,dag);
247#pragma omp parallel for simd
248 for(
unsigned int i=0;i<
kvol;i++){
252 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++)
253 for(
unsigned short c=0; c<
nc; c++){
259 for(
unsigned short clov=0;clov<6;clov++){
260 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
261 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++){
263 const unsigned short idirac = igorkov&3;
264 const unsigned short sind = (igorkov<4) ? sigin[clov*
ndirac+idirac] : sigin[clov*
ndirac+idirac]+4;
266 for(
unsigned short c=0; c<
nc; c++)
269 phi_s[igorkov][0]+=sigval[clov*
ndirac+idirac]*(
creal(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
271 phi_s[igorkov][1]+=sigval[clov*
ndirac+idirac]*(
conj(clov_s[1])*r_s[0]-
creal(clov_s[0])*r_s[1]);
275 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++)
276 for(
unsigned short c=0; c<
nc; c++){
281 phi[i+
kvol*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
283 phi[i+
kvolHalo*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
290 const char funcname[] =
"HbyClover";
294#pragma omp parallel for simd
295 for(
unsigned int i=0;i<
kvol;i++){
299 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
300 for(
unsigned short c=0; c<
nc; c++){
305 for(
unsigned short clov=0;clov<6;clov++){
306 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
307 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc){
308 const unsigned short sind = sigin[clov*
ndirac+(idirac>>1)] << (
nc-1);
310 for(
unsigned short c=0; c<
nc; c++){
316 phi_s[idirac+0]+=sig*(
creal(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
318 phi_s[idirac+1]+=sig*(
conj(clov_s[1])*r_s[0]-
creal(clov_s[0])*r_s[1]);
322 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
323 for(
unsigned short c=0; c<
nc; c++)
328 phi[i+
kvol*(c+idirac)]+=akappa*phi_s[idirac+c];
330 phi[i+
kvolHalo*(c+idirac)]+=akappa*phi_s[idirac+c];
340#pragma omp parallel for simd
341 for(
unsigned int i=0;i<
kvol;i++){
345 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++)
346 for(
unsigned short c=0; c<
nc; c++){
352 for(
unsigned short clov=0;clov<6;clov++){
353 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
354 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++){
356 const unsigned short idirac = igorkov&3;
357 const unsigned short sind = (igorkov<4) ? sigin[clov*
ndirac+idirac] : sigin[clov*
ndirac+idirac]+4;
359 for(
unsigned short c=0; c<
nc; c++)
362 phi_s[igorkov][0]+=sigval[clov*
ndirac+idirac]*(crealf(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
364 phi_s[igorkov][1]+=sigval[clov*
ndirac+idirac]*(
conj(clov_s[1])*r_s[0]-crealf(clov_s[0])*r_s[1]);
368 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++)
369 for(
unsigned short c=0; c<
nc; c++){
374 phi[i+
kvol*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
376 phi[i+
kvolHalo*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
383 const char funcname[] =
"HbyClover_f";
387#pragma omp parallel for simd
388 for(
unsigned int i=0;i<
kvol;i++){
392 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
393 for(
unsigned short c=0; c<
nc; c++){
398 for(
unsigned short clov=0;clov<6;clov++){
399 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
400 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc){
401 const unsigned short sind = sigin[clov*
ndirac+(idirac>>1)] << (
nc-1);
403 for(
unsigned short c=0; c<
nc; c++){
408 phi_s[idirac+0]+=sig*(crealf(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
410 phi_s[idirac+1]+=sig*(
conj(clov_s[1])*r_s[0]-crealf(clov_s[0])*r_s[1]);
414 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
415 for(
unsigned short c=0; c<
nc; c++)
420 phi[i+
kvol*(c+idirac)]+=akappa*phi_s[idirac+c];
422 phi[i+
kvolHalo*(c+idirac)]+=akappa*phi_s[idirac+c];
442 Z[1]=Xmn.
offd[ind]; Z[2]=conjf(Z[1]);
446 const unsigned short mu,
const unsigned short nu){
447 const char funcname[] =
"Xmunu";
453 clov = (mu==0) ? nu-1 : mu+nu;
454#pragma omp parallel for simd aligned(X1,X2:AVX)
455 for(
unsigned int i=0;i<
kvol;i++){
459 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc){
460 const unsigned short sind = sigin[clov*
ndirac+(idirac>>1)]<<1;
463 for(
unsigned short c1=0;c1<
nc;c1++){
468 for(
unsigned short c2=0;c2<
nc;c2++){
476 Xmn.
diag[c1]+=
creal(sig*(X2s*X1c+X1s*X2c));
478 Xmn.
offd+=sig*(X2s*X1c+X1s*X2c);
486 for(
unsigned short c=0;c<
nc;c++)
504 out[0]=G[0]*X[0]+G[1]*X[2];
505 out[1]=G[0]*X[1]+G[1]*X[3];
506 out[2]=-
conj(G[1])*X[0]+
conj(G[0])*X[2];
507 out[3]=-
conj(G[1])*X[1]+
conj(G[0])*X[3];
519 out[0]=G[0]*X[0]-
conj(G[1])*X[1];
520 out[1]=G[1]*X[0]+
conj(G[0])*X[1];
521 out[2]=G[0]*X[2]-
conj(G[1])*X[3];
522 out[3]=G[1]*X[2]+
conj(G[0])*X[3];
543 const unsigned short *sigin,
unsigned int *iu,
unsigned int *
id,
const float akappa){
544 const char funcname[] =
"Clov_Force";
549 unsigned short nclov=6;
unsigned short clov=0;
553 for(
unsigned short mu=0;mu<
ndim-1;mu++)
554 for(
unsigned short nu=mu+1;nu<
ndim;nu++)
556 clov = (mu==0) ? nu-1 : mu+nu;
559 CalcXmunu(Xmn[clov],X1,X2,sigval,sigin,mu,nu);
565 for(
unsigned short mu=0;mu<
ndim;mu++)
566 for(
unsigned short nu=0;nu<
ndim;nu++)
569 clov = (mu==0) ? nu-1 : mu+nu;
571 clov = (nu==0) ? mu-1 : mu+nu;
572#pragma omp parallel for
573 for(
unsigned int i=0;i<
kvol;i++){
579 unsigned int ind =
id[i+
kvol*nu];
595 W6[0]=W0[0]*W1[0]-W0[1]*conjf(W1[1]); W6[1]=W0[0]*W1[1]+W0[1]*conjf(W1[0]);
605 for(
unsigned short c=0;c<
nc*
nc;c++)
606 Zbuff1[c]+=Zbuff2[c];
611 GLeft(Zbuff2,W5,Zbuff1);
616 for(
unsigned short c=0;c<
nc*
nc;c++)
635 W7[0]=W0[0]*W1[0]-W0[1]*conjf(W1[1]); W7[1]=W0[0]*W1[1]+W0[1]*conjf(W1[0]);
643 for(
unsigned short c=0;c<
nc*
nc;c++)
644 Zbuff1[c]+=Zbuff2[c];
654 for(
unsigned short c=0;c<
nc*
nc;c++)
657 W0[0]=W7[0]*W4[0]-W7[1]*conjf(W4[1]); W0[1]=W7[0]*W4[1]+W7[1]*conjf(W4[0]);
658 W1[0]=W5[0]*W6[0]-W5[1]*conjf(W6[1]); W1[1]=W5[0]*W6[1]+W5[1]*conjf(W6[0]);
660 W0[0]-=W1[0]; W0[1]-=W1[1];
667 for(
unsigned short c=0;c<
nc*
nc;c++)
676 for(
unsigned short c=0;c<
nc*
nc;c++){
684 for(
unsigned short gen=0;gen<
nadj;gen++){
685 W1[0]=W0[0]; W1[1]=W0[1];
687 GLeft(Zbuff1,W1,F_int);
689 float dSdpis=crealf(Zbuff1[0])+crealf(Zbuff1[3]);
691 dSdpi[i+
kvol*(gen*
ndim+mu)] -=akappa*dSdpis/4.0f;
693 dSdpi[i+
kvol*(gen*
ndim+mu)] +=akappa*dSdpis/4.0f;
697 for(clov=0;clov<nclov;clov++){
698 free(Xmn[clov].diag); free(Xmn[clov].offd);
706 const char funcname[] =
"Init_clover";
707 unsigned short __attribute__((aligned(
AVX))) sigin_t[6][4] = {{0,1,2,3},{1,0,3,2},{1,0,3,2},{1,0,3,2},{1,0,3,2},{0,1,2,3}};
715 Complex __attribute__((aligned(
AVX))) sigval_t[6][4] = {{1,-1,1,-1},{
I,-
I,
I,-
I},{-1,-1,1,1},{1,1,1,1},{
I,-
I,-
I,
I},{-1,1,1,-1}};
719 cblas_zdscal(6*4, 0.5*c_sw, sigval_t, 1);
721#pragma omp parallel for simd collapse(2) aligned(sigval,sigval_f:AVX)
724 sigval_t[i][j]*=c_sw*0.5;
729 cudaGetDevice(&device);
731 cudaMalloc((
void **)sigin,6*4*
sizeof(
short));
732 cudaMalloc((
void **)sigval,6*4*
sizeof(
Complex));
733 cudaMalloc((
void **)sigval_f,6*4*
sizeof(
Complex_f));
735 cudaMemcpy(*sigin,sigin_t,6*4*
sizeof(
short),cudaMemcpyDefault);
736 cudaMemcpy(*sigval,sigval_t,6*4*
sizeof(
Complex),cudaMemcpyDefault);
740 *sigin = (
unsigned short *)malloc(6*4*
sizeof(
short));
743 memcpy(*sigval,sigval_t,6*4*
sizeof(
Complex));
744 memcpy(*sigin,sigin_t,6*4*
sizeof(
short));
745 for(
int i=0;i<6*4;i++)
751 for(
unsigned short c=0;c<
nc;c++){
756 cudaFreeAsync(clover[c],
streams[c]);
Routines needed for Clover improved wilson fermions.
static void GRight(Complex_f out[4], const Complex_f G[2], const Complex_f X[4])
Multiplies by a gauge field from the right.
void cuCalcXmunu(Bilinear_a Xmunu, Complex_f *X1, Complex_f *X2, const Complex_f *sigval, const unsigned short *sigin, const unsigned short mu, const unsigned short nu)
CUDA wrapper for CalcXmunu. Only called during testing to be honest.
void CalcXmunu(Bilinear_a Xmunu, Complex_f *X1, Complex_f *X2, const Complex_f *sigval, const unsigned short *sigin, const unsigned short mu, const unsigned short nu)
Gets for the clover force.
static void GLeft(Complex_f out[4], const Complex_f G[2], const Complex_f X[4])
Multiplies by a gauge field from the left.
int cuClov_Force(double *dSdpi, Complex_f *ut[nc], Complex_f *X1, Complex_f *X2, const Complex_f *sigval, const unsigned short *sigin, const unsigned int *iu, const unsigned int *id, const float akappa)
CUDA wrapper for Clover_Force.
static void GSandwich(Complex_f out[4], Complex_f tmp[4], const Complex_f Gl[2], const Complex_f X[4], const Complex_f Gr[2])
Multiplies by a gauge field from the left and the right.
static void GetBilinear(Complex_f Z[nc *nc], Bilinear_a Xmn, unsigned int ind)
Loads the compacted bilinear form into a complex valued matrix.
void Clov_Force(double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, const Complex_f *sigval, const unsigned short *sigin, unsigned int *iu, unsigned int *id, const float akappa)
Gets the clover contribution to the force.
void cuHbyClover(Complex *phi, Complex *r, Complex *clover[nc], Complex *sigval, const float akappa, unsigned short *sigin, bool dag)
CUDA wrapper for HbyClover.
void cuByClover_f(Complex_f *phi, Complex_f *r, Complex_f *clover[nc], Complex_f *sigval, const float akappa, unsigned short *sigin, bool dag)
CUDA wrapper for ByClover_f.
void cuHbyClover_f(Complex_f *phi, Complex_f *r, Complex_f *clover[nc], Complex_f *sigval, const float akappa, unsigned short *sigin, bool dag)
CUDA wrapper for HbyClover_f.
void HbyClover(Complex *phi, Complex *r, Complex *clover[2], Complex *sigval, const float akappa, unsigned short *sigin, bool dag)
Clover analogue of the Dslash operation. This version acts on all flavours similar to Dslash and Dsla...
void ByClover(Complex *phi, Complex *r, Complex *clover[2], Complex *sigval, const float akappa, unsigned short *sigin, bool dag)
Clover analogue of the Dslash operation. This version acts on all flavours similar to Dslash and Dsla...
void cuByClover(Complex *phi, Complex *r, Complex *clover[nc], Complex *sigval, const float akappa, unsigned short *sigin, bool dag)
CUDA wrapper for ByClover.
void ByClover_f(Complex_f *phi, Complex_f *r, Complex_f *clover[2], Complex_f *sigval, const float akappa, unsigned short *sigin, bool dag)
Clover analogue of the Dslash operation. This version acts on all flavours similar to Dslash and Dsla...
void HbyClover_f(Complex_f *phi, Complex_f *r, Complex_f *clover[2], Complex_f *sigval, const float akappa, unsigned short *sigin, bool dag)
Clover analogue of the Dslash operation. This version acts on all flavours similar to Dslash and Dsla...
int cuClover(Complex_f *clover[nc], Complex_f *ut[nc], unsigned int *iu, unsigned int *id)
CUDA wrapper for calculating the clovers in all directions at all sites .
void ByGenRight(Complex_f a[nc], const unsigned short gen)
Multiply leaf (or part of one) by generator from right.
void Half_Leaf(Complex_f Leaves[nc], Complex_f *ut[nc], Complex_f a[nc], unsigned int *iu, unsigned int *id, const unsigned int i, const unsigned short mu, const unsigned short nu, const unsigned short leaf)
Calculates the first half of the leaf for a clover term. We split it so that the force term can reuse...
void Clover_free(Complex_f *clover[nc])
Free's memory used for clover terms and leaves.
void Leaf(Complex_f Leaves[nc], Complex_f *ut[nc], unsigned int *iu, unsigned int *id, unsigned int i, const unsigned short mu, const unsigned short nu, const unsigned short leaf)
Calculates a leaf for a clover term.
void Half_Leaves(Complex_f *hLeaves[2], Complex_f *ut[2], unsigned int *iu, unsigned int *id, const unsigned short mu, const unsigned short nu)
Calculates the products of the first two links in a plaquette.
int Init_clover(Complex **sigval, Complex_f **sigval_f, unsigned short **sigin, float c_sw)
Initialise values needed for the clover terms.
void ByGenLeft(Complex_f a[nc], const unsigned short gen)
Multiply leaf (or part of one) by generator from left.
void Clover(Complex_f *clover[2], Complex_f *ut[2], unsigned int *iu, unsigned int *id)
Calculates the clovers in all directions at all sites.
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
void cuComplex_convert(Complex_f *a, Complex *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid)
takes an array of complex float and double precision numbers and converts the precision
int CHalo_swap_all(Complex_f *c, 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.
#define AVX
Alignment of arrays. 64 for AVX-512, 32 for AVX/AVX2. 16 for SSE. Since AVX is standard on modern x86...
#define ngorkov
Gor'kov indices.
#define nadj
adjacent spatial indices
#define kvol
Sublattice volume.
#define Complex
Double precision complex number.
#define ndirac
Dirac indices.
dim3 dimBlockOne
block size of one
dim3 dimGridOne
Grid size of one.
#define Complex_f
Single precision complex number.
#define kvolHalo
Subvolume + halo size.
Structure of arrays for Hermitian bilinear in memory.
Complex_f * offd
Complex valued off-diagonal terms. We only need to store one of these to get the other in .
float * diag
Real valued diagonal terms.
Hermitian bilinear on the local stack.
float diag[2]
Real valued diagonal terms.
Complex_f offd
Complex valued off-diagonal terms. We only need to store one of these to get the other in .
cudaStream_t streams[ndirac *ndim *nadj]
An array of concurrent GPU streams to keep it busy.
#define creal(z)
Extract Real Component using C standard notation.
#define I
Define I in double precision using C standard notation.