su2hmc
Loading...
Searching...
No Matches
clover.c
Go to the documentation of this file.
1
6#include <clover.h>
7//Multiplying by generators
8#pragma omp declare simd
9void ByGenLeft(Complex_f a[nc],const unsigned short gen){
10 Complex_f tmp = a[0];
11 switch(gen){
13 case(0):
14 a[0] = -cimagf(a[1])-crealf(a[1])*I;
15 a[1] = cimagf(tmp)+crealf(tmp)*I;
16 break;
18 case(1):
19 a[0] = -conjf(a[1]);
20 a[1] = conjf(tmp);
21 break;
23 case(2):
24 a[0] = -cimagf(a[0])+crealf(a[0])*I;
25 a[1] = -cimagf(a[1])+crealf(a[1])*I;
26 break;
27 }
28 return;
29}
30#pragma omp declare simd
31void ByGenRight(Complex_f a[nc],const unsigned short gen){
32 Complex_f tmp = a[0];
33 switch(gen){
35 case(0):
36 a[0] = -cimagf(a[1])+crealf(a[1])*I;
37 a[1] = -cimagf(tmp)+ crealf(tmp)*I;
38 break;
40 case(1):
41 a[0]=-a[1]; a[1]=tmp;
42 break;
44 case(2):
45 a[0] = -cimagf(a[0])+crealf(a[0])*I;
46 a[1] = cimagf(a[1])-crealf(a[1])*I;
47 break;
48 }
49 return;
50}
51
52//Calculating the clover and the leaves
53//=====================================
69#pragma omp declare simd
70void Half_Leaf(Complex_f Leaves[nc], Complex_f *ut[nc], Complex_f a[nc], unsigned int *iu,\
71 unsigned int *id, const unsigned int i, const unsigned short mu, const unsigned short nu, const unsigned short leaf){
72 unsigned int uidm;
73 switch(leaf){
74 case(0):
76 a[0]=ut[0][i+kvolHalo*mu]; a[1]=ut[1][i+kvolHalo*mu];
77 uidm = iu[mu*kvol+i];
78
80 Leaves[0]=a[0]*ut[0][uidm+kvolHalo*nu]-a[1]*conjf(ut[1][uidm+kvolHalo*nu]);
81 Leaves[1]=a[0]*ut[1][uidm+kvolHalo*nu]+a[1]*conjf(ut[0][uidm+kvolHalo*nu]);
82 break;
83 case(1):
85 //Should really read didm, but I've already declared this
86 uidm = id[mu*kvol+i];
87 a[0]=ut[0][i+kvolHalo*nu]; a[1]=ut[1][i+kvolHalo*nu];
88 //Awkward index...
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];
93 break;
94 case(2):
96 //Should really read didn, but I've already declared this
97 uidm = id[nu*kvol+i];
98 //Daggered. So Conj what goes into a[0] and negate what goes into a[1]
99 a[0]=conjf(ut[0][uidm+kvolHalo*nu]); a[1]=-ut[1][uidm+kvolHalo*nu];
100
102 //Don't forget negation of second term was handled earlier!
103 Leaves[0]=a[0]*ut[0][uidm+kvolHalo*mu]-a[1]*conjf(ut[1][uidm+kvolHalo*mu]);
104 Leaves[1]=a[0]*ut[1][uidm+kvolHalo*mu]+a[1]*conjf(ut[0][uidm+kvolHalo*mu]);
105 break;
106 case(3):
108 //Should really read didm, but I've already declared this
109 uidm = id[i+kvol*mu];
110 //Daggered. So Conj what goes into a[0] and negate what goes into a[1]
111 a[0]=conjf(ut[0][uidm+kvolHalo*mu]); a[1]=-ut[1][uidm+kvolHalo*mu];
112 //Another awkward index
113 const unsigned int din_didm=id[nu*kvol+uidm];
114
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];
118 break;
119 }
120 return;
121}
122void Half_Leaves(Complex_f *hLeaves[2],Complex_f *ut[2], unsigned int *iu,unsigned int *id,\
123 const unsigned short mu,const unsigned short nu){
124
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++){
128 Complex_f Leaves[nc], a[nc];
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];
131 }
132 return;
133}
134#pragma omp declare simd
135void Leaf(Complex_f Leaves[nc],Complex_f *ut[nc], unsigned int *iu, unsigned int *id, unsigned int i,\
136 const unsigned short mu, const unsigned short nu,const unsigned short leaf){
137 Complex_f a[nc];
138 Half_Leaf(Leaves,ut,a,iu,id,i,mu,nu,leaf);
139 unsigned int didm,didn,uidm;
140 switch(leaf){
141 case(0):
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]);
146 a[1]=-Leaves[0]*ut[1][uidn+kvolHalo*mu]+Leaves[1]*ut[0][uidn+kvolHalo*mu];
147
149 Leaves[0]=a[0]*conjf(ut[0][i+kvolHalo*nu])+a[1]*conjf(ut[1][i+kvolHalo*nu]);
150 Leaves[1]=-a[0]*ut[1][i+kvolHalo*nu]+a[1]*ut[0][i+kvolHalo*nu];
151
152 //DEBUG
153 // Leaves[0]=0; Leaves[1]=0;
154 break;
155 case(1):
157 didm = id[mu*kvol+i];
158
160 a[0]=Leaves[0]*conjf(ut[0][didm+kvolHalo*nu])+Leaves[1]*conjf(ut[1][didm+kvolHalo*nu]);
161 a[1]=-Leaves[0]*ut[1][didm+kvolHalo*nu]+Leaves[1]*ut[0][didm+kvolHalo*nu];
162
164 Leaves[0]=a[0]*ut[0][didm+kvolHalo*mu]-a[1]*conjf(ut[1][didm+kvolHalo*mu]);
165 Leaves[1]=a[0]*ut[1][didm+kvolHalo*mu]+a[1]*conjf(ut[0][didm+kvolHalo*mu]);
166 //DEBUG
167 // Leaves[0]=0; Leaves[1]=0;
168 break;
169 case(2):
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]);
176
178 Leaves[0]=a[0]*conjf(ut[0][i+kvolHalo*mu])+a[1]*conjf(ut[1][i+kvolHalo*mu]);
179 Leaves[1]=-a[0]*ut[1][i+kvolHalo*mu]+a[1]*ut[0][i+kvolHalo*mu];
180
181 //DEBUG
182 // Leaves[0]=0; Leaves[1]=0;
183 break;
184 case(3):
186 didn = id[nu*kvol+i];
187 unsigned int din_didm=id[mu*kvol+didn];
188
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]);
192
194 Leaves[0]=a[0]*ut[0][didn+kvolHalo*nu]-a[1]*conjf(ut[1][didn+kvolHalo*nu]);
195 Leaves[1]=a[0]*ut[1][didn+kvolHalo*nu]+a[1]*conjf(ut[0][didn+kvolHalo*nu]);
196
197 //DEBUG
198 // Leaves[0]=0; Leaves[1]=0;
199 break;
200 }
201 return;
202}
203void Clover(Complex_f *clover[2], Complex_f *ut[2], unsigned int *iu, unsigned int *id){
204 const char funcname[]="Full_Clover";
205#ifdef USE_GPU
206 cuClover(clover,ut,iu,id);
207#else
208 clover[0]=aligned_alloc(AVX,6*kvol*sizeof(Complex_f));
209 clover[1]=aligned_alloc(AVX,6*kvol*sizeof(Complex_f));
210 for(unsigned short mu=0;mu<ndim-1;mu++)
211 for(unsigned short nu=mu+1;nu<ndim;nu++)
212 if(mu!=nu){
213 //Clover index
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;
219 Complex_f Leaves[nc];
220 for(unsigned short leaf=0;leaf<ndim;leaf++)
221 {
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];
224 }
227
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);
235 }
236 }
237#endif
238 return;
239}
240
241//Multiplication for Congradq
242//=========================
243void ByClover(Complex *phi, Complex *r, Complex *clover[2], Complex *sigval, const float akappa, unsigned short *sigin, bool dag){
244#ifdef USE_GPU
245 cuByClover(phi,r,clover,sigval,akappa,sigin,dag);
246#else
247#pragma omp parallel for simd
248 for(unsigned int i=0;i<kvol;i++){
249 //Prefetched r and Phi array
250 Complex phi_s[ngorkov][nc];
251#pragma unroll
252 for(unsigned short igorkov=0; igorkov<ngorkov; igorkov++)
253 for(unsigned short c=0; c<nc; c++){
254 phi_s[igorkov][c]=0;
255 }
256 Complex r_s[nc];
257 Complex clov_s[nc];
258#pragma unroll
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++){
262 //Mod 4 done bitwise. In general n mod 2^m = n & (2^m-1)
263 const unsigned short idirac = igorkov&3;
264 const unsigned short sind = (igorkov<4) ? sigin[clov*ndirac+idirac] : sigin[clov*ndirac+idirac]+4;
265#pragma unroll
266 for(unsigned short c=0; c<nc; c++)
267 r_s[c]= r[i+kvolHalo*(sind*nc+c)];
269 phi_s[igorkov][0]+=sigval[clov*ndirac+idirac]*(creal(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
270 //Clover is in the Lie Algebra, not Lie group. So signs are correct here.
271 phi_s[igorkov][1]+=sigval[clov*ndirac+idirac]*(conj(clov_s[1])*r_s[0]-creal(clov_s[0])*r_s[1]);
272 }
273 }
274#pragma unroll
275 for(unsigned short igorkov=0; igorkov<ngorkov; igorkov++)
276 for(unsigned short c=0; c<nc; c++){
277 //dag is just to do with the output layout and if it has a halo
278 if(dag)
279 phi[i+kvol*(nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
280 else
281 phi[i+kvolHalo*(nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
282 }
283 }
284#endif
285 return;
286}
287void HbyClover(Complex *phi, Complex *r, Complex *clover[2],Complex *sigval, const float akappa, unsigned short *sigin,bool dag){
288 const char funcname[] = "HbyClover";
289#ifdef USE_GPU
290 cuHbyClover(phi,r,clover,sigval,akappa,sigin,dag);
291#else
292#pragma omp parallel for simd
293 for(unsigned int i=0;i<kvol;i++){
294 //Prefetched r and Phi array
295 Complex phi_s[ndirac*nc];
296#pragma unroll
297 for(unsigned short idirac=0; idirac<ndirac*nc; idirac+=nc)
298 for(unsigned short c=0; c<nc; c++){
299 phi_s[idirac+c]=0;
300 }
301 Complex r_s[nc]; Complex clov_s[nc];
302#pragma unroll
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);
307#pragma unroll
308 for(unsigned short c=0; c<nc; c++){
309 r_s[c]= r[i+kvolHalo*(sind+c)];
310 }
312 const Complex sig=sigval[clov*ndirac+(idirac>>1)];
313 //creal just an optimisation. Compiler can't optimise out the zero imag.
314 phi_s[idirac+0]+=sig*(creal(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
315 //Clover is in the Lie Algebra, not Lie group. So signs are correct here.
316 phi_s[idirac+1]+=sig*(conj(clov_s[1])*r_s[0]-creal(clov_s[0])*r_s[1]);
317 }
318 }
319#pragma unroll
320 for(unsigned short idirac=0; idirac<ndirac*nc; idirac+=nc)
321 for(unsigned short c=0; c<nc; c++)
322 //dag is just to do with the output layout and if it has a halo
323 if(dag)
324 phi[i+kvol*(c+idirac)]+=akappa*phi_s[idirac+c];
325 else
326 phi[i+kvolHalo*(c+idirac)]+=akappa*phi_s[idirac+c];
327 }
328#endif
329 return;
330}
331//Float versions
332void ByClover_f(Complex_f *phi, Complex_f *r, Complex_f *clover[2], Complex_f *sigval, const float akappa, unsigned short *sigin, bool dag){
333#ifdef USE_GPU
334 cuByClover_f(phi,r,clover,sigval,akappa,sigin,dag);
335#else
336#pragma omp parallel for simd
337 for(unsigned int i=0;i<kvol;i++){
338 //Prefetched r and Phi array
339 Complex_f phi_s[ngorkov][nc];
340#pragma unroll
341 for(unsigned short igorkov=0; igorkov<ngorkov; igorkov++)
342 for(unsigned short c=0; c<nc; c++){
343 phi_s[igorkov][c]=0;
344 }
345 Complex_f r_s[nc];
346 Complex_f clov_s[nc];
347#pragma unroll
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++){
351 //Mod 4 done bitwise. In general n mod 2^m = n & (2^m-1)
352 const unsigned short idirac = igorkov&3;
353 const unsigned short sind = (igorkov<4) ? sigin[clov*ndirac+idirac] : sigin[clov*ndirac+idirac]+4;
354#pragma unroll
355 for(unsigned short c=0; c<nc; c++)
356 r_s[c]= r[i+kvolHalo*(sind*nc+c)];
358 phi_s[igorkov][0]+=sigval[clov*ndirac+idirac]*(crealf(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
359 //Clover is in the Lie Algebra, not Lie group. So signs are correct here.
360 phi_s[igorkov][1]+=sigval[clov*ndirac+idirac]*(conj(clov_s[1])*r_s[0]-crealf(clov_s[0])*r_s[1]);
361 }
362 }
363#pragma unroll
364 for(unsigned short igorkov=0; igorkov<ngorkov; igorkov++)
365 for(unsigned short c=0; c<nc; c++){
366 //dag is just to do with the output layout and if it has a halo
367 if(dag)
368 phi[i+kvol*(nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
369 else
370 phi[i+kvolHalo*(nc*igorkov+c)]+=akappa*phi_s[igorkov][c];
371 }
372 }
373#endif
374 return;
375}
376void HbyClover_f(Complex_f *phi, Complex_f *r, Complex_f *clover[2],Complex_f *sigval, const float akappa, unsigned short *sigin,bool dag){
377 const char funcname[] = "HbyClover_f";
378#ifdef USE_GPU
379 cuHbyClover_f(phi,r,clover,sigval,akappa,sigin,dag);
380#else
381#pragma omp parallel for simd
382 for(unsigned int i=0;i<kvol;i++){
383 //Prefetched r and Phi array
384 Complex_f phi_s[ndirac*nc];
385#pragma unroll
386 for(unsigned short idirac=0; idirac<ndirac*nc; idirac+=nc)
387 for(unsigned short c=0; c<nc; c++){
388 phi_s[idirac+c]=0;
389 }
390 Complex_f r_s[nc]; Complex_f clov_s[nc];
391#pragma unroll
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);
396#pragma unroll
397 for(unsigned short c=0; c<nc; c++){
398 r_s[c]= r[i+kvolHalo*(sind+c)];
399 }
401 const Complex_f sig=sigval[clov*ndirac+(idirac>>1)];
402 phi_s[idirac+0]+=sig*(crealf(clov_s[0])*r_s[0]+clov_s[1]*r_s[1]);
403 //Clover is in the Lie Algebra, not Lie group. So signs are correct here.
404 phi_s[idirac+1]+=sig*(conj(clov_s[1])*r_s[0]-crealf(clov_s[0])*r_s[1]);
405 }
406 }
407#pragma unroll
408 for(unsigned short idirac=0; idirac<ndirac*nc; idirac+=nc)
409 for(unsigned short c=0; c<nc; c++)
410 //dag is just to do with the output layout and if it has a halo
411 if(dag)
412 phi[i+kvol*(c+idirac)]+=akappa*phi_s[idirac+c];
413 else
414 phi[i+kvolHalo*(c+idirac)]+=akappa*phi_s[idirac+c];
415 }
416#endif
417 return;
418}
419
420//Clover Force
421//===========
432static inline void GetBilinear(Complex_f Z[nc*nc], Bilinear_a Xmn,unsigned int ind){
433 Z[0]=Xmn.diag[ind]; Z[3]=Xmn.diag[ind+kvolHalo];
434 Z[1]=Xmn.offd[ind]; Z[2]=conjf(Z[1]);
435 return;
436}
437void CalcXmunu(Bilinear_a Xmunu, Complex_f *X1, Complex_f *X2, const Complex_f *sigval, const unsigned short *sigin,\
438 const unsigned short mu, const unsigned short nu){
439 const char funcname[] = "Xmunu";
440#ifdef USE_GPU
441 cuCalcXmunu(Xmunu,X1,X2,sigval,sigin,mu,nu);
442#else
443 unsigned short clov;
444 //Get sign and index of @f$\sigma_{\mu\nu}@f$ correct
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++){
448 //Buffer. Four registers
449 Bilinear Xmn;
450 Xmn.diag[0]=Xmn.diag[1]=0;Xmn.offd=0;
451 for(unsigned short idirac=0; idirac<ndirac*nc; idirac+=nc){
452 const unsigned short sind = sigin[clov*ndirac+(idirac>>1)]<<1;
453 const Complex_f sig = sigval[clov*ndirac+(idirac>>1)];
454#pragma unroll
455 for(unsigned short c1=0;c1<nc;c1++){
456 //Spinors (rows) So we only load from memory once.
457 const Complex_f X1s = X1[i+kvolHalo*(sind+c1)];
458 const Complex_f X2s = X2[i+kvolHalo*(sind+c1)];
459#pragma unroll
460 for(unsigned short c2=0;c2<nc;c2++){
461 //The second off diagonal term is the conjugate of the first
462 if(c1==1&&c2==0)
463 continue;
464 //Conjugated spinor (columns).
465 const Complex_f X1c = conjf(X1[i+kvolHalo*(idirac+c2)]);
466 const Complex_f X2c = conjf(X2[i+kvolHalo*(idirac+c2)]);
467 if(c1==c2)
468 Xmn.diag[c1]+=creal(sig*(X2s*X1c+X1s*X2c));
469 else
470 Xmn.offd+=sig*(X2s*X1c+X1s*X2c);
471
472 }
473 }
474 }
475 //And write back to global memory.
476#pragma unroll
477 //Write the diagonals
478 for(unsigned short c=0;c<nc;c++)
479 Xmunu.diag[i+kvolHalo*c]=Xmn.diag[c];
480 //And the off diagonal terms
481 Xmunu.offd[i]=Xmn.offd;
482 }
483#endif
484 return;
485}
486
495static inline void GLeft(Complex_f out[4],const Complex_f G[2], const Complex_f X[4]){
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];
500 return;
501}
502
510static inline void GRight(Complex_f out[4],const Complex_f G[2], const Complex_f X[4]){
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];
515 return;
516}
517
528static inline 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]){
529 GRight(tmp,Gr,X);
530 GLeft(out,Gl,tmp);
531 return;
532}
533
534void Clov_Force(double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, const Complex_f *sigval,\
535 const unsigned short *sigin, unsigned int *iu, unsigned int *id, const float akappa){
536 const char funcname[] = "Clov_Force";
537#ifdef USE_GPU
538 cuClov_Force(dSdpi,ut,X1,X2,sigval,sigin,iu,id,akappa);
539#else
540 //Allocate the @f$X_{\mu\nu}@f$ array
541 unsigned short nclov=6; unsigned short clov=0;
542 Bilinear_a Xmn[nclov];
543 //And get the @f$X_{\mu\nu}@f$ values
544 //Loop over @f$\mu@f$ and @f$\nu@f$. Symmetry means we actually only need half the terms
545 for(unsigned short mu=0;mu<ndim-1;mu++)
546 for(unsigned short nu=mu+1;nu<ndim;nu++)
547 if(mu!=nu){
548 clov = (mu==0) ? nu-1 : mu+nu;
549 Xmn[clov].diag=(float *)aligned_alloc(AVX,2*kvolHalo*sizeof(float));
550 Xmn[clov].offd=(Complex_f *)aligned_alloc(AVX,kvolHalo*sizeof(Complex_f));
551 CalcXmunu(Xmn[clov],X1,X2,sigval,sigin,mu,nu);
552#if(nproc>1)
553 SHalo_swap_all(Xmn[clov].diag,2);
554 CHalo_swap_all(Xmn[clov].offd,1);
555#endif
556 }
557 for(unsigned short mu=0;mu<ndim;mu++)
558 for(unsigned short nu=0;nu<ndim;nu++)
559 if(mu!=nu){
560 if(mu<nu)
561 clov = (mu==0) ? nu-1 : mu+nu;
562 else
563 clov = (nu==0) ? mu-1 : mu+nu;
564#pragma omp parallel for
565 for(unsigned int i=0;i<kvol;i++){
566 //This is where it gets messy. Using HiRep/OpenQCD labelling for different intermediate values
567 //But recycling to reduce register pressure on GPU
568 //First up, W0, W1 and W6 match their Documentation values
569 Complex_f W0[2], W1[2], W6[2];
570 //Get the correct site.
571 unsigned int ind = id[i+kvol*nu];
572 //Gauge field @f$U_\nu\left(i-\hat{\nu}\right)
573 W1[0]=ut[0][ind+kvolHalo*nu]; W1[1]=ut[1][ind+kvolHalo*nu];
574
575 //@f$Z_2=X_{\mu\nu}\left(x-\hat{\nu}\right)@f$
576 Complex_f Z[nc*nc];
577 GetBilinear(Z,Xmn[clov],ind);
578
579 //W0 is @f$U^\dagger_\mu\left(x-\hat{nu}\right)@f$
580 W0[0]=conjf(ut[0][ind+kvolHalo*mu]); W0[1]=-ut[1][ind+kvolHalo*mu];
581
582 //Need a temporary Z buffers for the intermediate result
583 Complex_f Zbuff1[nc*nc], Zbuff2[nc*nc];
584 GSandwich(Zbuff1,Zbuff2,W0,Z,W1);
585
586 //@f$W_6=W_0 W_1@f$
587 W6[0]=W0[0]*W1[0]-W0[1]*conjf(W1[1]); W6[1]=W0[0]*W1[1]+W0[1]*conjf(W1[0]);
588
589 //Z_3 is the @f$X_{\mu\nu}\left(x+\hat{\mu}-\hat{\nu}\right)@f$. Store in Z
590 ind=iu[ind+kvol*mu];
591 GetBilinear(Z,Xmn[clov],ind);
592
593 //Need a second Zbuffer for another intermediate result.
594 GRight(Zbuff2,W6,Z);
595 //Sum the two results into Zbuff1. Then scale by -W5
596#pragma unroll
597 for(unsigned short c=0;c<nc*nc;c++)
598 Zbuff1[c]+=Zbuff2[c];
599 //W5 is @f$U^\dagger_\nu\left(x+\hat{\mu}-\hat{\nu}\right)@f$
600 Complex_f W5[2];
601 W5[0]=conjf(ut[0][ind+kvolHalo*nu]); W5[1]=-ut[1][ind+kvolHalo*nu];
602 //Now multiply by @f$W_5@f$ from the left into Zbuff2
603 GLeft(Zbuff2,W5,Zbuff1);
604
605 //Intermediate results from the four parts of the sum.
606 Complex_f F_int[4];
607#pragma unroll
608 for(unsigned short c=0;c<nc*nc;c++)
609 //Negative as it is @f$-W_5@f$
610 F_int[c]=-Zbuff2[c];
611
612 //Now we repeat for the last term in the sum. Recycling along the way.
613 //First store @f$W_2=U_\nu\left(x+\hat{\mu}\right)@f$ into W0.
614 ind=iu[i+kvol*mu];
615 W0[0]=ut[0][ind+kvolHalo*nu]; W0[1]=ut[1][ind+kvolHalo*nu];
616 //@f$W_3=U^\dagger_\mu\left(x+\hat{\nu}\right)@f$. Storing it in W1
617 ind=iu[i+kvol*nu];
618 W1[0]=conjf(ut[0][ind+kvolHalo*mu]); W1[1]=-ut[1][ind+kvolHalo*mu];
619 //@f$Z_4=X_{\mu\nu}\left(x+\hat{\mu}+\hat{\nu}\right)@f$. Storing in Z
620 ind=iu[ind+kvol*mu];
621 GetBilinear(Z,Xmn[clov],ind);
622 //Calculate and write into Zbuff1
623 GSandwich(Zbuff1,Zbuff2,W0,Z,W1);
624
625 //@f$W_7=W_0 W_1@f$
626 Complex_f W7[2];
627 W7[0]=W0[0]*W1[0]-W0[1]*conjf(W1[1]); W7[1]=W0[0]*W1[1]+W0[1]*conjf(W1[0]);
628 //@f$Z_5=X_{\mu\nu}\left(x+\hat{\nu}\right)@f$
629 ind=iu[i+kvol*nu];
630 GetBilinear(Z,Xmn[clov],ind);
631 //And calculate the second term
632 GLeft(Zbuff2,W7,Z);
633 //Sum the two results into Zbuff1.
634#pragma unroll
635 for(unsigned short c=0;c<nc*nc;c++)
636 Zbuff1[c]+=Zbuff2[c];
637
638 //W4 is @f$U^\dagger_\nu\left(x\right)@f$
639 Complex_f W4[2];
640 W4[0]=conjf(ut[0][i+kvolHalo*nu]); W4[1]=-ut[1][i+kvolHalo*nu];
641 //Now multiply by @f$W_4@f$ from the right into Zbuff2
642 GRight(Zbuff2,W4,Zbuff1);
643
644 //Intermediate results from the four parts of the sum.
645#pragma unroll
646 for(unsigned short c=0;c<nc*nc;c++)
647 F_int[c]+=Zbuff2[c];
648 //The last thing we need is @f$W_8=W_7W_4-W_5W_6@f$. Do it in parts and store intermediates in W0 and W1
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]);
651 //Store W8 in W0
652 W0[0]-=W1[0]; W0[1]-=W1[1];
653
654 //Now load @f$Z_0=X_{\mu\nu}(x)@f$
655 GetBilinear(Z,Xmn[clov],i);
656 GLeft(Zbuff1,W0,Z);
657 //And sum intermediate
658#pragma unroll
659 for(unsigned short c=0;c<nc*nc;c++)
660 F_int[c]+=Zbuff1[c];
661
662 //Now load @f$Z_1=X_{\mu\nu}\left(x+\hat{mu})@f$
663 ind=iu[i+kvol*mu];
664 GetBilinear(Z,Xmn[clov],ind);
665 GRight(Zbuff1,W0,Z);
666 //And sum intermediate
667#pragma unroll
668 for(unsigned short c=0;c<nc*nc;c++){
669 F_int[c]+=Zbuff1[c];
670 //See if this works...
671 F_int[c]*=-I;
672 }
673
674 //Excellent. Now we just need to multiply by the derivative term
675 W0[0]=ut[0][i+kvolHalo*mu]; W0[1]=ut[1][i+kvolHalo*mu];
676 for(unsigned short gen=0;gen<nadj;gen++){
677 W1[0]=W0[0]; W1[1]=W0[1];
678 ByGenLeft(W1,gen);
679 GLeft(Zbuff1,W1,F_int);
680 //Sum of the real part of the trace.
681 float dSdpis=crealf(Zbuff1[0])+crealf(Zbuff1[3]);
682 if(mu<nu)
683 dSdpi[i+kvol*(gen*ndim+mu)] -=akappa*dSdpis/4.0f;
684 else
685 dSdpi[i+kvol*(gen*ndim+mu)] +=akappa*dSdpis/4.0f;
686 }
687 }
688 }
689 for(clov=0;clov<nclov;clov++){
690 free(Xmn[clov].diag); free(Xmn[clov].offd);
691 }
692#endif
693 return;
694}
695
696//Initialisation and freeing
697int Init_clover(Complex **sigval, Complex_f **sigval_f,unsigned short **sigin, float c_sw){
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}};
700 //The sigma matrices are the commutators of the gamma matrices. These are antisymmetric when you swap the indices
701 //0 is sigma_0,1
702 //1 is sigma_0,2
703 //2 is sigma_0,3
704 //3 is sigma_1,2
705 //4 is sigma_1,3
706 //5 is sigma_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}};
708 //Complex __attribute__((aligned(AVX))) sigval_t[6][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
709 //We mutiply by 1/2 and c_sw here since sigval is never used without them.
710#if defined USE_BLAS
711 cblas_zdscal(6*4, 0.5*c_sw, sigval_t, 1);
712#else
713#pragma omp parallel for simd collapse(2) aligned(sigval,sigval_f:AVX)
714 for(int i=0;i<6;i++)
715 for(int j=0;j<4;j++)
716 sigval_t[i][j]*=c_sw*0.5;
717#endif
718
719#ifdef USE_GPU
720 int device = -1;
721 cudaGetDevice(&device);
722
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));
726
727 cudaMemcpy(*sigin,sigin_t,6*4*sizeof(short),cudaMemcpyDefault);
728 cudaMemcpy(*sigval,sigval_t,6*4*sizeof(Complex),cudaMemcpyDefault);
729
730 cuComplex_convert(*sigval_f,*sigval,24,true,dimBlockOne,dimGridOne);
731#else
732 *sigin = (unsigned short *)malloc(6*4*sizeof(short));
733 *sigval=(Complex *)malloc(6*4*sizeof(Complex));
734 *sigval_f=(Complex_f *)malloc(6*4*sizeof(Complex_f));;
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++)
738 *(*sigval_f+i)=(Complex_f)*(*sigval+i);
739#endif
740 return 0;
741}
742inline void Clover_free(Complex_f *clover[nc]){
743 for(unsigned short c=0;c<nc;c++){
744#ifdef USE_GPU
745#ifdef _DEBUG
746 cudaFree(clover[c]);
747#else
748 cudaFreeAsync(clover[c],streams[c]);
749#endif
750#else
751 free(clover[c]);
752#endif
753 }
754}
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.
Definition clover.c:510
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.
Definition cuclover.cu:725
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.
Definition clover.c:437
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.
Definition clover.c:495
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.
Definition cuclover.cu:732
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.
Definition clover.c:528
static void GetBilinear(Complex_f Z[nc *nc], Bilinear_a Xmn, unsigned int ind)
Loads the compacted bilinear form into a complex valued matrix.
Definition clover.c:432
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.
Definition clover.c:534
void cuHbyClover(Complex *phi, Complex *r, Complex *clover[nc], Complex *sigval, const float akappa, unsigned short *sigin, bool dag)
CUDA wrapper for HbyClover.
Definition cuclover.cu:715
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.
Definition cuclover.cu:718
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.
Definition cuclover.cu:721
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...
Definition clover.c:287
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...
Definition clover.c:243
void cuByClover(Complex *phi, Complex *r, Complex *clover[nc], Complex *sigval, const float akappa, unsigned short *sigin, bool dag)
CUDA wrapper for ByClover.
Definition cuclover.cu:712
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...
Definition clover.c:332
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...
Definition clover.c:376
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 .
Definition cuclover.cu:690
void ByGenRight(Complex_f a[nc], const unsigned short gen)
Multiply leaf (or part of one) by generator from right.
Definition clover.c:31
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...
Definition clover.c:70
void Clover_free(Complex_f *clover[nc])
Free's memory used for clover terms and leaves.
Definition clover.c:742
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.
Definition clover.c:135
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.
Definition clover.c:122
int Init_clover(Complex **sigval, Complex_f **sigval_f, unsigned short **sigin, float c_sw)
Initialise values needed for the clover terms.
Definition clover.c:697
void ByGenLeft(Complex_f a[nc], const unsigned short gen)
Multiply leaf (or part of one) by generator from left.
Definition clover.c:9
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.
Definition clover.c:203
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
Definition cusu2hmc.cu:33
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
Definition cusu2hmc.cu:284
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...
Definition sizes.h:279
#define nc
Colours.
Definition sizes.h:182
#define ngorkov
Gor'kov indices.
Definition sizes.h:190
#define nadj
adjacent spatial indices
Definition sizes.h:184
#define kvol
Sublattice volume.
Definition sizes.h:163
#define Complex
Double precision complex number.
Definition sizes.h:64
#define ndirac
Dirac indices.
Definition sizes.h:186
dim3 dimBlockOne
block size of one
Definition cusu2hmc.cu:22
dim3 dimGridOne
Grid size of one.
Definition cusu2hmc.cu:23
#define Complex_f
Single precision complex number.
Definition sizes.h:62
#define ndim
Dimensions.
Definition sizes.h:188
#define kvolHalo
Subvolume + halo size.
Definition sizes.h:234
Structure of arrays for Hermitian bilinear in memory.
Definition clover.h:30
Complex_f * offd
Complex valued off-diagonal terms. We only need to store one of these to get the other in .
Definition clover.h:34
float * diag
Real valued diagonal terms.
Definition clover.h:32
Hermitian bilinear on the local stack.
Definition clover.h:40
float diag[2]
Real valued diagonal terms.
Definition clover.h:42
Complex_f offd
Complex valued off-diagonal terms. We only need to store one of these to get the other in .
Definition clover.h:44
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 I
Define I in double precision using C standard notation.