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++){
279 phi[i+
kvol*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
281 phi[i+
kvolHalo*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
288 const char funcname[] =
"HbyClover";
292#pragma omp parallel for simd
293 for(
unsigned int i=0;i<
kvol;i++){
297 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
298 for(
unsigned short c=0; c<
nc; c++){
303 for(
unsigned short clov=0;clov<6;clov++){
304 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
305 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc){
306 const unsigned short sind = sigin[clov*
ndirac+(idirac>>1)] << (
nc-1);
308 for(
unsigned short c=0; c<
nc; c++){
314 phi_s[idirac+0]+=sig*(
creal(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
316 phi_s[idirac+1]+=sig*(
conj(clov_s[1])*r_s[0]-
creal(clov_s[0])*r_s[1]);
320 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
321 for(
unsigned short c=0; c<
nc; c++)
324 phi[i+
kvol*(c+idirac)]+=akappa*phi_s[idirac+c];
326 phi[i+
kvolHalo*(c+idirac)]+=akappa*phi_s[idirac+c];
336#pragma omp parallel for simd
337 for(
unsigned int i=0;i<
kvol;i++){
341 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++)
342 for(
unsigned short c=0; c<
nc; c++){
348 for(
unsigned short clov=0;clov<6;clov++){
349 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
350 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++){
352 const unsigned short idirac = igorkov&3;
353 const unsigned short sind = (igorkov<4) ? sigin[clov*
ndirac+idirac] : sigin[clov*
ndirac+idirac]+4;
355 for(
unsigned short c=0; c<
nc; c++)
358 phi_s[igorkov][0]+=sigval[clov*
ndirac+idirac]*(crealf(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
360 phi_s[igorkov][1]+=sigval[clov*
ndirac+idirac]*(
conj(clov_s[1])*r_s[0]-crealf(clov_s[0])*r_s[1]);
364 for(
unsigned short igorkov=0; igorkov<
ngorkov; igorkov++)
365 for(
unsigned short c=0; c<
nc; c++){
368 phi[i+
kvol*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
370 phi[i+
kvolHalo*(
nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
377 const char funcname[] =
"HbyClover_f";
381#pragma omp parallel for simd
382 for(
unsigned int i=0;i<
kvol;i++){
386 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
387 for(
unsigned short c=0; c<
nc; c++){
392 for(
unsigned short clov=0;clov<6;clov++){
393 clov_s[0]=clover[0][clov*
kvol+i]; clov_s[1]=clover[1][clov*
kvol+i];
394 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc){
395 const unsigned short sind = sigin[clov*
ndirac+(idirac>>1)] << (
nc-1);
397 for(
unsigned short c=0; c<
nc; c++){
402 phi_s[idirac+0]+=sig*(crealf(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
404 phi_s[idirac+1]+=sig*(
conj(clov_s[1])*r_s[0]-crealf(clov_s[0])*r_s[1]);
408 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc)
409 for(
unsigned short c=0; c<
nc; c++)
412 phi[i+
kvol*(c+idirac)]+=akappa*phi_s[idirac+c];
414 phi[i+
kvolHalo*(c+idirac)]+=akappa*phi_s[idirac+c];
434 Z[1]=Xmn.
offd[ind]; Z[2]=conjf(Z[1]);
438 const unsigned short mu,
const unsigned short nu){
439 const char funcname[] =
"Xmunu";
445 clov = (mu==0) ? nu-1 : mu+nu;
446#pragma omp parallel for simd aligned(X1,X2:AVX)
447 for(
unsigned int i=0;i<
kvol;i++){
451 for(
unsigned short idirac=0; idirac<
ndirac*
nc; idirac+=
nc){
452 const unsigned short sind = sigin[clov*
ndirac+(idirac>>1)]<<1;
455 for(
unsigned short c1=0;c1<
nc;c1++){
460 for(
unsigned short c2=0;c2<
nc;c2++){
468 Xmn.
diag[c1]+=
creal(sig*(X2s*X1c+X1s*X2c));
470 Xmn.
offd+=sig*(X2s*X1c+X1s*X2c);
478 for(
unsigned short c=0;c<
nc;c++)
496 out[0]=G[0]*X[0]+G[1]*X[2];
497 out[1]=G[0]*X[1]+G[1]*X[3];
498 out[2]=-
conj(G[1])*X[0]+
conj(G[0])*X[2];
499 out[3]=-
conj(G[1])*X[1]+
conj(G[0])*X[3];
511 out[0]=G[0]*X[0]-
conj(G[1])*X[1];
512 out[1]=G[1]*X[0]+
conj(G[0])*X[1];
513 out[2]=G[0]*X[2]-
conj(G[1])*X[3];
514 out[3]=G[1]*X[2]+
conj(G[0])*X[3];
535 const unsigned short *sigin,
unsigned int *iu,
unsigned int *
id,
const float akappa){
536 const char funcname[] =
"Clov_Force";
541 unsigned short nclov=6;
unsigned short clov=0;
545 for(
unsigned short mu=0;mu<
ndim-1;mu++)
546 for(
unsigned short nu=mu+1;nu<
ndim;nu++)
548 clov = (mu==0) ? nu-1 : mu+nu;
551 CalcXmunu(Xmn[clov],X1,X2,sigval,sigin,mu,nu);
557 for(
unsigned short mu=0;mu<
ndim;mu++)
558 for(
unsigned short nu=0;nu<
ndim;nu++)
561 clov = (mu==0) ? nu-1 : mu+nu;
563 clov = (nu==0) ? mu-1 : mu+nu;
564#pragma omp parallel for
565 for(
unsigned int i=0;i<
kvol;i++){
571 unsigned int ind =
id[i+
kvol*nu];
587 W6[0]=W0[0]*W1[0]-W0[1]*conjf(W1[1]); W6[1]=W0[0]*W1[1]+W0[1]*conjf(W1[0]);
597 for(
unsigned short c=0;c<
nc*
nc;c++)
598 Zbuff1[c]+=Zbuff2[c];
603 GLeft(Zbuff2,W5,Zbuff1);
608 for(
unsigned short c=0;c<
nc*
nc;c++)
627 W7[0]=W0[0]*W1[0]-W0[1]*conjf(W1[1]); W7[1]=W0[0]*W1[1]+W0[1]*conjf(W1[0]);
635 for(
unsigned short c=0;c<
nc*
nc;c++)
636 Zbuff1[c]+=Zbuff2[c];
646 for(
unsigned short c=0;c<
nc*
nc;c++)
649 W0[0]=W7[0]*W4[0]-W7[1]*conjf(W4[1]); W0[1]=W7[0]*W4[1]+W7[1]*conjf(W4[0]);
650 W1[0]=W5[0]*W6[0]-W5[1]*conjf(W6[1]); W1[1]=W5[0]*W6[1]+W5[1]*conjf(W6[0]);
652 W0[0]-=W1[0]; W0[1]-=W1[1];
659 for(
unsigned short c=0;c<
nc*
nc;c++)
668 for(
unsigned short c=0;c<
nc*
nc;c++){
676 for(
unsigned short gen=0;gen<
nadj;gen++){
677 W1[0]=W0[0]; W1[1]=W0[1];
679 GLeft(Zbuff1,W1,F_int);
681 float dSdpis=crealf(Zbuff1[0])+crealf(Zbuff1[3]);
683 dSdpi[i+
kvol*(gen*
ndim+mu)] -=akappa*dSdpis/4.0f;
685 dSdpi[i+
kvol*(gen*
ndim+mu)] +=akappa*dSdpis/4.0f;
689 for(clov=0;clov<nclov;clov++){
690 free(Xmn[clov].diag); free(Xmn[clov].offd);
698 const char funcname[] =
"Init_clover";
699 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}};
707 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}};
711 cblas_zdscal(6*4, 0.5*c_sw, sigval_t, 1);
713#pragma omp parallel for simd collapse(2) aligned(sigval,sigval_f:AVX)
716 sigval_t[i][j]*=c_sw*0.5;
721 cudaGetDevice(&device);
723 cudaMalloc((
void **)sigin,6*4*
sizeof(
short));
724 cudaMalloc((
void **)sigval,6*4*
sizeof(
Complex));
725 cudaMalloc((
void **)sigval_f,6*4*
sizeof(
Complex_f));
727 cudaMemcpy(*sigin,sigin_t,6*4*
sizeof(
short),cudaMemcpyDefault);
728 cudaMemcpy(*sigval,sigval_t,6*4*
sizeof(
Complex),cudaMemcpyDefault);
732 *sigin = (
unsigned short *)malloc(6*4*
sizeof(
short));
735 memcpy(*sigval,sigval_t,6*4*
sizeof(
Complex));
736 memcpy(*sigin,sigin_t,6*4*
sizeof(
short));
737 for(
int i=0;i<6*4;i++)
743 for(
unsigned short c=0;c<
nc;c++){
748 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.