su2hmc
Loading...
Searching...
No Matches
Molecular dynamics
Collaboration diagram for Molecular dynamics:

Topics

 Clover Force

Functions

int Gauge_Update (const double d, double *pp, Complex *ut[2], Complex_f *ut_f[2])
 Gauge update for the integration step of the HMC.
int Momentum_Update (const double d, const double *dSdpi, double *pp)
 Wrapper for the momentum update during the integration step of the HMC.
int Leapfrog (Complex *ut[2], Complex_f *ut_f[2], Complex *X0, Complex *X1, Complex *Phi, double *dk[2], float *dk_f[2], double *dSdpi, double *pp, unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, const Complex jqq, const float beta, const float akappa, const float c_sw, const int stepl, const float dt, double *ancg, int *itot, const float proby)
 Leapfrog integrator. Each trajectory step takes the form of p->p+dt/2,u->u+dt,p->p+dt/2 In practice this is implemented for the entire trajectory as p->p+dt/2,u->u+dt,p->p+dt,u->u+dt,p->p+dt,...p->p+dt/2,u->u+dt,p->p+dt/2.
int OMF2 (Complex *ut[2], Complex_f *ut_f[2], Complex *X0, Complex *X1, Complex *Phi, double *dk[2], float *dk_f[2], double *dSdpi, double *pp, unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, const Complex jqq, const float beta, const float akappa, const float c_sw, const int stepl, const float dt, double *ancg, int *itot, const float proby)
 OMF second order five step integrator.
int OMF4 (Complex *ut[2], Complex_f *ut_f[2], Complex *X0, Complex *X1, Complex *Phi, double *dk[2], float *dk_f[2], double *dSdpi, double *pp, unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, const Complex jqq, const float beta, const float akappa, const float c_sw, const int stepl, const float dt, double *ancg, int *itot, const float proby)
 OMF fourth order eleven step integrator.
void cuGauge_Update (const double d, double *pp, Complex *ut[2], dim3 dimGrid, dim3 dimBlock)
 CUDA wrapper for the gauge update during the integration step of the HMC.
void Force_s (double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, Complex_f gamval[20], unsigned int *iu, const unsigned short gamin[16], const float akappa, const unsigned short mu)
 Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.
void Force_t (double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, Complex_f gamval[20], float *dk[2], unsigned int *iu, const unsigned short gamin[16], float akappa)
 Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.
int Force (double *dSdpi, const bool iflag, double res1, Complex *X0, Complex *X1, Complex *Phi, Complex *ut[2], Complex_f *ut_f[2], unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, double *dk[2], float *dk_f[2], const Complex_f jqq, const float akappa, const float beta, const float c_sw, double *ancg)
 Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.
int Gauge_force (double *dSdpi, Complex_f *ut[2], unsigned int *iu, unsigned int *id, float beta)
 Calculates the gauge force due to the Wilson Action at each intermediate time.
int Congradq (int na, double res, Complex *X1, Complex *r, Complex *ud[2], Complex_f *ut[2], Complex_f *clover_f[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, double *dk[2], float *dk_f[2], Complex_f jqq, float akappa, float c_sw, int *itercg)
 Matrix Inversion via Conjugate Gradient (up/down flavour partitioning). Solves \((M^\dagger)Mx=\Phi\) Implements up/down partitioning The matrix multiplication step is done at mixed precision, while the update is done at double.
int Congradp (int na, double res, Complex *Phi, Complex *xi, Complex *ud[2], Complex_f *ut[2], Complex_f *clover_f[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, double *dk[2], float *dk_f[2], Complex_f jqq, float akappa, float c_sw, int *itercg)
 Matrix Inversion via Conjugate Gradient (no up/down flavour partitioning). Solves \((M^\dagger)Mx=\Phi\) The matrix multiplication step is done at single precision, while the update is done at double.
void cuGauge_force (Complex_f *ut[2], double *dSdpi, float beta, unsigned int *iu, unsigned int *id, dim3 dimGrid, dim3 dimBlock)
 Calculate the gauge contribution to the force.
void cuForce (double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, Complex_f gamval[20], float *dk[2], unsigned int *iu, const unsigned short gamin[16], float akappa, dim3 dimGrid, dim3 dimBlock)
 Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.
__global__ void Kernels::Plus_staple (const int mu, const int nu, unsigned int *iu, Complex_f *Sigma11, Complex_f *Sigma12, Complex_f *u11t, Complex_f *u12t)
 Calculates the staple in the positive \(\mu\) direction.
__global__ void Kernels::Minus_staple (const int mu, const int nu, unsigned int *iu, unsigned int *id, Complex_f *Sigma11, Complex_f *Sigma12, Complex_f *u11sh, Complex_f *u12sh, Complex_f *u11t, Complex_f *u12t)
 Calculates the staple in the negative \(\mu\) direction.
__global__ void Kernels::cuGaugeForce (int mu, Complex_f *Sigma11, Complex_f *Sigma12, double *dSdpi, Complex_f *u11t, Complex_f *u12t, float beta)
 Calculates the gauge force due to the Wilson Action at each intermediate time.
__global__ void Kernels::cuForce_s (double *dSdpi, Complex_f *u11t, Complex_f *u12t, Complex_f *X1, Complex_f *X2, Complex_f gamval[20], unsigned int *iu, const unsigned short gamin[16], float akappa, const unsigned short mu)
 Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.
__global__ void Kernels::cuForce_t (double *dSdpi, Complex_f *u11t, Complex_f *u12t, Complex_f *X1, Complex_f *X2, Complex_f gamval[20], float *dk4m, float *dk4p, unsigned int *iu, const unsigned short gamin[16], float akappa)
 Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.
__global__ void Kernels::cuGauge_Update (const double d, double *pp, Complex *u11t, Complex *u12t, int mu)
 Gauge update for the integration step of the HMC.

Detailed Description

Function Documentation

◆ Congradp()

int Congradp ( int na,
double res,
Complex * Phi,
Complex * xi,
Complex * ud[2],
Complex_f * ut[2],
Complex_f * clover_f[nc],
unsigned int * iu,
unsigned int * id,
Complex gamval[20],
Complex_f gamval_f[20],
const unsigned short gamin[16],
Complex * sigval,
Complex_f * sigval_f,
unsigned short * sigin,
double * dk[2],
float * dk_f[2],
Complex_f jqq,
float akappa,
float c_sw,
int * itercg )

Matrix Inversion via Conjugate Gradient (no up/down flavour partitioning). Solves \((M^\dagger)Mx=\Phi\) The matrix multiplication step is done at single precision, while the update is done at double.

Parameters
[in]naFlavour index
[in]resLimit for conjugate gradient
[in]PhiPseudofermion field.
[in,out]xiReturned as \((M^\dagger M)^{-1} \Phi\)
[in]ut,udDouble/float Gauge fields
[in]iu,idUpper/Lower halo indices
[in]gamval,gamval_fdouble float Gamma matrices rescaled by kappa
[in]gaminDirac indices
[in]clover_fArray of clover fields
[in]sigval,sigval_fDouble/float Commutators of gamma matrices scaled by \(\frac{c_\text{SW}}{2}\)
[in]siginWhat element of the spinor is multiplied by row idirac each sigma matrix?
[in]dk,dk_fDouble/float \(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\)
[in]jqqDiquark source
[in]akappaHopping Parameter
[in]c_swClover coefficient.
[in]itercgCounts the iterations of the conjugate gradient
Returns
0 on success, integer error code otherwise
Postcondition
Contents of Phi overwritten

TODO: Set this as an argument How much does the residue have to shrink by before we do a double precision update

\(x2 = (M^\dagger M)p \)

\(\alpha_d= p* (M^\dagger M)p\)

\(alpha=\frac{\alpha_n} {\alpha_d}=\frac{r\cdot r}{p(M^\dagger M)p}\)

\(x+\alpha p\)

Definition at line 735 of file congrad.c.

738 {
739 const char funcname[] = "Congradp";
740 //Return value
741 int ret_val=0;
742 const double resid = res*res;
743#ifdef _DEBUGCG
744#warning "CG Debugging"
745 char *endline = "\n";
746#else
747 char *endline = "\r";
748#endif
749
752 const float d_prec=1.0f/128.0f;
753
754 //These were evaluated only in the first loop of niterx so we'll just do it outside of the loop.
755 alignas(8) double alphan=1.0;
756 //These alpha and beta terms should be double, but that causes issues with BLAS. Instead we declare
757 //them Complex and work with the real part (especially for \alpha_d)
758 //Give initial values Will be overwritten if niterx>0
759 alignas(8) double betad = 1.0; alignas(8) Complex_f alphad=0; alignas(16)Complex alpha = 1; //Alignment needed for cuBLAS
760
761 Complex_f *p_f, *r_f, *x1_f, *x2_f, *xi_f;
762 Complex *p, *r, *x1, *x2, *clover[nc];
763 P_allocate_f(&p_f,&r_f,&x1_f,&x2_f,&xi_f);
764 P_allocate(&p, &r, &x1, &x2,clover);
765
766 ComplexConvert(r_f,Phi+na*kferm,kferm,true,1);
767 ComplexConvert(xi_f,xi,kferm,true,1);
768 if(c_sw){
769 ComplexConvert(clover_f[0],clover[0],6*kvol,false,1);
770 ComplexConvert(clover_f[1],clover[1],6*kvol,false,1);
771 }
772 //Instead of copying element-wise in a loop, use memcpy.
773#ifdef USE_GPU
774 //Get r in single precision
775 //Get xi in single precision
776 cudaMemcpy(r,Phi+na*kferm,kferm*sizeof(Complex),cudaMemcpyDefault);
777#if (nproc>1)//strided memcpy
778 for(unsigned short j=0;j<nc*ngorkov;j++){
779 cudaMemcpyAsync(p+j*kvolHalo,xi+j*kvol,kvol*sizeof(Complex),cudaMemcpyDefault,streams[j]);
780 cudaMemcpyAsync(p_f+j*kvolHalo,xi_f+j*kvol,kvol*sizeof(Complex_f),cudaMemcpyDefault,streams[j]);
781 }
782#else
783 cudaMemcpyAsync(p,xi,kferm*sizeof(Complex),cudaMemcpyDefault,streams[0]);
784 cudaMemcpyAsync(p_f,xi_f,kferm*sizeof(Complex_f),cudaMemcpyDefault,streams[1]);
785#endif
787#else
788 memcpy(r,Phi+na*kferm,kferm*sizeof(Complex));
789 //These strided loops for MPI halos are a total pain in the arse...
790 for(unsigned short j=0;j<nc*ngorkov;j++){
791 memcpy(p+j*kvolHalo,xi+j*kvol,kvol*sizeof(Complex));
792 memcpy(p_f+j*kvolHalo,xi_f+j*kvol,kvol*sizeof(Complex_f));
793 }
794#endif
795
796 double betan=1;double beta_max=FLT_MAX; bool do_dp=true;
797 for((*itercg)=0; (*itercg)<niterc; (*itercg)++){
798 //Don't overwrite on first run.
799 if(do_dp){
800#ifdef _DEBUGCG
801 if(!rank)
802 printf("Going to double precision on iteration %d. %sbetan %e\talpha %e. %s",
803 *itercg,endline,betan,creal(alpha),endline);
804#elifdef _DEBUG
805 if(!rank)
806 printf("\nGoing to double precision on iteration %d. %sbetan %e\talpha %e.\n",
807 *itercg,endline,betan,creal(alpha));
808#endif
809 ComplexConvert(r_f,r,kferm,false,1);
810 //TODO: Banking on converting the halo too being faster than multiple launches
811 ComplexConvert(p_f,p,kvol,false,nc*ngorkov);
812#ifdef USE_GPU
813 //Update the residue vector, but not on the first call.
814 if(*itercg)
815 cuMixed_Sumto((double *)xi,(float *)xi_f,2*kferm,dimGrid,dimBlock);
816 //Bring everything into double precision
817 //Reset xi_f to zero.
819 cudaMemsetAsync(xi_f,0,kferm*sizeof(Complex_f),streams[4]);
820#else
821 //Update the residue vector, but not on the first call.
822 if(*itercg)
823#pragma omp parallel for simd aligned(xi,xi_f:AVX)
824 for(unsigned int i=0;i<kferm;i++)
825 xi[i]+=(Complex)xi_f[i];
826 memset(xi_f,0,kferm*sizeof(Complex_f));
827#endif
829 //No need to synchronise here. The memcpy in Dslash is blocking
830 Dslash(x1,p,ud,iu,id,gamval,gamin,dk,jqq,akappa);
831 if(c_sw)
832 ByClover(x1,p,clover,sigval,akappa,sigin,false);
833 Dslashd(x2,x1,ud,iu,id,gamval,gamin,dk,jqq,akappa);
834 if(c_sw)
835 ByClover(x2,x1,clover,sigval,akappa,sigin,true);
836#ifdef USE_GPU
838#endif
839
841 if(*itercg){
842 alpha=0;
843#ifdef USE_GPU
844#if (nproc>1)//Strided
845 for(unsigned short j=0;j<nc*ngorkov;j++){
846 alignas(16) Complex alpha_t=0;
847 cublasZdotc(cublas_handle,kvol,(cuDoubleComplex *)p+j*kvolHalo,1,(cuDoubleComplex *)x2+j*kvol,1,(cuDoubleComplex *)&alpha_t);
848 alpha+=alpha_t
849 }
850#else
851 cublasZdotc(cublas_handle,kferm,(cuDoubleComplex *)p,1,(cuDoubleComplex *)x2,1,(cuDoubleComplex *)&alpha);
852#endif
853#elif defined USE_BLAS
854 for(unsigned short j=0;j<nc*ngorkov;j++){
855 Complex alpha_t=0;
856 cblas_zdotc_sub(kvol, p+j*kvolHalo, 1, x2+j*kvol, 1, &alpha_t);
857 alpha+=alpha_t;
858 }
859#else
860#pragma omp parallel for simd collapse(2) aligned(p,x2:AVX) reduction(+:alpha)
861 for(unsigned short j=0;j<nc*ngorkov;j++)
862 for(unsigned int i=0; i<kvol; i++)
863 alpha+=conj(p[i+j*kvolHalo])*x2[i+j*kvol];
864#endif
865 //For now I'll cast it into a float for the reduction. Each rank only sends and writes
866 //to the real part so this is fine
867#if (nproc>1)
868 Par_dsum((double *)&alpha);
869#endif
871 alpha=alphan/creal(alpha);
873#ifdef USE_GPU
874#if (nproc>1)
875 for(unsigned short j=0;j<nc*ngorkov;j++)
876 cublasZaxpy(cublas_handle,kvol,(cuDoubleComplex *)&alpha,(cuDoubleComplex *)p+j*kvolHalo,1,(cuDoubleComplex *)xi+j*kvol,1);
877#else
878 cublasZaxpy(cublas_handle,kferm,(cuDoubleComplex *)&alpha,(cuDoubleComplex *)p,1,(cuDoubleComplex *)xi,1);
879#endif
880#elif defined USE_BLAS
881 for(unsigned short j=0;j<nc*ngorkov;j++)
882 cblas_zaxpy(kvol, &alpha, p+j*kvolHalo, 1, xi+j*kvol, 1);
883#else
884#pragma omp parallel for simd collapse(2) aligned(p,xi:AVX)
885 for(unsigned short j=0;j<nc*ngorkov;j++)
886 for(unsigned int i=0; i<kvol; i++)
887 xi[i+j*kvol]+=alpha*p[i+j*kvolHalo];
888#endif
889 }
890
891#ifdef USE_GPU
892 Complex alpha_m=(Complex)(-alpha);
893 cublasZaxpy(cublas_handle, kferm,(cuDoubleComplex *)&alpha_m,(cuDoubleComplex *)x2,1,(cuDoubleComplex *)r,1);
894 double betan_d;
895 cublasDznrm2(cublas_handle,kferm,(cuDoubleComplex *)r,1,&betan_d);
896 betan=betan_d*betan_d;
897#elif defined USE_BLAS
898 const Complex alpha_m = (Complex)(-alpha);
899 cblas_zaxpy(kferm, &alpha_m, x2, 1, r, 1);
900 //Undo the negation for the BLAS routine
901 double betan_d = cblas_dznrm2(kferm, r,1);
902 //Gotta square it to "undo" the norm
903 betan = betan_d*betan_d;
904#else
905 betan=0;
906#pragma omp parallel for simd aligned(r,x2:AVX) reduction(+:betan)
907 for(unsigned int i=0; i<kferm; i++){
908 r[i]-=alpha*x2[i];
909 betan += conj(r[i])*r[i];
910 }
911 double betan_d=sqrt(betan);
912#endif
913 //And... reduce.
914#if (nproc>1)
915 Par_dsum(&betan);
916#endif
917 betan_d=sqrt(betan);
918 //Update beta_max. Mandatory for double precision.
919 beta_max=betan_d;
920#ifdef _DEBUG
921 if(! rank) printf("DP Iter(CG)=%i\tbeta_n=%e\talpha=%e\n", *itercg, betan, creal(alpha));
922 fflush(stdout);
923#endif
924 alignas(16) const Complex beta = (*itercg) ? betan/betad : 0;
925 betad=betan; alphan=betan;
926#ifdef USE_GPU
927 alpha_m=1;
928#if (nproc>1)
929 for(unsigned short j=0;j<nc*ngorkov;j++){
930 cublasZdscal(cublas_handle,kvol,(double *)&beta,(cuDoubleComplex *)p+j*kvolHalo,1);
931 cublasZaxpy(cublas_handle,kvol,(cuDoubleComplex *)&alpha_m,(cuDoubleComplex *)r+j*kvol,1,(cuDoubleComplex *)p+j*kvolHalo,1);
932 }
933#else
934 cublasZdscal(cublas_handle,kferm,(double *)&beta,(cuDoubleComplex *)p,1);
935 cublasZaxpy(cublas_handle,kferm,(cuDoubleComplex *)&alpha_m,(cuDoubleComplex *)r,1,(cuDoubleComplex *)p,1);
936#endif
937#elif (defined __USE_MKL__||defined OPENBLAS||defined AMD_BLAS)
938 const Complex a = 1.0;
939 //There is cblas_? axpby in the MKL and AMD though, set a = 1 and b = \beta.
940 //If we get a small enough \beta_n before hitting the iteration cap we break
941 for(unsigned short j=0;j<nc*ngorkov;j++)
942 cblas_zaxpby(kvol, &a, r+j*kvol, 1, &beta, p+j*kvolHalo, 1);
943#elif defined USE_BLAS
944 const Complex a = 1.0;
945 for(unsigned short j=0;j<nc*ngorkov;j++){
946 cblas_zscal(kvol,&beta,p+j*kvolHalo,1);
947 cblas_zaxpy(kvol,&a,r+j*kvol,1,p+j*kvolHalo,1);
948 }
949#else
950#pragma omp parallel for simd collapse(2) aligned(r,p:AVX)
951 for(unsigned short j=0;j<nc*ngorkov;j++)
952 for(unsigned int i=0; i<kvol; i++)
953 p[i+j*kvolHalo]=r[i+j*kvol]+beta*p[i+j*kvolHalo];
954#endif
955 ComplexConvert(p_f,p,kvol,true,nc*ngorkov);
956 ComplexConvert(r_f,r,kferm,true,1);
957#ifdef _DEBUGCG
958 if(! rank) printf("Double precision. Iter(CG)=%i\tbeta_n=%e\talpha=%e\n", *itercg, betan, creal(alpha));
959 fflush(stdout);
960#endif
961 if(betan<resid){
962 (*itercg)++;
963#ifdef _DEBUG
964 if(!rank) printf("\nIter(CG)=%i\tResidue: %e\tTolerance: %e\n", *itercg, betan, resid);
965#endif
966 ret_val=0; break;
967 }
968 else
969 do_dp=false;
970 }
971 else{
972 //x2=(M^\dagger)x1=(M^\dagger)Mp
973 Dslash_f(x1_f,p_f,ut,iu,id,gamval_f,gamin,dk_f,jqq,akappa);
974 if(c_sw)
975 ByClover_f(x1_f,p_f,clover_f,sigval_f,akappa,sigin,false);
976 Dslashd_f(x2_f,x1_f,ut,iu,id,gamval_f,gamin,dk_f,jqq,akappa);
977 if(c_sw)
978 ByClover_f(x2_f,x1_f,clover_f,sigval_f,akappa,sigin,true);
979#ifdef USE_GPU
981#endif
982 //We can't evaluate \alpha on the first niterx because we need to get \beta_n.
983 if(*itercg){
984 //x*.x
985 alphad=0;
986#ifdef USE_GPU
987#if(nproc>1)//strided
988 for(unsigned short j=0;j<nc*ngorkov;j++){
989 alignas(8) Complex_f alpha_t=0;
990 cublasCdotc(cublas_handle,kvol,(cuComplex *)p_f+j*kvolHalo,1,(cuComplex *)x2_f+j*kvol,1,(cuComplex *)&alpha_t);
991 alphad+=alpha_t;
992 }
993#else
994 cublasCdotc(cublas_handle,kferm,(cuComplex *)p_f,1,(cuComplex *)x2_f,1,(cuComplex *)&alphad);
995#endif
996#elifdef USE_BLAS
997 for(unsigned short j=0;j<nc*ngorkov;j++){
998 alignas(8) Complex_f alpha_t=0;
999 cblas_cdotc_sub(kvol,p_f+j*kvolHalo,1,x2_f+j*kvol,1,&alpha_t);
1000 alphad+=alpha_t;
1001 }
1002#else
1003#pragma omp parallel for simd collapse(2) aligned(p_f,x2_f:AVX) reduction(+:alphad)
1004 for(unsigned short j=0;j<nc*ngorkov;j++)
1005 for(unsigned int i = 0; i<kvol; i++)
1006 alphad+=conj(p_f[i+j*kvolHalo])*x2_f[i+j*kvol];
1007#endif
1008#if (nproc>1)
1009 Par_fsum((float *)&alphad);
1010#endif
1011 //alpha=(r.r)/p(M^\dagger)Mp
1012 alpha=alphan/creal(alphad);
1013 // Complex_f alpha_f = (Complex_f)alpha;
1014 //x+\alpha p
1015#ifdef USE_BLAS
1016 alignas(8) Complex_f alpha_f=(float)alpha;
1017#ifdef USE_GPU
1018#if (nproc>1) //strided
1019 for(unsigned short j=0;j<nc*ngorkov;j++)
1020 cublasCaxpy(cublas_handle,kvol,(cuComplex*) &alpha_f,(cuComplex*) p_f+j*kvolHalo,1,(cuComplex*) xi_f+j*kvol,1);
1021#else
1022 cublasCaxpy(cublas_handle,kferm,(cuComplex*) &alpha_f,(cuComplex*) p_f,1,(cuComplex*) xi_f,1);
1023#endif
1024#else
1025 for(unsigned short j=0;j<nc*ngorkov;j++)
1026 cblas_caxpy(kvol, (Complex_f*)&alpha_f,(Complex_f*)p_f+j*kvolHalo, 1, (Complex_f*)xi_f+j*kvol, 1);
1027#endif
1028#else
1029#pragma omp parallel for simd collapse(2) aligned(xi_f,p_f:AVX)
1030 for(unsigned short j=0;j<nc*ngorkov;j++)
1031 for(unsigned int i = 0; i<kvol; i++)
1032 xi_f[i+j*kvol]+=alpha*p_f[i+j*kvolHalo];
1033#endif
1034 }
1035
1036 //r=\alpha(M^\dagger)Mp and \beta_n=r*.r
1037 alignas(8) float betan_f=0;
1038#if defined USE_BLAS
1039 alignas(16) Complex_f alpha_m=(Complex_f)(-alpha);
1040#ifdef USE_GPU
1041 cublasCaxpy(cublas_handle,kferm, (cuComplex *)&alpha_m,(cuComplex *) x2_f, 1,(cuComplex *) r_f, 1);
1042 //cudaDeviceSynchronise();
1043 //r*.r
1044 cublasScnrm2(cublas_handle,kferm,(cuComplex *) r_f,1,(float *)&betan_f);
1045#else
1046 cblas_caxpy(kferm,(Complex_f*) &alpha_m,(Complex_f*) x2_f, 1,(Complex_f*) r_f, 1);
1047 //r*.r
1048 betan_f = cblas_scnrm2(kferm, (Complex_f*)r_f,1);
1049#endif
1050 //Gotta square it to "undo" the norm
1051 betan=betan_f*betan_f;
1052#else
1053 //Just like Congradq, this loop could be unrolled but will need a reduction to deal with the betan
1054 //addition.
1055 betan = 0;
1056 //If we get a small enough \beta_n before hitting the iteration cap we break
1057#pragma omp parallel for simd aligned(x2_f,r_f:AVX) reduction(+:betan)
1058 for(unsigned int i = 0; i<kferm;i++){
1059 r_f[i]-=alpha*x2_f[i];
1060 betan+=conj(r_f[i])*r_f[i];
1061 }
1062 betan_f=sqrt(betan);
1063#endif
1064 //This is basically just congradq at the end. Check there for comments
1065#if (nproc>1)
1066 Par_dsum(&betan);
1067#endif
1068 //Update beta_max if needed. On paper congrad is monotonically decreasing
1069 betan_f=sqrt(betan);
1070 beta_max = (betan_f>beta_max) ?betan_f : beta_max;
1071#ifdef _DEBUG
1072 if(!rank) printf("Iter (CG) = %i beta_n= %e alpha= %e%s", *itercg, betan, creal(alpha),endline);
1073#endif
1074 if(betan_f<beta_max*d_prec){
1075#ifdef _DEBUG
1076 if(!rank)
1077 printf("Residue %e is less than %e times %e. %s",betan_f,d_prec,beta_max,endline);
1078#endif
1079 do_dp=true;
1080 }
1081 else if(betan<resid){
1082 //Started counting from zero so add one to make it accurate
1083 (*itercg)++;
1084#ifdef _DEBUG
1085 if(!rank) printf("\nIter (CG) = %i resid = %e toler = %e\n", *itercg, betan, resid);
1086#endif
1087 //Final iteration should be in double precision.
1088 do_dp=true;
1089 }
1090 else if(*itercg==niterc-1){
1091 if(!rank) fprintf(stderr, "Warning %i in %s: Exceeded iteration limit %i beta_n=%e\n",
1092 ITERLIM, funcname, niterc, betan);
1093 ret_val=ITERLIM; break;
1094 }
1095 //Note that beta below is not the global beta and scoping is used to avoid conflict between them
1096 alignas(8) Complex beta = (*itercg) ? betan/betad : 0;
1097 betad=betan; alphan=betan;
1098 //BLAS for p=r+\betap doesn't exist in standard BLAS. This is NOT an axpy case as we're multiplying y by
1099 //\beta instead of x.
1100 //There is cblas_zaxpby in the MKL though, set a = 1 and b = \beta.
1101#ifdef USE_BLAS
1102 alignas(8) Complex_f beta_f = (Complex_f)beta;
1103 alignas(8) Complex_f a = 1.0;
1104#ifdef USE_GPU
1105#if (nproc>1) //strided
1106 for(unsigned short j=0;j<nc*ngorkov;j++){
1107 cublasCscal(cublas_handle,kvol,(cuComplex *)&beta_f,(cuComplex *)p_f+j*kvolHalo,1);
1108 cublasCaxpy(cublas_handle,kvol,(cuComplex *)&a,(cuComplex *)r_f+j*kvol,1,(cuComplex *)p_f+j*kvolHalo,1);
1109 }
1110#else
1111 cublasCscal(cublas_handle,kferm,(cuComplex *)&beta_f,(cuComplex *)p_f,1);
1112 cublasCaxpy(cublas_handle,kferm,(cuComplex *)&a,(cuComplex *)r_f,1,(cuComplex *)p_f,1);
1113#endif
1115#elif (defined __USE_MKL__||defined OPENBLAS||defined AMD_BLAS)
1116 for(unsigned short j=0;j<nc*ngorkov;j++)
1117 cblas_caxpby(kvol, &a, r_f+j*kvol, 1, &beta_f, p_f+j*kvolHalo, 1);
1118#else
1119 for(unsigned short j=0;j<nc*ngorkov;j++){
1120 cblas_cscal(kvol,&beta_f,p_f+j*kvolHalo,1);
1121 cblas_caxpy(kvol,&a,r_f+j*kvol,1,p_f+j*kvolHalo,1);
1122 }
1123#endif
1124#else
1125#pragma omp parallel for simd aligned(r_f,p_f:AVX)
1126 for(unsigned short j=0;j<nc*ngorkov;j++)
1127 for(unsigned int i=0; i<kvol; i++)
1128 p_f[i+j*kvolHalo]=r_f[i+j*kvol]+beta*p_f[i+j*kvolHalo];
1129#endif
1130 }
1131 }
1132#ifdef USE_GPU
1134#endif
1135 P_free_f(&p_f,&r_f,&x1_f,&x2_f,&xi_f);
1136 P_free(&p,&r,&x1,&x2,clover);
1137 return ret_val;
1138}
#define ITERLIM
Exceeded max number of iterations.
Definition errorcodes.h:137
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 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:336
int Dslash_f(Complex_f *phi, Complex_f *r, Complex_f *ut[nc], unsigned int *iu, unsigned int *id, Complex_f gamval[20], const unsigned short gamin[16], float *dk[nc], Complex_f jqq, float akappa)
Evaluates in single precision.
Definition matrices.c:425
int Dslashd_f(Complex_f *phi, Complex_f *r, Complex_f *ut[nc], unsigned int *iu, unsigned int *id, Complex_f gamval[20], const unsigned short gamin[16], float *dk[nc], Complex_f jqq, float akappa)
Evaluates in single precision.
Definition matrices.c:544
int Dslashd(Complex *phi, Complex *r, Complex *ut[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], const unsigned short gamin[16], double *dk[nc], Complex_f jqq, float akappa)
Evaluates in double precision.
Definition matrices.c:135
int Dslash(Complex *phi, Complex *r, Complex *ut[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], const unsigned short gamin[16], double *dk[nc], Complex_f jqq, float akappa)
Evaluates in double precision.
Definition matrices.c:16
void P_allocate(Complex **p, Complex **r, Complex **x1, Complex **x2, Complex *clover[2])
Allocates double precision memory needed for Congradp. Just to improve readability Note that since C ...
Definition congrad.c:140
void P_free(Complex **p, Complex **r, Complex **x1, Complex **x2, Complex *clover[2])
Frees memory needed for Congradp. Just to improve readability Note that since C does not modify it's ...
Definition congrad.c:263
void P_allocate_f(Complex_f **p_f, Complex_f **r_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **xi_f)
Allocates memory needed for Congradp. Just to improve readability Note that since C does not modify i...
Definition congrad.c:103
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
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
Definition cusu2hmc.cu:33
void cuMixed_Sumto(double *d, float *f, const unsigned int n, const dim3 dimGrid, const dim3 dimBlock)
Add a single to a double value, and save the output in the double array For complex valued arrays,...
void P_free_f(Complex_f **p_f, Complex_f **r_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **xi_f)
Frees memory needed for Congradp. Just to improve readability Note that since C does not modify it's ...
Definition congrad.c:243
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_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 nc
Colours.
Definition sizes.h:182
#define ngorkov
Gor'kov indices.
Definition sizes.h:190
#define niterc
Hard limit for runaway trajectories in Conjugate gradient.
Definition sizes.h:172
#define kvol
Sublattice volume.
Definition sizes.h:163
#define Complex
Double precision complex number.
Definition sizes.h:64
#define kferm
sublattice size including Gor'kov indices
Definition sizes.h:195
#define cudaDeviceSynchronise()
Get rid of that bastardised yankee English.
Definition sizes.h:53
cublasHandle_t cublas_handle
Handle for cuBLAS.
Definition main.c:47
#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 kvolHalo
Subvolume + halo size.
Definition sizes.h:234
dim3 dimBlock
Default block size. Usually 128.
Definition cusu2hmc.cu:25
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.

References ByClover(), ByClover_f(), Complex, Complex_f, ComplexConvert(), conj(), creal, cublas_handle, cudaDeviceSynchronise, cuMixed_Sumto(), dimBlock, dimGrid, Dslash(), Dslash_f(), Dslashd(), Dslashd_f(), ITERLIM, kferm, kvol, kvolHalo, nc, ngorkov, niterc, P_allocate(), P_allocate_f(), P_free(), P_free_f(), Par_dsum(), Par_fsum(), rank, and streams.

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

◆ Congradq()

int Congradq ( int na,
double res,
Complex * X1,
Complex * r,
Complex * ud[2],
Complex_f * ut[2],
Complex_f * clover_f[nc],
unsigned int * iu,
unsigned int * id,
Complex gamval[20],
Complex_f gamval_f[20],
const unsigned short gamin[16],
Complex * sigval,
Complex_f * sigval_f,
unsigned short * sigin,
double * dk[2],
float * dk_f[2],
Complex_f jqq,
float akappa,
float c_sw,
int * itercg )

Matrix Inversion via Conjugate Gradient (up/down flavour partitioning). Solves \((M^\dagger)Mx=\Phi\) Implements up/down partitioning The matrix multiplication step is done at mixed precision, while the update is done at double.

Parameters
[in]naFlavour index
[in]resLimit for conjugate gradient
[in,out]X1Pseudofermion field \(\Phi\) initially, returned as \((M^\dagger M)^{-1} \Phi\)
[in]rPartition of \(\Phi\) being used. Gets recycled as the residual vector
[in]ud,utDouble/float Trial colour fields
[in]iu,idUpper/lower halo indices
[in]gamval,gamval_fDouble/float gamma matrices rescaled by kappa
[in]gaminWhat element of the spinor is multiplied by row idirac each gamma matrix?
[in]clover_fArray of clover fields
[in]sigval,sigval_fCommutators of gamma matrices scaled by \(\frac{c_\text{SW}}{2}\)
[in]siginWhat element of the spinor is multiplied by row idirac each sigma matrix?
[in]dk,dk_f\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\)
[in]jqqDiquark source
[in]akappaHopping Parameter
[in]c_swClover coefficient. If non-zero calculate the clover contribution
[in]itercgCounts the iterations of the conjugate gradient
Returns
0 on success, integer error code otherwise
Postcondition
Contents of X1 and r overwritten

TODO: Set this as an argument How much does the residue have to shrink by before we do a double precision update

The \(\kappa^2\) factor is needed to normalise the fields correctly \(j_{qq}\) is the diquark condensate and is global scope.

The alpha and beta terms should be double, but that causes issues with BLAS pointers. Instead we declare them complex and work with the real part (especially for \(\alpha_d\)) Give initial values Will be overwritten if niterx>0

\(x2 = (M^\dagger M)p \)

\(\alpha_d= p* (M^\dagger M+c_\text{SW} \sum\limits_{\mu\ne\nu}\frac{1}{2}\sigma_{\mu\nu}F_{\mu\nu}+J^2)p\)

\(\alpha=\frac{\alpha_n}{\alpha_d}=\frac{r\cdot r}{p(M^\dagger M+c_\text{SW} \sum\limits_{\mu\ne\nu}\frac{1}{2}\sigma_{\mu\nu}F_{\mu\nu}+J^2)p}\)

\(x+\alpha p\)

\(x2 = (M^\dagger M)p \)

\(x2 = (M^\dagger M+J^2)p\)

First iteration \( \vec{r}_0=\vec{p}_0\)
\(\alpha_d= p* (M^\dagger M+c_\text{SW} \sum\limits_{\mu\ne\nu}\frac{1}{2}\sigma_{\mu\nu}F_{\mu\nu}+J^2)p\)

\(\alpha=\frac{\alpha_n}{\alpha_d}=\frac{r\cdot r}{p(M^\dagger M+c_\text{SW} \sum\limits_{\mu\ne\nu}\frac{1}{2}\sigma_{\mu\nu}F_{\mu\nu}+J^2)p}\)

\(x+\alpha p\)

\(r_{n+1} = r_n-\alpha(M^\dagger M)p_n\) and \(\beta_n=r^\dagger r\)

Definition at line 278 of file congrad.c.

281 {
282 const char funcname[] = "Congradq";
283 int ret_val=0;
284 const double resid = res*res;
285#ifdef _DEBUGCG
286#warning "CG Debugging"
287 char *endline = "\n";
288#else
289 char *endline = "\r";
290#endif
291
294 const float d_prec=1.0f/128.0f;
297 const Complex_f fac_f = conj(jqq)*jqq*akappa*akappa;
298 //These were evaluated only in the first loop of niterx so we'll just do it outside of the loop.
299 //n suffix is numerator, d is denominator
300 alignas(16) double alphan=1;
304 //Alignment needed for cuBLAS
305 alignas(16) double betad = 1.0; alignas(8) Complex_f alphad=0; alignas(16) Complex alpha = 1;
306 //Because we're dealing with flattened arrays here we can call cblas safely without the halo
307
308 Complex_f *p_f, *x1_f, *x2_f, *r_f, *X1_f;
309 Complex *p, *x1, *x2, *clover[2];
310 Q_allocate_f(&p_f,&x1_f,&x2_f,&r_f,&X1_f);
311 Q_allocate(&p,&x1,&x2,clover);
312
313 //Instead of copying element-wise in a loop, use memcpy.
314 //Get X1 in single precision
315 //Since X1 has a halo and X1_f does not we have to do this manually
316#if (nproc>1)
317 for(unsigned short j=0;j<nc*ndirac;j++)
318 ComplexConvert(X1_f+j*kvol,X1+j*kvolHalo,kvol,true,1);
319#else
320 ComplexConvert(X1_f,X1,kferm2,true,1);
321#endif
322 ComplexConvert(r_f,r,kferm2,true,1);
323 //And clover in double
324 if(c_sw){
325 ComplexConvert(clover_f[0],clover[0],6*kvol,false,1);
326 ComplexConvert(clover_f[1],clover[1],6*kvol,false,1);
327 }
328#ifdef USE_GPU
329 //Ensure conversion is done
331 //Needs to be strided
332#if (nproc>1)
333 for(unsigned int j=0;j<nc*ndirac;j++)
334 cudaMemcpyAsync(p_f+j*kvolHalo, X1_f+j*kvol, kvol*sizeof(Complex_f),cudaMemcpyDefault,streams[j]);
336#else
337 cudaMemcpy(p_f, X1_f, kferm2*sizeof(Complex_f),cudaMemcpyDefault);
338#endif
339#else
340#pragma omp parallel for simd aligned(X1_f,r_f,X1,r:AVX)
341 for(unsigned int j=0;j<nc*ndirac;j++)
342 memcpy(p_f+j*kvolHalo, X1_f+j*kvol, kvol*sizeof(Complex_f));
343#endif
344
345 alignas(16) double betan=1;double beta_max=FLT_MAX; bool do_dp=true;
346 for(*itercg=0; *itercg<niterc; (*itercg)++){
347 if(do_dp){
348#ifdef _DEBUGCG
349 if(!rank)
350 printf("Going to double precision on iteration %d. betan %e\talpha %e.\n",
351 *itercg,betan,creal(alpha));
352#elifdef _DEBUG
353 if(!rank)
354 printf("\nGoing to double precision on iteration %d. betan %e\talpha %e.\n",
355 *itercg,betan,creal(alpha));
356#endif
357 ComplexConvert(r_f,r,kferm2,false,1);
358 ComplexConvert(p_f,p,kvol,false,nc*ndirac);
359#ifdef USE_GPU
360 //Update the residue vector, but not on the first call.
361 //TODO: Check for multi-gpu. I fear this will get messy
362 if(*itercg)
363 cuMixed_Sumto((double *)X1,(float *)X1_f,2*kferm2,dimGrid,dimBlock);
364 //Bring everything into double precision
365 //Reset X1_f to zero.
366 cudaMemset(X1_f,0,kferm2*sizeof(Complex_f));
367#else
368 //Update the residue vector, but not on the first call.
369 if(*itercg)
370#pragma omp parallel for simd collapse(2) aligned(X1,X1_f:AVX)
371 for(unsigned short j=0;j<nc*ndirac;j++)
372 for(unsigned int i=0;i<kvol;i++){
373 X1[i+j*kvolHalo]+=(Complex)X1_f[i+j*kvol];
374 }
375 memset(X1_f,0,kferm2*sizeof(Complex_f));
376#endif
378 //No need to synchronise here. The memcpy in Hdslash is blocking
379 Hdslash(x1,p,ud,iu,id,gamval,gamin,dk,akappa);
380 //Clover contribution
381 if(c_sw)
382 HbyClover(x1,p,clover,sigval,akappa,sigin,false);
383 Hdslashd(x2,x1,ud,iu,id,gamval,gamin,dk,akappa);
384 //Clover contribution
385 if(c_sw)
386 HbyClover(x2,x1,clover,sigval,akappa,sigin,true);
387#ifdef USE_GPU
389#endif
390 if(fac_f!=0){
391 alignas(16) const double fac=(double)fac_f;
392#ifdef USE_GPU
393 //Multiple ranks means we need striding
394#if (nproc>1)
395 for(unsigned short j=0;j<nc*ndirac;j++)
396 cublasZaxpy(cublas_handle,kvol,(cuDoubleComplex *)&fac,(cuDoubleComplex *)p+j*kvolHalo,1,(cuDoubleComplex *)x2+j*kvol,1);
397#else
398 //Single GPU, no halos, so make it one call to speed things up
399 cublasZaxpy(cublas_handle,kferm2,(cuDoubleComplex *)&fac,(cuDoubleComplex *)p,1,(cuDoubleComplex *)x2,1);
400#endif
401#elif defined USE_BLAS
402 for(unsigned short j=0;j<nc*ndirac;j++)
403 cblas_zaxpy(kvol, &fac, p+j*kvolHalo, 1, x2+j*kvol, 1);
404#else
405#pragma omp parallel for simd collapse(2) aligned(p,x2:AVX)
406 for(unsigned short j=0;j<nc*ndirac;j++)
407 for(unsigned int i=0; i<kvol; i++)
408 x2[i+j*kvol]+=fac*p[i+j*kvolHalo];
409#endif
410 }
411
413 if(*itercg){
414 alpha=0;
415#ifdef USE_GPU
416#if (nproc>1)
417 for(unsigned short j=0;j<nc*ndirac;j++){
418 Complex alpha_t=0;
419 cublasZdotc(cublas_handle,kvol,(cuDoubleComplex *)p+j*kvolHalo,1,(cuDoubleComplex *)x2+j*kvol,1,(cuDoubleComplex *)&alpha_t);
420 alpha+=alpha_t;
421 }
422#else
423 cublasZdotc(cublas_handle,kferm2,(cuDoubleComplex *)p,1,(cuDoubleComplex *)x2,1,(cuDoubleComplex *)&alpha);
424#endif
425#elif defined USE_BLAS
426 for(unsigned short j=0;j<nc*ndirac;j++){
427 Complex alpha_t=0;
428 cblas_zdotc_sub(kvol, p+j*kvolHalo, 1, x2+j*kvol, 1, &alpha_t);
429 alpha+=creal(alpha_t);
430 }
431#else
432#pragma omp parallel for simd collapse(2) aligned(p,x2:AVX) reduction(+:alpha)
433 for(unsigned short j=0;j<nc*ndirac;j++)
434 for(unsigned int i=0; i<kvol; i++)
435 alpha+=conj(p[i+j*kvolHalo])*x2[i+j*kvol];
436#endif
437 //For now I'll cast it into a float for the reduction. Each rank only sends and writes
438 //to the real part so this is fine
439#if (nproc>1)
440 Par_dsum((double *)&alpha);
441#endif
443 alpha=alphan/creal(alpha);
445#ifdef USE_GPU
446#if (nproc>1)
447 for(unsigned short j=0;j<nc*ndirac;j++)
448 cublasZaxpy(cublas_handle,kvol,(cuDoubleComplex *)&alpha,(cuDoubleComplex *)p+j*kvolHalo,1,(cuDoubleComplex *)X1+j*kvolHalo,1);
449#else
450 cublasZaxpy(cublas_handle,kferm2,(cuDoubleComplex *)&alpha,(cuDoubleComplex *)p,1,(cuDoubleComplex *)X1,1);
451#endif
452#elif defined USE_BLAS
453 for(unsigned short j=0;j<nc*ndirac;j++)
454 cblas_zaxpy(kvol, &alpha, p+j*kvolHalo, 1, X1+j*kvolHalo, 1);
455#else
456#pragma omp parallel for simd collapse(2) aligned(p,X1:AVX)
457 for(unsigned short j=0;j<nc*ndirac;j++)
458 for(unsigned int i=0; i<kvol; i++)
459 X1[i+j*kvolHalo]+=alpha*p[i+j*kvolHalo];
460#endif
461 }
462
463#ifdef USE_GPU
464 alignas(16) Complex alpha_m=(Complex)(-alpha);
465 cublasZaxpy(cublas_handle, kferm2,(cuDoubleComplex *)&alpha_m,(cuDoubleComplex *)x2,1,(cuDoubleComplex *)r,1);
466 alignas(16) double betan_d;
467 cublasDznrm2(cublas_handle,kferm2,(cuDoubleComplex *)r,1,&betan_d);
468 betan=betan_d*betan_d;
469#elif defined USE_BLAS
470 const Complex alpha_m = (Complex)(-alpha);
471 cblas_zaxpy(kferm2, &alpha_m, x2, 1, r, 1);
472 //Undo the negation for the BLAS routine
473 double betan_d = cblas_dznrm2(kferm2, r,1);
474 //Gotta square it to "undo" the norm
475 betan = betan_d*betan_d;
476#else
477 betan=0;
478#pragma omp parallel for simd aligned(r_f,x2_f:AVX) reduction(+:betan)
479 for(unsigned int i=0; i<kferm2; i++){
480 r[i]-=alpha*x2[i];
481 betan += conj(r[i])*r[i];
482 }
483 alignas(16) double betan_d=sqrt(betan);
484#endif
485 //And... reduce.
486#if (nproc>1)
487 Par_dsum(&betan);
488#endif
489 betan_d=sqrt(betan);
490 //Update beta_max. Mandatory for double precision.
491 beta_max=betan_d;
492#ifdef _DEBUG
493 if(!rank) printf("DP Iter(CG)=%i\tbeta_n=%e\talpha=%e\n", *itercg, betan, creal(alpha));
494 fflush(stdout);
495#endif
496 alignas(16) const Complex beta = (*itercg) ? betan/betad : 0;
497 betad=betan; alphan=betan;
498#ifdef USE_GPU
499 alpha_m=1;
500 //Strided multi-gpu
501#if (nproc>1)
502 for(unsigned short j=0;j<nc*ndirac;j++){
503 cublasZdscal(cublas_handle,kvol,(double *)&beta,(cuDoubleComplex *)p+j*kvolHalo,1);
504 cublasZaxpy(cublas_handle,kvol,(cuDoubleComplex *)&alpha_m,(cuDoubleComplex *)r+j*kvol,1,(cuDoubleComplex *)p+j*kvolHalo,1);
505 }
506 //And single GPU
507#else
508 cublasZdscal(cublas_handle,kferm2,(double *)&beta,(cuDoubleComplex *)p,1);
509 cublasZaxpy(cublas_handle,kferm2,(cuDoubleComplex *)&alpha_m,(cuDoubleComplex *)r,1,(cuDoubleComplex *)p,1);
510#endif
511#elif (defined __USE_MKL__||defined OPENBLAS||defined AMD_BLAS)
512 const Complex a = 1.0;
513 //There is cblas_?axpby in the MKL and AMD though, set a = 1 and b = \beta.
514 //If we get a small enough \beta_n before hitting the iteration cap we break
515 for(unsigned short j=0;j<nc*ndirac;j++)
516 cblas_zaxpby(kvol, &a, r+j*kvol, 1, &beta, p+j*kvolHalo, 1);
517#elifdef USE_BLAS
518 const Complex a = 1.0;
519 for(unsigned short j=0;j<nc*ndirac;j++){
520 cblas_zscal(kvol,&beta,p+j*kvolHalo,1);
521 cblas_zaxpy(kvol,&a,r+j*kvol,1,p+j*kvolHalo,1);
522 }
523#else
524#pragma omp parallel for simd collapse(2) aligned(r,p:AVX)
525 for(unsigned short j=0;j<nc*ndirac;j++)
526 for(unsigned int i=0; i<kvol; i++)
527 p[i+j*kvolHalo]=r[i+j*kvol]+beta*p[i+j*kvolHalo];
528#endif
529 ComplexConvert(p_f,p,kvol,true,nc*ndirac);
530 ComplexConvert(r_f,r,kferm2,true,1);
531#ifdef _DEBUGCG
532 if(!rank) printf("Double precision. Iter(CG)=%i\tbeta_n=%e\talpha=%e\n", *itercg, betan, creal(alpha));
533 fflush(stdout);
534#endif
535 if(betan<resid){
536 (*itercg)++;
537#ifdef _DEBUG
538 if(!rank) printf("\nIter(CG)=%i\tResidue: %e\tTolerance: %e\n", *itercg, betan, resid);
539#endif
540 ret_val=0; break;
541 }
542 else
543 do_dp=false;
544 }
545 else{
547 //No need to synchronise here. The memcpy in Hdslash is blocking
548 Hdslash_f(x1_f,p_f,ut,iu,id,gamval_f,gamin,dk_f,akappa);
549 //Clover contribution
550 if(c_sw)
551 HbyClover_f(x1_f,p_f,clover_f,sigval_f,akappa,sigin,false);
552 Hdslashd_f(x2_f,x1_f,ut,iu,id,gamval_f,gamin,dk_f,akappa);
553 //Clover contribution
554 if(c_sw)
555 HbyClover_f(x2_f,x1_f,clover_f,sigval_f,akappa,sigin,true);
556#ifdef USE_GPU
558#endif
560 //No point adding zero a couple of hundred times if the diquark source is zero
561 if(fac_f!=0){
562#ifdef USE_GPU
563 //Strided multi-gpu
564#if (nproc>1)
565 for(unsigned short j=0;j<nc*ndirac;j++)
566 cublasCaxpy(cublas_handle,kvol,(cuComplex *)&fac_f,(cuComplex *)p_f+j*kvolHalo,1,(cuComplex *)x2_f+j*kvol,1);
567 //Single GPU
568#else
569 cublasCaxpy(cublas_handle,kferm2,(cuComplex *)&fac_f,(cuComplex *)p_f,1,(cuComplex *)x2_f,1);
570#endif
571#elif defined USE_BLAS
572 for(unsigned short j=0;j<nc*ndirac;j++)
573 cblas_caxpy(kvol, &fac_f, p_f+j*kvolHalo, 1, x2_f+j*kvol, 1);
574#else
575#pragma omp parallel for simd collapse(2) aligned(p_f,x2_f:AVX)
576 for(unsigned short j=0;j<nc*ndirac;j++)
577 for(unsigned int i=0; i<kvol; i++)
578 x2_f[i+j*kvol]+=fac_f*p_f[i+j*kvolHalo];
579#endif
580 }
583 if(*itercg){
584 alphad=0;
585#ifdef USE_GPU
586#if (nproc>1)
587 for(unsigned short j=0;j<nc*ndirac;j++){
588 Complex alpha_t=0;
589 cublasCdotc(cublas_handle,kvol,(cuComplex *)p_f+j*kvolHalo,1,(cuComplex *)x2_f+j*kvol,1,(cuComplex *)&alpha_t);
590 alphad+=alpha_t;
591 }
592#else
593 cublasCdotc(cublas_handle,kferm2,(cuComplex *)p_f,1,(cuComplex *)x2_f,1,(cuComplex *)&alphad);
594#endif
595#elif defined USE_BLAS
596 for(unsigned short j=0;j<nc*ndirac;j++){
597 Complex_f alpha_t=0;
598 cblas_cdotc_sub(kvol, p_f+j*kvolHalo, 1, x2_f+j*kvol, 1, &alpha_t);
599 alphad+=creal(alpha_t);
600 }
601#else
602#pragma omp parallel for simd aligned(p_f,x2_f:AVX) reduction(alphad:+)
603 for(unsigned short j=0;j<nc*ndirac;j++)
604 for(unsigned int i=0; i<kvol; i++)
605 alphad+=conj(p_f[i+j*kvolHalo])*x2_f[i+j*kvol];
606#endif
607 //For now I'll cast it into a float for the reduction. Each rank only sends and writes
608 //to the real part so this is fine
609#if (nproc>1)
610 Par_fsum((float *)&alphad);
611#endif
613 alpha=alphan/creal(alphad);
615#ifdef USE_GPU
616 alignas(8) Complex_f alpha_f = (Complex_f)alpha;
617#if (nproc>1)
618 for(unsigned short j=0;j<nc*ndirac;j++)
619 cublasCaxpy(cublas_handle,kvol,(cuComplex *)&alpha_f,(cuComplex *)p_f+j*kvolHalo,1,(cuComplex *)X1_f+j*kvol,1);
620#else
621 cublasCaxpy(cublas_handle,kferm2,(cuComplex *)&alpha_f,(cuComplex *)p_f,1,(cuComplex *)X1_f,1);
622#endif
623#elif defined USE_BLAS
624 Complex_f alpha_f = (Complex_f)alpha;
625 for(unsigned short j=0;j<nc*ndirac;j++)
626 cblas_caxpy(kvol, &alpha_f, p_f+j*kvolHalo, 1, X1_f+j*kvol, 1);
627#else
628#pragma omp parallel for simd collapse(2) aligned(X1_f,p_f:AVX)
629 for(unsigned short j=0;j<nc*ndirac;j++)
630 for(unsigned int i=0; i<kvol; i++)
631 X1_f[i+j*kvol]+=alpha*p_f[i+j*kvolHalo];
632#endif
633 }
635 // And no Halos here so nice and easy
636#ifdef USE_GPU
637 alignas(8) __managed__ Complex_f alpha_m=(Complex_f)(-alpha);
638 cublasCaxpy(cublas_handle, kferm2,(cuComplex *)&alpha_m,(cuComplex *)x2_f,1,(cuComplex *)r_f,1);
639 alignas(8) float betan_f;
640 cublasScnrm2(cublas_handle,kferm2,(cuComplex *)r_f,1,&betan_f);
641 betan = betan_f*betan_f;
642#elif defined USE_BLAS
643 const Complex_f alpha_m = (Complex_f)(-alpha);
644 cblas_caxpy(kferm2, &alpha_m, x2_f, 1, r_f, 1);
645 //Undo the negation for the BLAS routine
646 float betan_f = cblas_scnrm2(kferm2, r_f,1);
647 //Gotta square it to "undo" the norm
648 betan = betan_f*betan_f;
649#else
650 betan=0;
651#pragma omp parallel for simd aligned(r_f,x2_f:AVX) reduction(+:betan)
652 for(unsigned int i=0; i<kferm2; i++){
653 r_f[i]-=alpha*x2_f[i];
654 betan += conj(r_f[i])*r_f[i];
655 }
656 alignas(8) float betan_f=sqrt(betan);
657#endif
658 //And... reduce.
659#if (nproc>1)
660 Par_dsum(&betan);
661#endif
662 betan_f=sqrt(betan);
663 //Update beta_max if needed. On paper congrad is monotonically decreasing
664 beta_max = (betan_f>beta_max) ?betan_f : beta_max;
665
666#ifdef _DEBUG
667 if(!rank) printf("Iter(CG)=%i\tbeta_n=%e\talpha=%e%s", *itercg, betan, creal(alpha),endline);
668 fflush(stdout);
669#endif
670 if(betan_f<beta_max*d_prec){
671#ifdef _DEBUG
672 if(!rank)
673 printf("\nResidue %e is less than %e times %e.%s",betan_f,d_prec,beta_max,endline);
674#endif
675 do_dp=true;
676 }
677 else if(betan<resid){
678#ifdef _DEBUG
679 if(!rank)
680 printf("\nBetan %e is less than target residue %e.\n",betan,resid);
681#endif
682 do_dp=true;
683 //break;
684 }
685 else if(*itercg==niterc-1){
686 if(!rank) fprintf(stderr, "\nWarning %i in %s: Exceeded iteration limit %i beta_n=%e\n",\
687 ITERLIM, funcname, *itercg, betan);
688 ret_val=ITERLIM; break;
689 }
690 //Here we evaluate beta=(r_{k+1}.r_{k+1})/(r_k.r_k) and then shuffle our indices down the line.
691 //On the first iteration we define beta to be zero.
692 //Note that beta below is not the global beta and scoping is used to avoid conflict between them
693 Complex beta = (*itercg) ? betan/betad : 0;
694 betad=betan; alphan=betan;
695 //BLAS for p=r+\betap doesn't exist in standard BLAS. This is NOT an axpy case as we're multiplying y by
696 //\beta instead of x.
697#ifdef USE_GPU
698 alignas(8) Complex_f beta_f=(Complex_f)beta;
699 alpha_m = 1.0;
700#if (nproc>1)
701 for(unsigned short j=0;j<nc*ndirac;j++){
702 cublasCscal(cublas_handle,kvol,(cuComplex *)&beta_f,(cuComplex *)p_f+j*kvolHalo,1);
703 cublasCaxpy(cublas_handle,kvol,(cuComplex *)&alpha_m,(cuComplex *)r_f+j*kvolHalo,1,(cuComplex *)p_f+j*kvolHalo,1);
704 }
705#else
706 cublasCscal(cublas_handle,kferm2,(cuComplex *)&beta_f,(cuComplex *)p_f,1);
707 cublasCaxpy(cublas_handle,kferm2,(cuComplex *)&alpha_m,(cuComplex *)r_f,1,(cuComplex *)p_f,1);
708#endif
709#elif (defined __USE_MKL__||defined OPENBLAS||defined AMD_BLAS)
710 Complex_f a = 1.0;
711 Complex_f beta_f=(Complex_f)beta;
712 //There is cblas_?axpby in the MKL and AMD though, set a = 1 and b = \beta.
713 //If we get a small enough \beta_n before hitting the iteration cap we break
714 for(unsigned short j=0;j<nc*ndirac;j++)
715 cblas_caxpby(kvol, &a, r_f+j*kvol, 1, &beta_f, p_f+j*kvolHalo, 1);
716#elif defined USE_BLAS
717 Complex_f beta_f=(Complex_f)beta;
718 Complex_f a = 1.0;
719 for(unsigned short j=0;j<nc*ndirac;j++){
720 cblas_cscal(kvol,&beta_f,p_f+j*kvolHalo,1);
721 cblas_caxpy(kvol,&a,r_f+j*kvol,1,p_f+j*kvolHalo,1);
722 }
723#else
724#pragma omp parallel for simd collapse(2) aligned(p_f,r_f:AVX)
725 for(unsigned short j=0;j<nc*ndirac;j++)
726 for(unsigned int i=0; i<kvol; i++)
727 p_f[i+j*kvolHalo]=r_f[i+j*kvol]+beta*p_f[i+j*kvolHalo];
728#endif
729 }
730 }
731 Q_free_f(&p_f,&x1_f,&x2_f,&r_f,&X1_f);
732 Q_free(&p,&x1,&x2,clover);
733 return ret_val;
734}
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:289
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:382
int Hdslashd_f(Complex_f *phi, Complex_f *r, Complex_f *ut[nc], unsigned int *iu, unsigned int *id, Complex_f gamval[20], const unsigned short gamin[16], float *dk[nc], float akappa)
Evaluates in single precision.
Definition matrices.c:746
int Hdslashd(Complex *phi, Complex *r, Complex *ut[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], const unsigned short gamin[16], double *dk[nc], float akappa)
Evaluates in double precision.
Definition matrices.c:338
int Hdslash(Complex *phi, Complex *r, Complex *ut[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], const unsigned short gamin[16], double *dk[nc], float akappa)
Evaluates in double precision.
Definition matrices.c:254
int Hdslash_f(Complex_f *phi, Complex_f *r, Complex_f *ut[nc], unsigned int *iu, unsigned int *id, Complex_f gamval[20], const unsigned short gamin[16], float *dk[nc], float akappa)
Evaluates in single precision.
Definition matrices.c:663
void Q_allocate_f(Complex_f **p_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **r_f, Complex_f **X1_f)
Allocates memory needed for Congradq. Just to improve readability Note that since C does not modify i...
Definition congrad.c:23
void Q_allocate(Complex **p, Complex **x1, Complex **x2, Complex *clover[2])
Allocates double precision memory needed for Congradq. Just to improve readability Note that since C ...
Definition congrad.c:64
void Q_free(Complex **p, Complex **x1, Complex **x2, Complex *clover[2])
Frees double precision memory needed for Congradq. Just to improve readability Note that since C does...
Definition congrad.c:211
void Q_free_f(Complex_f **p_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **r_f, Complex_f **X1_f)
Frees memory needed for Congradq. Just to improve readability Note that since C does not modify it's ...
Definition congrad.c:181
#define ndirac
Dirac indices.
Definition sizes.h:186
#define kferm2
sublattice size including Dirac indices
Definition sizes.h:197

References Complex, Complex_f, ComplexConvert(), conj(), creal, cublas_handle, cudaDeviceSynchronise, cuMixed_Sumto(), dimBlock, dimGrid, HbyClover(), HbyClover_f(), Hdslash(), Hdslash_f(), Hdslashd(), Hdslashd_f(), ITERLIM, kferm2, kvol, kvolHalo, nc, ndirac, niterc, Par_dsum(), Par_fsum(), Q_allocate(), Q_allocate_f(), Q_free(), Q_free_f(), rank, and streams.

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

◆ cuForce()

void cuForce ( double * dSdpi,
Complex_f * ut[2],
Complex_f * X1,
Complex_f * X2,
Complex_f gamval[20],
float * dk[2],
unsigned int * iu,
const unsigned short gamin[16],
float akappa,
dim3 dimGrid,
dim3 dimBlock )

Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.

Parameters
[in,out]dSdpiThe force
[in]utGauge fields
[in]X1Inverted field
[in]X2\(MX_1\)
[in]gamvalDouble/float precision gamma matrices rescaled by \(\kappa\)
[in]gaminGamma indices
[in]iuLattice indices
[in]dk\(e^{-\mu}\) and \(e^\mu\)
[in]akappaHopping parameter
[in]dimGrid,dimBlockCUDA grid/block size
Postcondition
Fermion force added onto dSdpi

Definition at line 373 of file cuforce.cu.

375 {
376 const char *funcname = "Force";
377 //X1=(M†M)^{1} Phi
378 // Transpose_z(X1,ndirac*nc,kvol); Transpose_z(X2,ndirac*nc,kvol);
380#pragma unroll
381 for(unsigned short mu=0;mu<3;mu++){
382 Kernels::cuForce_s<<<dimGrid,dimBlock,0,streams[mu]>>>(dSdpi,ut[0],ut[1],X1,X2,gamval,iu,gamin,akappa,mu);
383 }
384 //Set stream for time direction
385 unsigned short mu=3;
386 Kernels::cuForce_t<<<dimGrid,dimBlock,0,streams[mu]>>>(dSdpi,ut[0],ut[1],X1,X2,gamval,dk[0],dk[1],iu,gamin,akappa);
388}
__global__ void cuForce_s(double *dSdpi, Complex_f *u11t, Complex_f *u12t, Complex_f *X1, Complex_f *X2, Complex_f gamval[20], unsigned int *iu, const unsigned short gamin[16], float akappa, const unsigned short mu)
Calculates the force at each intermediate time.
Definition cuforce.cu:146
__global__ void cuForce_t(double *dSdpi, Complex_f *u11t, Complex_f *u12t, Complex_f *X1, Complex_f *X2, Complex_f gamval[20], float *dk4m, float *dk4p, unsigned int *iu, const unsigned short gamin[16], float akappa)
Calculates the force at each intermediate time.
Definition cuforce.cu:243

References Complex_f, cudaDeviceSynchronise, Kernels::cuForce_s(), Kernels::cuForce_t(), dimBlock, and dimGrid.

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

◆ cuForce_s()

__global__ void Kernels::cuForce_s ( double * dSdpi,
Complex_f * u11t,
Complex_f * u12t,
Complex_f * X1,
Complex_f * X2,
Complex_f gamval[20],
unsigned int * iu,
const unsigned short gamin[16],
float akappa,
const unsigned short mu )

Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.

Parameters
[in,out]dSdpiThe force
[in]u11t,u12tFloat precision colour fields
[in]X1Inverted field
[in]X2\(MX_1\)
[in]gamvalGamma matrices rescaled by \(\kappa\)
[in]iuLattice indices
[in]gaminGamma indices
[in]akappaHopping parameter
[in]muForce direction
Postcondition
Force added to dSdpi

Definition at line 146 of file cuforce.cu.

147 {
148 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
149 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
150 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
151 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
152 const unsigned int gthreadId= blockId * bsize+bthreadId;
153
154 for(unsigned int i=gthreadId;i<kvol;i+=gsize*bsize){
155 const unsigned int ind=i+kvolHalo*mu;
156 const Complex_f u11s=u11t[ind]; const Complex_f u12s=u12t[ind];
157 const unsigned int uid = iu[i+kvol*mu];
158 //Similarly to Hdslash we always see idirac*nc so we do that here too.
159 for(unsigned short idirac=0;idirac<nc*ndirac;idirac+=nc){
160 Complex_f X1s[nc]; Complex_f X1su[nc];
161 Complex_f X2s[nc]; Complex_f X2su[nc];
162
163 X1s[0]=X1[i+kvolHalo*(idirac)]; X1s[1]=X1[i+kvolHalo*(1+idirac)];
164 X1su[0]=X1[uid+kvolHalo*(idirac)]; X1su[1]=X1[uid+kvolHalo*(1+idirac)];
165 X2s[0]=2*X2[i+kvolHalo*(idirac)]; X2s[1]=2*X2[i+kvolHalo*(1+idirac)];
166 X2su[0]=2*X2[uid+kvolHalo*(idirac)]; X2su[1]=2*X2[uid+kvolHalo*(1+idirac)];
167
168 // Need to be double to avoid accumulation errors
169 double dSdpis[3];
170 //Careful!! cant use ind here as dSdpi has no halo!
171 dSdpis[0]=dSdpi[i+kvol*mu];
172 //Multiplying by i and taking the real component is the same as taking the negative imaginary component
173 //The positions of u11 and u12 might look a bit funky here. That's just because we've multiplied by the
174 //generators by hand
175 dSdpis[0]+=-akappa*(
176 conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
177 +conj(X1s[1])*(u11s*X2su[0]+u12s*X2su[1])
178 +conj(X1su[0])*(u12s*X2s[0]-conj(u11s)*X2s[1])
179 +conj(X1su[1])*(-u11s*X2s[0]-conj(u12s)*X2s[1])).imag();
180
181 dSdpis[1]=dSdpi[i+kvol*(ndim+mu)];
182 dSdpis[1]+=akappa*(
183 (conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
184 +conj(X1s[1])*(-u11s*X2su[0]-u12s*X2su[1])
185 +conj(X1su[0])*(-u12s*X2s[0]-conj(u11s)*X2s[1])
186 +conj(X1su[1])*(u11s*X2s[0]-conj(u12s)*X2s[1]))).real();
187
188 dSdpis[2]=dSdpi[i+kvol*(2*ndim+mu)];
189 dSdpis[2]+=-akappa*(
190 conj(X1s[0])*(u11s *X2su[0]+u12s *X2su[1])
191 +conj(X1s[1])*(conj(u12s)*X2su[0]-conj(u11s)*X2su[1])
192 +conj(X1su[0])*(-conj(u11s)*X2s[0]-u12s *X2s[1])
193 +conj(X1su[1])*(-conj(u12s)*X2s[0]+u11s *X2s[1])).imag();
194
195 const unsigned short gindex=mu*ndirac+(idirac>>1);
196 const Complex_f gamval_c=gamval[gindex];
197 //Rescaling gind by nc
198 const unsigned short gind = gamin[gindex]<<1;
199 X2s[0]=2*X2[i+kvolHalo*(gind)]; X2s[1]=2*X2[i+kvolHalo*(1+gind)];
200 X2su[0]=2*X2[uid+kvolHalo*(gind)]; X2su[1]=2*X2[uid+kvolHalo*(1+gind)];
201
202 //If you are asked to rederive the force from Montvay and Munster you'll notice that it should be kappa*gamma
203 //but below is only gamma. We rescaled gamma by kappa already when we defined it so that's where it has gone
204 dSdpis[0]+=-(gamval_c*
205 (conj(X1s[0])* (-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
206 +conj(X1s[1])* (u11s *X2su[0]+u12s *X2su[1])
207 +conj(X1su[0])* (-u12s *X2s[0] +conj(u11s)*X2s[1])
208 +conj(X1su[1])*(u11s *X2s[0] +conj(u12s)*X2s[1]))).imag();
209 dSdpi[i+kvol*mu]=dSdpis[0];
210
211 dSdpis[1]+=(gamval_c*
212 (conj(X1s[0])* (-conj(u12s)*X2su[0] +conj(u11s)*X2su[1])
213 +conj(X1s[1])*(-u11s *X2su[0]-u12s *X2su[1])
214 +conj(X1su[0])* (u12s *X2s[0]+conj(u11s)*X2s[1])
215 +conj(X1su[1])* (-u11s *X2s[0]+conj(u12s)*X2s[1]))).real();
216 dSdpi[i+kvol*(ndim+mu)]=dSdpis[1];
217
218 dSdpis[2]+=-(gamval_c*
219 (conj(X1s[0])*(u11s *X2su[0]+u12s *X2su[1])
220 +conj(X1s[1])*(conj(u12s)*X2su[0]-conj(u11s)*X2su[1])
221 +conj(X1su[0])*(conj(u11s)*X2s[0]+u12s *X2s[1])
222 +conj(X1su[1])*(conj(u12s)*X2s[0]-u11s *X2s[1]))).imag();
223 dSdpi[i+kvol*(2*ndim+mu)]=dSdpis[2];
224 }
225 }
226 }
#define ndim
Dimensions.
Definition sizes.h:188

References Complex_f, conj(), kvol, kvolHalo, nc, ndim, and ndirac.

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

◆ cuForce_t()

__global__ void Kernels::cuForce_t ( double * dSdpi,
Complex_f * u11t,
Complex_f * u12t,
Complex_f * X1,
Complex_f * X2,
Complex_f gamval[20],
float * dk4m,
float * dk4p,
unsigned int * iu,
const unsigned short gamin[16],
float akappa )

Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.

Parameters
[in,out]dSdpiThe force
[in]u11t,u12tFloat precision colour fields
[in]X1Inverted field
[in]X2\(MX_1\)
[in]gamvalGamma matrices rescaled by \(\kappa\)
[in]dk4m,dk4p\(e^{-\mu}\) and \(e^\mu\)
[in]iuLattice indices
[in]gaminGamma indices
[in]akappaHopping parameter
Postcondition
Force added to dSdpi

Definition at line 243 of file cuforce.cu.

244 {
245 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
246 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
247 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
248 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
249 const unsigned int gthreadId= blockId * bsize+bthreadId;
250
251 const unsigned short mu=3;
252 for(unsigned int i=gthreadId;i<kvol;i+=gsize*bsize){
253 const unsigned int ind=i+kvolHalo*mu;
254 const Complex_f u11s=u11t[ind]; const Complex_f u12s=u12t[ind];
255 const float dk4ms=dk4m[i]; const float dk4ps=dk4p[i];
256 //Up indices
257 const unsigned int uid = iu[i+kvol*mu];
258 //Similarly to Hdslash we always see idirac*nc so we do that here too.
259 for(unsigned short idirac=0;idirac<ndirac*nc;idirac+=nc){
260 Complex_f X1s[nc]; Complex_f X1su[nc];
261 Complex_f X2s[nc]; Complex_f X2su[nc];
262
263 X1s[0]=X1[i+kvolHalo*(idirac)]; X1s[1]=X1[i+kvolHalo*(1+idirac)];
264 X1su[0]=X1[uid+kvolHalo*(idirac)]; X1su[1]=X1[uid+kvolHalo*(1+idirac)];
265 X2s[0]=2*X2[i+kvolHalo*(idirac)]; X2s[1]=2*X2[i+kvolHalo*(1+idirac)];
266 X2su[0]=2*X2[uid+kvolHalo*(idirac)]; X2su[1]=2*X2[uid+kvolHalo*(1+idirac)];
267
268 // Need to be double to avoid accumulation errors
269 double dSdpis[3];
270 dSdpis[0]=dSdpi[i+kvol*mu];
271 //Multiplying by i and taking the real component is the same as taking the negative imaginary component
272 //The positions of u11 and u12 might look a bit funky here. That's just because we've multiplied by the
273 //generators by hand
274 dSdpis[0]+=-(dk4ms*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
275 +conj(X1s[1])*(u11s *X2su[0]+u12s *X2su[1]))
276 +dk4ps*(conj(X1su[0])*(+u12s*X2s[0]-conj(u11s)*X2s[1])
277 +conj(X1su[1])*(-u11s*X2s[0]-conj(u12s)*X2s[1]))).imag();
278
279 dSdpis[1]=dSdpi[i+kvol*(ndim+mu)];
280 dSdpis[1]+=(dk4ms*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
281 +conj(X1s[1])*(-u11s *X2su[0]-u12s *X2su[1]))
282 +dk4ps*(conj(X1su[0])*(-u12s *X2s[0]-conj(u11s)*X2s[1])
283 +conj(X1su[1])*( u11s *X2s[0]-conj(u12s)*X2s[1]))).real();
284
285 dSdpis[2]=dSdpi[i+kvol*(2*ndim+mu)];
286 dSdpis[2]+=-(dk4ms* (conj(X1s[0])* (u11s *X2su[0]+u12s *X2su[1])
287 +conj(X1s[1])* (conj(u12s)*X2su[0]-conj(u11s)*X2su[1]))
288 +dk4ps*(conj(X1su[0])*(-conj(u11s)*X2s[0]-u12s *X2s[1])
289 +conj(X1su[1])* (-conj(u12s)*X2s[0]+u11s *X2s[1]))).imag();
290
291 const unsigned short gindex=mu*ndirac+(idirac>>1);
292 //Rescaling gind by nc
293 const unsigned short gind = gamin[gindex]<<1;
294 X2s[0]=2*X2[i+kvolHalo*(gind)]; X2s[1]=2*X2[i+kvolHalo*(1+gind)];
295 X2su[0]=2*X2[uid+kvolHalo*(gind)]; X2su[1]=2*X2[uid+kvolHalo*(1+gind)];
296
297 dSdpis[0]+=-(dk4ms*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
298 +conj(X1s[1])*(u11s *X2su[0]+u12s *X2su[1]))
299 -dk4ps*(conj(X1su[0])* (u12s *X2s[0]-conj(u11s)*X2s[1])
300 +conj(X1su[1])*(-u11s *X2s[0]-conj(u12s)*X2s[1]))).imag();
301 dSdpi[i+kvol*mu]=dSdpis[0];
302
303 dSdpis[1]+=(dk4ms*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
304 +conj(X1s[1])*(-u11s*X2su[0]-u12s *X2su[1]))
305 -dk4ps*(conj(X1su[0])*(-u12s *X2s[0]-conj(u11s)*X2s[1])
306 +conj(X1su[1])*(u11s*X2s[0]-conj(u12s)*X2s[1]))).real();
307 dSdpi[i+kvol*(ndim+mu)]=dSdpis[1];
308
309 dSdpis[2]+=-(dk4ms*(conj(X1s[0])*(u11s*X2su[0] +u12s *X2su[1])
310 +conj(X1s[1])* (conj(u12s)*X2su[0]-conj(u11s)*X2su[1]))
311 -dk4ps*(conj(X1su[0])*(-conj(u11s)*X2s[0]-u12s *X2s[1])
312 +conj(X1su[1])*(-conj(u12s)*X2s[0]+u11s *X2s[1]))).imag();
313 dSdpi[i+kvol*(2*ndim+mu)]=dSdpis[2];
314 }
315 }
316 }

References Complex_f, conj(), kvol, kvolHalo, nc, ndim, and ndirac.

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

◆ cuGauge_force()

void cuGauge_force ( Complex_f * ut[2],
double * dSdpi,
float beta,
unsigned int * iu,
unsigned int * id,
dim3 dimGrid,
dim3 dimBlock )

Calculate the gauge contribution to the force.

Parameters
[in]utGauge fields
[out]dSdpiForce
[in]betaInverse gauge coupling
[in]iu,idUpper/lower indices
[in]dimGrid,dimBlockCUDA grid/block size
Postcondition
Contents of dSdpi overwritten

Definition at line 319 of file cuforce.cu.

319 {
320 const char funcname[] = "Gauge_force";
321 int device=-1;
322 cudaGetDevice(&device);
323 Complex_f *Sigma[ndim][2], *ush[ndim][2];
324 for(unsigned short i=0;i<ndim;i++){
325#ifdef _DEBUG
326 cudaMallocManaged((void **)&Sigma[i][0],kvol*sizeof(Complex_f),cudaMemAttachGlobal);
327 cudaMallocManaged((void **)&Sigma[i][1],kvol*sizeof(Complex_f),cudaMemAttachGlobal);
328 cudaMallocManaged((void **)&ush[i][0],kvolHalo*sizeof(Complex_f),cudaMemAttachGlobal);
329 cudaMallocManaged((void **)&ush[i][1],kvolHalo*sizeof(Complex_f),cudaMemAttachGlobal);
330#else
331 cudaMallocAsync((void **)&Sigma[i][0],kvol*sizeof(Complex_f),streams[i]);
332 cudaMallocAsync((void **)&Sigma[i][1],kvol*sizeof(Complex_f),streams[i]);
333 cudaMallocAsync((void **)&ush[i][0],kvolHalo*sizeof(Complex_f),streams[i]);
334 cudaMallocAsync((void **)&ush[i][1],kvolHalo*sizeof(Complex_f),streams[i]);
335#endif
336 }
337 for(unsigned short mu=0; mu<ndim; mu++){
338 cudaMemsetAsync(Sigma[mu][0],0, kvol*sizeof(Complex_f),streams[mu]);
339 cudaMemsetAsync(Sigma[mu][1],0, kvol*sizeof(Complex_f),streams[mu]);
340 for(unsigned short nu=0; nu<ndim; nu++)
341 if(nu!=mu){
342 //The @f$-\nu@f$ Staple
343 Kernels::Plus_staple<<<dimGrid,dimBlock,0,streams[mu]>>>(mu, nu, iu, Sigma[mu][0], Sigma[mu][1],ut[0],ut[1]);
344 Kernels::Gather<<<dimGrid,dimBlock,0,streams[mu]>>>(ush[mu][0], ut[0], kvol, id, nu);
345 Kernels::Gather<<<dimGrid,dimBlock,0,streams[mu]>>>(ush[mu][1], ut[1], kvol, id, nu);
346
347#if(nproc>1)
348 //Prefetch to the CPU for until we get NCCL working
349 //cudaMemPrefetchAsync(ush[0], kvolHalo*sizeof(Complex_f),cudaCpuDeviceId,streams[0]);
350 //cudaMemPrefetchAsync(ush[1], kvolHalo*sizeof(Complex_f),cudaCpuDeviceId,streams[1]);
351 CHalo_swap_dir(ush[mu][0], 1, mu, DOWN); CHalo_swap_dir(ush[mu][1], 1, mu, DOWN);
352 //cudaMemPrefetchAsync(ush[0]+kvol, halo*sizeof(Complex_f),device,streams[0]);
353 //cudaMemPrefetchAsync(ush[1]+kvol, halo*sizeof(Complex_f),device,streams[1]);
354#endif
355 //Next up, the @f$-\nu@f$ staple
356 Kernels::Minus_staple<<<dimGrid,dimBlock,0,streams[mu]>>>(mu, nu, iu, id,Sigma[mu][0],Sigma[mu][1],\
357 ush[mu][0],ush[mu][1],ut[0],ut[1]);
358 }
359 //Now get the gauge force acting in the @f$\mu@f$ direction
360 Kernels::cuGaugeForce<<<dimGrid,dimBlock,0,streams[mu]>>>(mu,Sigma[mu][0],Sigma[mu][1],dSdpi,ut[0],ut[1],beta);
361 }
362 for(unsigned short i=0;i<ndim;i++){
363#ifdef _DEBUG
364 cudaFree(Sigma[i][0]); cudaFree(Sigma[i][1]);
365 cudaFree(ush[i][0]); cudaFree(ush[i][1]);
366#else
367 cudaFreeAsync(Sigma[i][0],streams[i]); cudaFreeAsync(Sigma[i][1],streams[i]);
368 cudaFreeAsync(ush[i][0],streams[i]); cudaFreeAsync(ush[i][1],streams[i]);
369#endif
370 }
372}
__global__ void Gather(T *x, T *y, const unsigned int n, unsigned int *table, const unsigned short mu)
Extracts all the single precision gauge links in the direction only.
Definition cuforce.cu:116
__global__ void Plus_staple(const int mu, const int nu, unsigned int *iu, Complex_f *Sigma11, Complex_f *Sigma12, Complex_f *u11t, Complex_f *u12t)
Calculates the staple in the positive direction.
Definition cuforce.cu:23
__global__ void cuGaugeForce(int mu, Complex_f *Sigma11, Complex_f *Sigma12, double *dSdpi, Complex_f *u11t, Complex_f *u12t, float beta)
Calculates the gauge force due to the Wilson Action at each intermediate time.
Definition cuforce.cu:89
__global__ void Minus_staple(const int mu, const int nu, unsigned int *iu, unsigned int *id, Complex_f *Sigma11, Complex_f *Sigma12, Complex_f *u11sh, Complex_f *u12sh, Complex_f *u11t, Complex_f *u12t)
Calculates the staple in the negative direction.
Definition cuforce.cu:55
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.
#define DOWN
Flag for send down.
Definition par_mpi.h:37

References CHalo_swap_dir(), Complex_f, cudaDeviceSynchronise, Kernels::cuGaugeForce(), dimBlock, dimGrid, DOWN, Kernels::Gather(), kvol, kvolHalo, Kernels::Minus_staple(), ndim, Kernels::Plus_staple(), and streams.

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

◆ cuGauge_Update() [1/2]

void cuGauge_Update ( const double d,
double * pp,
Complex * ut[2],
dim3 dimGrid,
dim3 dimBlock )

CUDA wrapper for the gauge update during the integration step of the HMC.

Parameters
[in]dGauge step size
[in]ppMomentum field
[in,out]ut: Double precision gauge fields
[in]dimGrid,dimBlockCUDA Grid/Block dimensions
Postcondition
ut updated in place

Definition at line 298 of file cusu2hmc.cu.

298 {
299 for(int mu=0;mu<ndim;mu++)
300 Kernels::cuGauge_Update<<<dimGrid,dimBlock,0,streams[mu]>>>(d,pp,ut[0],ut[1],mu);
302}
__global__ void cuGauge_Update(const double d, double *pp, Complex *u11t, Complex *u12t, int mu)
Gauge update for the integration step of the HMC.
Definition cusu2hmc.cu:176

References Complex, cudaDeviceSynchronise, Kernels::cuGauge_Update(), dimBlock, dimGrid, ndim, and streams.

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

◆ cuGauge_Update() [2/2]

__global__ void Kernels::cuGauge_Update ( const double d,
double * pp,
Complex * u11t,
Complex * u12t,
int mu )

Gauge update for the integration step of the HMC.

Parameters
[in]dGauge step size
[in]ppMomentum field
[in,out]u11t,u12tDouble precision gauge fields
[in]muLattice direction being updated
Postcondition
ut and ut_f updated in place

Definition at line 176 of file cusu2hmc.cu.

176 {
177 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
178 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
179 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
180 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
181 const unsigned int gthreadId= blockId * bsize+bthreadId;
182 for(unsigned int i=gthreadId;i<kvol;i+=gsize*bsize){
183 //Sticking to what was in the FORTRAN for variable names.
184 //CCC for cosine SSS for sine AAA for...
185 //Re-exponentiating the force field. Can be done analytically in SU(2)
186 //using sine and cosine which is nice
187 const unsigned int ind = i+kvol*mu;
188 double AAA = d*sqrt(pp[ind]*pp[ind]\
189 +pp[i+kvol*(1*ndim+mu)]*pp[i+kvol*(1*ndim+mu)]\
190 +pp[i+kvol*(2*ndim+mu)]*pp[i+kvol*(2*ndim+mu)]);
191 double CCC = cos(AAA);
192 double SSS = d*sin(AAA)/AAA;
193 Complex a11 = CCC+I*SSS*pp[i+kvol*(2*ndim+mu)];
194 Complex a12 = pp[i+kvol*(1*ndim+mu)]*SSS + I*SSS*pp[ind];
195 //b11 and b12 are u11t and u12t terms, so we'll use u12t directly
196 //but use b11 for u11t to prevent RAW dependency
197 Complex b11 = u11t[ind];
198 u11t[ind] = a11*b11-a12*conj(u12t[ind]);
199 u12t[ind] = a11*u12t[ind]+a12*conj(b11);
200 }
201}
#define I
Define I in double precision using C standard notation.

References Complex, conj(), I, kvol, and ndim.

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

◆ cuGaugeForce()

__global__ void Kernels::cuGaugeForce ( int mu,
Complex_f * Sigma11,
Complex_f * Sigma12,
double * dSdpi,
Complex_f * u11t,
Complex_f * u12t,
float beta )

Calculates the gauge force due to the Wilson Action at each intermediate time.

Parameters
[out]dSdpiThe force
[in]u11t,u12tGauge fields
[in]Sigma11,Sigma12Staples
[in]muGenerator index
[in]betaInverse gauge coupling
Postcondition
Gauge force written to dSdpi.

Definition at line 89 of file cuforce.cu.

89 {
90 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
91 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
92 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
93 const unsigned int threadId= blockId * bsize+(threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
94 for(unsigned int i=threadId;i<kvol;i+=gsize*bsize){
95 const unsigned int ind = i+kvolHalo*mu;
96 Complex_f a11 = u11t[ind]*Sigma12[i]+u12t[ind]*conj(Sigma11[i]);
97 Complex_f a12 = u11t[ind]*Sigma11[i]+conj(u12t[ind])*Sigma12[i];
98 //Not worth splitting into different streams, before we get ideas...
99 dSdpi[i+kvol*mu]=beta*a11.imag();
100 dSdpi[i+kvol*(1*ndim+mu)]=beta*a11.real();
101 dSdpi[i+kvol*(2*ndim+mu)]=beta*a12.imag();
102 }
103 }

References Complex_f, conj(), kvol, kvolHalo, and ndim.

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

◆ Force()

int Force ( double * dSdpi,
const bool iflag,
double res1,
Complex * X0,
Complex * X1,
Complex * Phi,
Complex * ut[2],
Complex_f * ut_f[2],
unsigned int * iu,
unsigned int * id,
Complex gamval[20],
Complex_f gamval_f[20],
const unsigned short gamin[16],
Complex * sigval,
Complex_f * sigval_f,
unsigned short * sigin,
double * dk[2],
float * dk_f[2],
const Complex_f jqq,
const float akappa,
const float beta,
const float c_sw,
double * ancg )

Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.

Parameters
[in,out]dSdpiThe force
[in]iflagInvert before evaluating the force. 0 to invert, one not to. Blame FORTRAN...
[in]res1Conjugate gradient residue
[in]X0Up/down partitioned pseudofermion field
[in]X1Holder for the partitioned fermion field, then the inverted dield
[in]PhiPseudofermion field
[in]ut,ut_fDouble/float precision colour fields
[in]iu,idLattice indices
[in]gamval,gamval_fDouble/float precision gamma matrices rescaled by \(\kappa\)
[in]gaminGamma indices
[in]sigval,sigval_fDouble/float Commutators of gamma matrices scaled by \(\frac{c_\text{SW}}{2}\)
[in]siginWhat element of the spinor is multiplied by row idirac each sigma matrix?
[in]dk,dk_fDouble/float \(e^{-\mu}\) and \(e^\mu\)
[in]jqqDiquark source
[in]akappaHopping parameter
[in]betaInverse gauge coupling
[in]c_swClover coefficient. If non-zero calculate the clover contribution
[in]ancgCounter for conjugate gradient iterations
Returns
Zero on success, integer error code otherwise
Postcondition
Force added to dSdpi
Todo
If Gauge_force has not been called then set dSdpi to zero. The rest of the force uses += and as a result will add onto the previous answer instead of giving just the fermion force at this step

\((X1=(M\dagger M)^{-1} \Phi\)

Definition at line 228 of file force.c.

231 {
232 const char funcname[] = "Force";
233#ifdef USE_GPU
234 int device=-1;
235 cudaGetDevice(&device);
236#endif
237#ifndef NO_GAUGE
238 Gauge_force(dSdpi,ut_f,iu,id,beta);
239#else
240#endif
243 if(!akappa)
244 return 0;
245 //X1=(M†M)^{1} Phi
246 int itercg=1;
247 Complex_f *clover[2];
248#ifdef USE_GPU
249 Complex_f *X1_f, *X2_f;
250 cudaMallocAsync((void **)&X1_f,kferm2Halo*sizeof(Complex_f),streams[1]);
251 cudaMallocAsync((void **)&X2_f,kferm2Halo*sizeof(Complex_f),streams[0]);
252#else
253 Complex_f *X1_f= (Complex_f *)aligned_alloc(AVX,kferm2Halo*sizeof(Complex_f));
254 Complex_f *X2_f= (Complex_f *)aligned_alloc(AVX,kferm2Halo*sizeof(Complex_f));
255#endif
256 if(c_sw)
257 Clover(clover,ut_f,iu,id);
258
259 for(int na = 0; na<nf; na++){
260#ifdef USE_GPU
261#if(nproc>1) //Strided
262 for(unsigned short j=0;j<nc*idirac;j++)
263 cudaMemcpyAsync(X1+j*kvolHalo,X0+na*kferm2+j*kvol,kvol*sizeof(Complex),cudaMemcpyDeviceToDevice,streams[j]);
264#else
265 cudaMemcpyAsync(X1,X0+na*kferm2,kferm2*sizeof(Complex),cudaMemcpyDeviceToDevice,NULL);
266#endif
267#else
268 for(unsigned short j=0;j<nc*ndirac;j++)
269 memcpy(X1+j*kvolHalo,X0+na*kferm2+j*kvol,kvol*sizeof(Complex));
270#endif
271 if(!iflag){
272 int itercg=1;
273#ifdef USE_GPU
274 Complex *smallPhi;
275 cudaMallocAsync((void **)&smallPhi,kferm2*sizeof(Complex),streams[0]);
276#else
277 Complex *smallPhi = (Complex *)aligned_alloc(AVX,kferm2*sizeof(Complex));
278#endif
279 Fill_Small_Phi(na, smallPhi, Phi);
281 Congradq(na,res1,X1,smallPhi,ut,ut_f,clover,iu,id,gamval,gamval_f,gamin,sigval,sigval_f,sigin,dk,dk_f,\
282 jqq,akappa,c_sw,&itercg);
283#ifdef USE_GPU
284 cudaFreeAsync(smallPhi,streams[0]);
285#else
286 free(smallPhi);
287#endif
288 *ancg+=itercg;
289#ifdef USE_GPU
290 alignas(16) const Complex blasa=2.0; alignas(16) const double blasb=-1.0;
291 cublasZdscal(cublas_handle,kferm2,&blasb,(cuDoubleComplex *)(X0+na*kferm2),1);
292#if(nproc>1) //strided
293 for(unsigned short j=0;j<nc*ndirac;j++)
294 cublasZaxpy(cublas_handle,kvol,(cuDoubleComplex *)&blasa,(cuDoubleComplex *)X1+j*kvolHalo,1,(cuDoubleComplex *)X0+na*kferm2+j*kvol,1);
295#else
296 cublasZaxpy(cublas_handle,kferm2,(cuDoubleComplex *)&blasa,(cuDoubleComplex *)X1,1,(cuDoubleComplex *)(X0+na*kferm2),1);
297#endif
298#elif (defined __USE_MKL__||defined OPENBLAS||defined AMD_BLAS)
299 const Complex blasa=2.0; const Complex blasb=-1.0;
300 //This is not a general BLAS Routine. BLIS and MKl support it
301 //CUDA and GSL does not support it
302 cblas_zaxpby(kferm2, &blasa, X1, 1, &blasb, X0+na*kferm2, 1);
303#elifdef USE_BLAS
304 const Complex blasa=2.0; const double blasb=-1.0;
305 cblas_zdscal(kferm2,blasb,X0+na*kferm2,1);
306 for(unsigned short j=0;j<nc*ndirac;j++)
307 cblas_zaxpy(kvol,&blasa,X1+j*kvolHalo,1,X0+na*kferm2+j*kvol,1);
308#else
309#pragma omp parallel for simd collapse(2) aligned(X0,X1:AVX)
310 for(int idirac=0;idirac<ndirac;idirac++){
311 for(int i=0;i<kvol;i++)
312 X0[i+kvol*(0+nc*(idirac+ndirac*na))]=
313 2*X1[i+kvolHalo*(0+idirac*c)]-X0[i+kvol*(0+nc*(idirac+ndirac*na))];
314 X0[i+kvol*(1+nc*(idirac+ndirac*na))]=
315 2*X1[i+kvolHalo*(1+idirac*c)]-X0[i+kvol*(1+nc*(idirac+ndirac*na))];
316 }
317#endif
318 }
319#ifdef USE_GPU
321#endif
322 //Since it has to be stridded in MPI, we have to pass kvol and nc*ndirac instead of kferm2
323 ComplexConvert(X1_f,X1,kvol,true,nc*ndirac);
324 Hdslash_f(X2_f,X1_f,ut_f,iu,id,gamval_f,gamin,dk_f,akappa);
325 if(c_sw)
326 HbyClover_f(X2_f,X1_f,clover,sigval_f,akappa,sigin,false);
327 //NOTE: This was orginally two. But was changed as a test for Claude so the two appears inside Force_s and Force_t
328 //It may need to be reverted back later
329 alignas(8) const float blasd=1.0;
330#ifdef USE_GPU
332#if(nproc>1)
333 for(unsigned short j=0;j<nc*ndirac;j++)
334 cublasCsscal(cublas_handle,kvol, &blasd, (cuComplex *)X2_f+j*kvolHalo, 1);
335#else
336 cublasCsscal(cublas_handle,kferm2, &blasd, (cuComplex *)X2_f, 1);
337#endif
338#elif defined USE_BLAS
339 for(unsigned short j=0;j<nc*ndirac;j++)
340 cblas_csscal(kvol, blasd, X2_f+j*kvolHalo, 1);
341#else
342#pragma unroll
343#pragma omp parallel for simd collapse(2) aligned(X2_f:AVX)
344 for(unsigned short j=0;j<nc*ndirac;j++)
345 for(unsigned int i=0;i<kvol;i++)
346 X2_f[i+j*kvolHalo]*=1;
347#endif
348#if(npx>1)
351#endif
352#if(npy>1)
355#endif
356#if(npz>1)
359#endif
360#if(npt>1)
363#endif
364
365 // The original FORTRAN Comment:
366 // dSdpi=dSdpi-Re(X1*(d(Mdagger)dp)*X2) -- Yikes!
367 // we're gonna need drugs for this one......
368 //
369 // Makes references to X1(.,.,iu(i,mu)) AND X2(.,.,iu(i,mu))
370 // as a result, need to swap the DOWN halos in all dirs for
371 // both these arrays, each of which has 8 cpts
372 //
373#ifdef USE_GPU
374 cuForce(dSdpi,ut_f,X1_f,X2_f,gamval_f,dk_f,iu,gamin,akappa,dimGrid,dimBlock);
376#else
377 //Thankfully the CUDA version is much neater so we're using that style going forwards
378 for(unsigned short mu=0;mu<ndim-1;mu++)
379 Force_s(dSdpi,ut_f,X1_f,X2_f,gamval_f,iu,gamin,akappa,mu);
380 Force_t(dSdpi,ut_f,X1_f,X2_f,gamval_f,dk_f,iu,gamin,akappa);
381#endif
382 if(c_sw){
383 //Clover_Force(dSdpi,ut_f,X1_f,X2_f,sigval_f,sigin,iu,id,akappa);
384 Clov_Force(dSdpi,ut_f,X1_f,X2_f,sigval_f,sigin,iu,id,akappa);
385 Clover_free(clover);
386 }
387 }
388#ifdef USE_GPU
389 cudaFreeAsync(X1_f,streams[0]); cudaFreeAsync(X2_f,streams[1]);
390#else
391 free(X1_f); free(X2_f);
392#endif
393 return 0;
394}
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:542
void Clover_free(Complex_f *clover[nc])
Free's memory used for clover terms and leaves.
Definition clover.c:750
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
int Fill_Small_Phi(int na, Complex *smallPhi, Complex *Phi)
Copies necessary (2*4*kvol) elements of Phi into a vector variable.
Definition su2hmc.c:311
void Force_t(double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, Complex_f gamval[20], float *dk[2], unsigned int *iu, const unsigned short gamin[16], float akappa)
Calculates the force at each intermediate time.
Definition force.c:156
void cuForce(double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, Complex_f gamval[20], float *dk[2], unsigned int *iu, const unsigned short gamin[16], float akappa, dim3 dimGrid, dim3 dimBlock)
Calculates the force at each intermediate time.
Definition cuforce.cu:373
void Force_s(double *dSdpi, Complex_f *ut[2], Complex_f *X1, Complex_f *X2, Complex_f gamval[20], unsigned int *iu, const unsigned short gamin[16], const float akappa, const unsigned short mu)
Calculates the force at each intermediate time.
Definition force.c:81
int Congradq(int na, double res, Complex *X1, Complex *r, Complex *ud[2], Complex_f *ut[2], Complex_f *clover_f[nc], unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, double *dk[2], float *dk_f[2], Complex_f jqq, float akappa, float c_sw, int *itercg)
Matrix Inversion via Conjugate Gradient (up/down flavour partitioning). Solves Implements up/down pa...
Definition congrad.c:278
int Gauge_force(double *dSdpi, Complex_f *ut[2], unsigned int *iu, unsigned int *id, float beta)
Calculates the gauge force due to the Wilson Action at each intermediate time.
Definition force.c:11
#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 kferm2Halo
Dirac lattice and halo.
Definition sizes.h:238
#define nf
Fermion flavours (double it).
Definition sizes.h:160

References AVX, CHalo_swap_dir(), Clov_Force(), Clover(), Clover_free(), Complex, Complex_f, ComplexConvert(), Congradq(), cublas_handle, cudaDeviceSynchronise, cuForce(), dimBlock, dimGrid, DOWN, Fill_Small_Phi(), Force_s(), Force_t(), Gauge_force(), HbyClover_f(), Hdslash_f(), kferm2, kferm2Halo, kvol, kvolHalo, nc, ndim, ndirac, nf, and streams.

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

◆ Force_s()

void Force_s ( double * dSdpi,
Complex_f * ut[2],
Complex_f * X1,
Complex_f * X2,
Complex_f gamval[20],
unsigned int * iu,
const unsigned short gamin[16],
const float akappa,
const unsigned short mu )

Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.

Parameters
[in,out]dSdpiThe force
[in]utFloat precision colour fields
[in]X1Inverted field
[in]X2\(MX_1\)
[in]gamvalGamma matrices rescaled by \(\kappa\)
[in]iuLattice indices
[in]gaminGamma indices
[in]akappaHopping parameter
[in]muForce direction
Postcondition
Force added to dSdpi

Definition at line 81 of file force.c.

82 {
83#pragma omp parallel for simd
84 for(unsigned int i=0;i<kvol;i++){
85 const unsigned int ind=i+kvolHalo*mu;
86 const Complex_f u11s=ut[0][ind]; const Complex_f u12s=ut[1][ind];
87 const unsigned int uid = iu[i+kvol*mu];
88 //Similarly to Hdslash we always see idirac*nc so we do that here too.
89 for(unsigned short idirac=0;idirac<nc*ndirac;idirac+=nc){
90 Complex_f X1s[nc]; Complex_f X1su[nc];
91 Complex_f X2s[nc]; Complex_f X2su[nc];
92
93 X1s[0]=X1[i+kvolHalo*(idirac)]; X1s[1]=X1[i+kvolHalo*(1+idirac)];
94 X1su[0]=X1[uid+kvolHalo*(idirac)]; X1su[1]=X1[uid+kvolHalo*(1+idirac)];
95 X2s[0]=2*X2[i+kvolHalo*(idirac)]; X2s[1]=2*X2[i+kvolHalo*(1+idirac)];
96 X2su[0]=2*X2[uid+kvolHalo*(idirac)]; X2su[1]=2*X2[uid+kvolHalo*(1+idirac)];
97
98 float dSdpis[3];
99 dSdpis[0]=dSdpi[i+kvol*mu];
100 //Multiplying by i and taking the real component is the same as taking the negative imaginary component
101 //The positions of u11 and u12 might look a bit funky here. That's just because we've multiplied by the
102 //generators by hand
103 dSdpis[0]+=-akappa*cimag(
104 conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
105 +conj(X1s[1])*(u11s*X2su[0]+u12s*X2su[1])
106 +conj(X1su[0])*(u12s*X2s[0]-conj(u11s)*X2s[1])
107 +conj(X1su[1])*(-u11s*X2s[0]-conj(u12s)*X2s[1]));
108
109 dSdpis[1]=dSdpi[i+kvol*(ndim+mu)];
110 dSdpis[1]+=akappa*creal(
111 (conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
112 +conj(X1s[1])*(-u11s*X2su[0]-u12s*X2su[1])
113 +conj(X1su[0])*(-u12s*X2s[0]-conj(u11s)*X2s[1])
114 +conj(X1su[1])*(u11s*X2s[0]-conj(u12s)*X2s[1])));
115
116 dSdpis[2]=dSdpi[i+kvol*(2*ndim+mu)];
117 dSdpis[2]+=-akappa*cimag(
118 conj(X1s[0])*(u11s *X2su[0]+u12s *X2su[1])
119 +conj(X1s[1])*(conj(u12s)*X2su[0]-conj(u11s)*X2su[1])
120 +conj(X1su[0])*(-conj(u11s)*X2s[0]-u12s *X2s[1])
121 +conj(X1su[1])*(-conj(u12s)*X2s[0]+u11s *X2s[1]));
122
123 const unsigned short gindex=mu*ndirac+(idirac>>1);
124 const Complex_f gamval_c=gamval[gindex];
125 //Rescaling gind by nc
126 const unsigned short gind = gamin[gindex]<<1;
127 X2s[0]=2*X2[i+kvolHalo*(gind)]; X2s[1]=2*X2[i+kvolHalo*(1+gind)];
128 X2su[0]=2*X2[uid+kvolHalo*(gind)]; X2su[1]=2*X2[uid+kvolHalo*(1+gind)];
129
130 //If you are asked to rederive the force from Montvay and Munster you'll notice that it should be kappa*gamma
131 //but below is only gamma. We rescaled gamma by kappa already when we defined it so that's where it has gone
132 dSdpis[0]+=-cimag(gamval_c*
133 (conj(X1s[0])* (-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
134 +conj(X1s[1])* (u11s *X2su[0]+u12s *X2su[1])
135 +conj(X1su[0])* (-u12s *X2s[0] +conj(u11s)*X2s[1])
136 +conj(X1su[1])*(u11s *X2s[0] +conj(u12s)*X2s[1])));
137 dSdpi[i+kvol*mu]=dSdpis[0];
138
139 dSdpis[1]+=creal(gamval_c*
140 (conj(X1s[0])* (-conj(u12s)*X2su[0] +conj(u11s)*X2su[1])
141 +conj(X1s[1])*(-u11s *X2su[0]-u12s *X2su[1])
142 +conj(X1su[0])* (u12s *X2s[0]+conj(u11s)*X2s[1])
143 +conj(X1su[1])* (-u11s *X2s[0]+conj(u12s)*X2s[1])));
144 dSdpi[i+kvol*(ndim+mu)]=dSdpis[1];
145
146 dSdpis[2]+=-cimag(gamval_c*
147 (conj(X1s[0])*(u11s *X2su[0]+u12s *X2su[1])
148 +conj(X1s[1])*(conj(u12s)*X2su[0]-conj(u11s)*X2su[1])
149 +conj(X1su[0])*(conj(u11s)*X2s[0]+u12s *X2s[1])
150 +conj(X1su[1])*(conj(u12s)*X2s[0]-u11s *X2s[1])));
151 dSdpi[i+kvol*(2*ndim+mu)]=dSdpis[2];
152 }
153 }
154 return;
155}
#define cimag(z)
Extract Imaginary Component using C standard notation.

References cimag, Complex_f, conj(), creal, kvol, kvolHalo, nc, ndim, and ndirac.

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

◆ Force_t()

void Force_t ( double * dSdpi,
Complex_f * ut[2],
Complex_f * X1,
Complex_f * X2,
Complex_f gamval[20],
float * dk[2],
unsigned int * iu,
const unsigned short gamin[16],
float akappa )

Calculates the force \(\frac{dS}{d\pi}\) at each intermediate time.

Parameters
[in,out]dSdpiThe force
[in]utFloat precision colour fields
[in]X1Inverted field
[in]X2\(MX_1\)
[in]gamvalGamma matrices rescaled by \(\kappa\)
[in]dk\(e^{-\mu}\) and \(e^\mu\)
[in]iuLattice indices
[in]gaminGamma indices
[in]akappaHopping parameter
Postcondition
Force added to dSdpi

Definition at line 156 of file force.c.

157 {
158
159 const unsigned short mu=3;
160#pragma omp parallel for simd
161 for(unsigned int i=0;i<kvol;i++){
162 const unsigned int ind=i+kvolHalo*mu;
163 const Complex_f u11s=ut[0][ind]; const Complex_f u12s=ut[1][ind];
164 //TODO: The only diffrence with these is that the sign flips for the temporal components
165 // Can we figure out a way of doing this without having to read in a large array.
166 // Will result in a conditional inside a CUDA loop. If i>kvol3
167 const float dks[2] = {dk[0][i],dk[1][i]};
168 //Up indices
169 const unsigned int uid = iu[i+kvol*mu];
170 //Similarly to Hdslash we always see idirac*nc so we do that here too.
171 for(unsigned short idirac=0;idirac<ndirac*nc;idirac+=nc){
172 Complex_f X1s[nc]; Complex_f X1su[nc];
173 Complex_f X2s[nc]; Complex_f X2su[nc];
174
175 X1s[0]=X1[i+kvolHalo*(idirac)]; X1s[1]=X1[i+kvolHalo*(1+idirac)];
176 X1su[0]=X1[uid+kvolHalo*(idirac)]; X1su[1]=X1[uid+kvolHalo*(1+idirac)];
177 X2s[0]=2*X2[i+kvolHalo*(idirac)]; X2s[1]=2*X2[i+kvolHalo*(1+idirac)];
178 X2su[0]=2*X2[uid+kvolHalo*(idirac)]; X2su[1]=2*X2[uid+kvolHalo*(1+idirac)];
179
180 float dSdpis[3];
181 dSdpis[0]=dSdpi[i+kvol*mu];
182 //Multiplying by i and taking the real component is the same as taking the negative imaginary component
183 //The positions of u11 and u12 might look a bit funky here. That's just because we've multiplied by the
184 //generators by hand
185 dSdpis[0]+=-cimag(dks[0]*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
186 +conj(X1s[1])*(u11s *X2su[0]+u12s *X2su[1]))
187 +dks[1]*(conj(X1su[0])*(+u12s*X2s[0]-conj(u11s)*X2s[1])
188 +conj(X1su[1])*(-u11s*X2s[0]-conj(u12s)*X2s[1])));
189
190 dSdpis[1]=dSdpi[i+kvol*(ndim+mu)];
191 dSdpis[1]+=creal(dks[0]*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
192 +conj(X1s[1])*(-u11s *X2su[0]-u12s *X2su[1]))
193 +dks[1]*(conj(X1su[0])*(-u12s *X2s[0]-conj(u11s)*X2s[1])
194 +conj(X1su[1])*( u11s *X2s[0]-conj(u12s)*X2s[1])));
195
196 dSdpis[2]=dSdpi[i+kvol*(2*ndim+mu)];
197 dSdpis[2]+=-cimag(dks[0]* (conj(X1s[0])* (u11s *X2su[0]+u12s *X2su[1])
198 +conj(X1s[1])* (conj(u12s)*X2su[0]-conj(u11s)*X2su[1]))
199 +dks[1]*(conj(X1su[0])*(-conj(u11s)*X2s[0]-u12s *X2s[1])
200 +conj(X1su[1])* (-conj(u12s)*X2s[0]+u11s *X2s[1])));
201
202 const unsigned short gindex=mu*ndirac+(idirac>>1);
203 //Rescaling gind by nc
204 const unsigned short gind = gamin[gindex]<<1;
205 X2s[0]=2*X2[i+kvolHalo*(gind)]; X2s[1]=2*X2[i+kvolHalo*(1+gind)];
206 X2su[0]=2*X2[uid+kvolHalo*(gind)]; X2su[1]=2*X2[uid+kvolHalo*(1+gind)];
207
208 dSdpis[0]+=-cimag(dks[0]*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
209 +conj(X1s[1])*(u11s *X2su[0]+u12s *X2su[1]))
210 -dks[1]*(conj(X1su[0])* (u12s *X2s[0]-conj(u11s)*X2s[1])
211 +conj(X1su[1])*(-u11s *X2s[0]-conj(u12s)*X2s[1])));
212 dSdpi[i+kvol*mu]=dSdpis[0];
213
214 dSdpis[1]+=creal(dks[0]*(conj(X1s[0])*(-conj(u12s)*X2su[0]+conj(u11s)*X2su[1])
215 +conj(X1s[1])*(-u11s*X2su[0]-u12s *X2su[1]))
216 -dks[1]*(conj(X1su[0])*(-u12s *X2s[0]-conj(u11s)*X2s[1])
217 +conj(X1su[1])*(u11s*X2s[0]-conj(u12s)*X2s[1])));
218 dSdpi[i+kvol*(ndim+mu)]=dSdpis[1];
219
220 dSdpis[2]+=-cimag(dks[0]*(conj(X1s[0])*(u11s*X2su[0] +u12s *X2su[1])
221 +conj(X1s[1])* (conj(u12s)*X2su[0]-conj(u11s)*X2su[1]))
222 -dks[1]*(conj(X1su[0])*(-conj(u11s)*X2s[0]-u12s *X2s[1])
223 +conj(X1su[1])*(-conj(u12s)*X2s[0]+u11s *X2s[1])));
224 dSdpi[i+kvol*(2*ndim+mu)]=dSdpis[2];
225 }
226 }
227}

References cimag, Complex_f, conj(), creal, kvol, kvolHalo, nc, ndim, and ndirac.

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

◆ Gauge_force()

int Gauge_force ( double * dSdpi,
Complex_f * ut[2],
unsigned int * iu,
unsigned int * id,
float beta )

Calculates the gauge force due to the Wilson Action at each intermediate time.

Parameters
[out]dSdpiThe force
[in]utGauge fields
[in]iu,idLattice indices
[in]betaInverse gauge coupling
Returns
Zero on success, integer error code otherwise
Postcondition
Contents of dSdpi replaced by gauge force

Definition at line 11 of file force.c.

11 {
12 const char funcname[] = "Gauge_force";
13
14 //We define zero halos for debugging
15 // #ifdef _DEBUG
16 // memset(ut[0][kvol], 0, ndim*halo*sizeof(Complex_f));
17 // memset(ut[1][kvol], 0, ndim*halo*sizeof(Complex_f));
18 // #endif
19 //Was a trial field halo exchange here at one point.
20#ifdef USE_GPU
21 cuGauge_force(ut,dSdpi,beta,iu,id,dimGrid,dimBlock);
23#else
24 Complex_f *Sigma[2], *ush[2];
25 Sigma[0] = (Complex_f *)aligned_alloc(AVX,kvol*sizeof(Complex_f));
26 Sigma[1]= (Complex_f *)aligned_alloc(AVX,kvol*sizeof(Complex_f));
27 ush[0] = (Complex_f *)aligned_alloc(AVX,kvolHalo*sizeof(Complex_f));
28 ush[1] = (Complex_f *)aligned_alloc(AVX,kvolHalo*sizeof(Complex_f));
29 //Holders for directions
30 for(int mu=0; mu<ndim; mu++){
31 memset(Sigma[0],0, kvol*sizeof(Complex_f));
32 memset(Sigma[1],0, kvol*sizeof(Complex_f));
33 for(int nu=0; nu<ndim; nu++)
34 if(nu!=mu){
35 //The +ν Staple
36#pragma omp parallel for simd //aligned(ut[0],ut[1],Sigma[0],Sigma[1],iu:AVX)
37 for(int i=0;i<kvol;i++){
38 int uidm = iu[mu*kvol+i];
39 int uidn = iu[nu*kvol+i];
40 Complex_f a11=ut[0][uidm+kvolHalo*nu]*conj(ut[0][uidn+kvolHalo*mu])+\
41 ut[1][uidm+kvolHalo*nu]*conj(ut[1][uidn+kvolHalo*mu]);
42 Complex_f a12=-ut[0][uidm+kvolHalo*nu]*ut[1][uidn+kvolHalo*mu]+\
43 ut[1][uidm+kvolHalo*nu]*ut[0][uidn+kvolHalo*mu];
44 Sigma[0][i]+=a11*conj(ut[0][i+kvolHalo*nu])+a12*conj(ut[1][i+kvolHalo*nu]);
45 Sigma[1][i]+=-a11*ut[1][i+kvolHalo*nu]+a12*ut[0][i+kvolHalo*nu];
46 }
47 C_gather(ush[0], ut[0], kvol, id, nu);
48 C_gather(ush[1], ut[1], kvol, id, nu);
49#if(nproc>1)
50 CHalo_swap_dir(ush[0], 1, mu, DOWN); CHalo_swap_dir(ush[1], 1, mu, DOWN);
51#endif
52 //Next up, the -ν staple
53#pragma omp parallel for simd //aligned(ut[0],ut[1],ush[0],ush[1],Sigma[0],Sigma[1],iu,id:AVX)
54 for(int i=0;i<kvol;i++){
55 int uidm = iu[mu*kvol+i];
56 int didn = id[nu*kvol+i];
57 //uidm is correct here
58 Complex_f a11=conj(ush[0][uidm])*conj(ut[0][didn+kvolHalo*mu])-\
59 ush[1][uidm]*conj(ut[1][didn+kvolHalo*mu]);
60 Complex_f a12=-conj(ush[0][uidm])*ut[1][didn+kvolHalo*mu]-\
61 ush[1][uidm]*ut[0][didn+kvolHalo*mu];
62 Sigma[0][i]+=a11*ut[0][didn+kvolHalo*nu]-a12*conj(ut[1][didn+kvolHalo*nu]);
63 Sigma[1][i]+=a11*ut[1][didn+kvolHalo*nu]+a12*conj(ut[0][didn+kvolHalo*nu]);
64 }
65 }
66#pragma omp parallel for simd //aligned(ut[0],ut[1],Sigma[0],Sigma[1],dSdpi:AVX)
67 for(int i=0;i<kvol;i++){
68 const unsigned int ind = i+kvolHalo*mu;
69 Complex_f a11 = ut[0][ind]*Sigma[1][i]+ut[1][ind]*conj(Sigma[0][i]);
70 Complex_f a12 = ut[0][ind]*Sigma[0][i]+conj(ut[1][ind])*Sigma[1][i];
71
72 dSdpi[i+kvol*mu]=(double)(beta*cimag(a11));
73 dSdpi[i+kvol*(1*ndim+mu)]=(double)(beta*creal(a11));
74 dSdpi[i+kvol*(2*ndim+mu)]=(double)(beta*cimag(a12));
75 }
76 }
77 free(ush[0]); free(ush[1]); free(Sigma[0]); free(Sigma[1]);
78#endif
79 return 0;
80}
int C_gather(Complex_f *x, Complex_f *y, int n, unsigned int *table, unsigned int mu)
Extracts all the single precision gauge links in the direction only.
Definition su2hmc.c:291
void cuGauge_force(Complex_f *ut[2], double *dSdpi, float beta, unsigned int *iu, unsigned int *id, dim3 dimGrid, dim3 dimBlock)
Calculate the gauge contribution to the force.
Definition cuforce.cu:319

References AVX, C_gather(), CHalo_swap_dir(), cimag, Complex_f, conj(), creal, cudaDeviceSynchronise, cuGauge_force(), dimBlock, dimGrid, DOWN, kvol, kvolHalo, and ndim.

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

◆ Gauge_Update()

int Gauge_Update ( const double d,
double * pp,
Complex * ut[2],
Complex_f * ut_f[2] )

Gauge update for the integration step of the HMC.

Parameters
[in]dGauge step size
[in]ppMomentum field
[in,out]utDouble precision gauge fields
[in,out]ut_fSingle precision gauge fields
Returns
Zero on success, integer error code otherwise.
Postcondition
ut and ut_f updated in place

Definition at line 37 of file integrate.c.

37 {
38 char funcname[] = "Gauge_Update";
39#ifdef USE_GPU
41#else
42#pragma omp parallel for simd collapse(2) aligned(pp:AVX)
43 for(unsigned int i=0;i<kvol;i++)
44 for(unsigned short mu = 0; mu<ndim; mu++){
45 /*
46 * Sticking to what was in the FORTRAN for variable names.
47 * CCC for cosine SSS for sine AAA for...
48 * Re-exponentiating the force field. Can be done analytically in SU(2)
49 * using sine and cosine which is nice
50 */
51 const unsigned int ind = i+kvol*mu;
52 double AAA = d*sqrt(pp[ind]*pp[ind]\
53 +pp[i+kvol*(1*ndim+mu)]*pp[i+kvol*(1*ndim+mu)]\
54 +pp[i+kvol*(2*ndim+mu)]*pp[i+kvol*(2*ndim+mu)]);
55 double CCC = cos(AAA);
56 double SSS = d*sin(AAA)/AAA;
57 Complex a11 = CCC+I*SSS*pp[i+kvol*(2*ndim+mu)];
58 Complex a12 = pp[i+kvol*(1*ndim+mu)]*SSS + I*SSS*pp[ind];
59 //b11 and b12 are ut[0] and ut[1] terms, so we'll use ut[1] directly
60 //but use b11 for ut[0] to prevent RAW dependency
61 Complex b11 = ut[0][i+kvolHalo*mu];
62 ut[0][i+kvolHalo*mu] = a11*b11-a12*conj(ut[1][i+kvolHalo*mu]);
63 ut[1][i+kvolHalo*mu] = a11*ut[1][i+kvolHalo*mu]+a12*conj(b11);
64 }
65#endif
66 Reunitarise(ut);
67 //Get trial fields from accelerator for halo exchange
68 Trial_Exchange(ut,ut_f);
69 return 0;
70}
int Reunitarise(Complex *ut[2])
Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.
Definition su2hmc.c:342
void cuGauge_Update(const double d, double *pp, Complex *ut[2], dim3 dimGrid, dim3 dimBlock)
CUDA wrapper for the gauge update during the integration step of the HMC.
Definition cusu2hmc.cu:298
int Trial_Exchange(Complex *ut[2], Complex_f *ut_f[2])
Exchanges the trial fields.
Definition par_mpi.c:1043

References Complex, Complex_f, conj(), cuGauge_Update(), dimBlock, dimGrid, I, kvol, kvolHalo, ndim, Reunitarise(), and Trial_Exchange().

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

◆ Leapfrog()

int Leapfrog ( Complex * ut[2],
Complex_f * ut_f[2],
Complex * X0,
Complex * X1,
Complex * Phi,
double * dk[2],
float * dk_f[2],
double * dSdpi,
double * pp,
unsigned int * iu,
unsigned int * id,
Complex gamval[20],
Complex_f gamval_f[20],
const unsigned short gamin[16],
Complex * sigval,
Complex_f * sigval_f,
unsigned short * sigin,
const Complex jqq,
const float beta,
const float akappa,
const float c_sw,
const int stepl,
const float dt,
double * ancg,
int * itot,
const float proby )

Leapfrog integrator. Each trajectory step takes the form of p->p+dt/2,u->u+dt,p->p+dt/2 In practice this is implemented for the entire trajectory as p->p+dt/2,u->u+dt,p->p+dt,u->u+dt,p->p+dt,...p->p+dt/2,u->u+dt,p->p+dt/2.

Parameters
[in,out]utDouble precision colour fields
[in,out]ut_fSingle precision colour fields
[in]X0Up/down partitioned pseudofermion field
[in]X1Holder for the partitioned fermion field, then the conjugate gradient output
[in]PhiPseudofermion field
[in]dk\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\)
[in]dk_f\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\) float
[in,out]dSdpiThe force
[in,out]ppMomentum field
[in]iu,idLattice indices
[in]gaminGamma indices
[in]gamvalDouble precision gamma matrices rescaled by kappa
[in]gamval_fSingle precision gamma matrices rescaled by kappa
[in]sigval,sigval_fDouble/float Commutators of gamma matrices scaled by \(\frac{c_\text{SW}}{2}\)
[in]siginWhat element of the spinor is multiplied by row idirac each sigma matrix?
[in]c_swClover coefficient
[in]jqqDiquark source
[in]akappaHopping parameter
[in]betaInverse gauge coupling
[in]steplSteps per trajectory
[in]dtStep size
[in]ancgCounter for average conjugate gradient iterations
[in]itotTotal average conjugate gradient iterations
[in]probyTermination probability for random trajectory length
Returns
Zero on success, integer error code otherwise
Postcondition
ut, ut_f, pp and dSdpi updated in place throughout the integration

References Complex, and Complex_f.

Here is the caller graph for this function:

◆ Minus_staple()

__global__ void Kernels::Minus_staple ( const int mu,
const int nu,
unsigned int * iu,
unsigned int * id,
Complex_f * Sigma11,
Complex_f * Sigma12,
Complex_f * u11sh,
Complex_f * u12sh,
Complex_f * u11t,
Complex_f * u12t )

Calculates the staple in the negative \(\mu\) direction.

Parameters
[in]mu\(\mu\) direction
[in]nu\(\nu\) direction
[in]iu,idUpper/lower indices
[in,out]Sigma11,Sigma12Staple output
[in]u11sh,u12shGauge fields in \(\mu\) direction only
[in]u11t,u12tGauge fields
Postcondition
Staples added to Sigma11 and Sigma12

Definition at line 55 of file cuforce.cu.

56 {
57 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
58 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
59 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
60 const unsigned int threadId= blockId * bsize+(threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
61 for(unsigned int i=threadId;i<kvol;i+=gsize*bsize){
62 const unsigned int uidm = iu[mu*kvol+i];
63 const unsigned int didn = id[nu*kvol+i];
64 //uidm is correct here
65 unsigned int ind=didn+kvolHalo*mu;
66 Complex_f u11s=u11t[ind]; Complex_f u12s=u12t[ind];
67 Complex_f a11=conj(u11sh[uidm])*conj(u11s)-\
68 u12sh[uidm]*conj(u12s);
69 Complex_f a12=-conj(u11sh[uidm])*u12s-\
70 u12sh[uidm]*u11s;
71 ind=didn+kvolHalo*nu;
72 u11s=u11t[ind]; u12s=u12t[ind];
73 Sigma11[i]+=a11*u11s-a12*conj(u12s);
74 Sigma12[i]+=a11*u12s+a12*conj(u11s);
75 }
76 }

References Complex_f, conj(), kvol, and kvolHalo.

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

◆ Momentum_Update()

int Momentum_Update ( const double d,
const double * dSdpi,
double * pp )
inline

Wrapper for the momentum update during the integration step of the HMC.

Parameters
[in]dStep size
[in,out]ppMomentum field
[in]dSdpiForce field
Returns
Zero on success, integer error code otherwise.
Postcondition
pp update in place

Definition at line 71 of file integrate.c.

72{
73 const char funcname[] = "Momentum_Update";
74#ifdef USE_GPU
75 cublasDaxpy(cublas_handle,kmom, &d, dSdpi, 1, pp, 1);
77#elif defined USE_BLAS
78 cblas_daxpy(kmom, d, dSdpi, 1, pp, 1);
79#else
80#pragma omp parallel for simd
81 for(int i=0;i<kmom;i++)
82 pp[i]+=d*dSdpi[i];
83#endif
84 return 0;
85}
#define kmom
sublattice momentum sites
Definition sizes.h:193

References cublas_handle, cudaDeviceSynchronise, and kmom.

Here is the caller graph for this function:

◆ OMF2()

int OMF2 ( Complex * ut[2],
Complex_f * ut_f[2],
Complex * X0,
Complex * X1,
Complex * Phi,
double * dk[2],
float * dk_f[2],
double * dSdpi,
double * pp,
unsigned int * iu,
unsigned int * id,
Complex gamval[20],
Complex_f gamval_f[20],
const unsigned short gamin[16],
Complex * sigval,
Complex_f * sigval_f,
unsigned short * sigin,
const Complex jqq,
const float beta,
const float akappa,
const float c_sw,
const int stepl,
const float dt,
double * ancg,
int * itot,
const float proby )

OMF second order five step integrator.

Parameters
[in,out]utDouble precision colour fields
[in,out]ut_fSingle precision colour fields
[in]X0Up/down partitioned pseudofermion field
[in]X1Holder for the partitioned fermion field, then the conjugate gradient output
[in]PhiPseudofermion field
[in]dk\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\)
[in]dk_f\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\) float
[in,out]dSdpiThe force
[in,out]ppMomentum field
[in]iu,idLattice indices
[in]gaminGamma indices
[in]gamvalDouble precision gamma matrices rescaled by kappa
[in]gamval_fSingle precision gamma matrices rescaled by kappa
[in]sigval,sigval_fDouble/float Commutators of gamma matrices scaled by \(\frac{c_\text{SW}}{2}\)
[in]siginWhat element of the spinor is multiplied by row idirac each sigma matrix?
[in]c_swClover coefficient
[in]jqqDiquark source
[in]akappaHopping parameter
[in]betaInverse gauge coupling
[in]steplSteps per trajectory
[in]dtStep size
[in]ancgCounter for average conjugate gradient iterations
[in]itotTotal average conjugate gradient iterations
[in]probyTermination probability for random trajectory length
Returns
Zero on success, integer error code otherwise
Postcondition
ut, ut_f, pp and dSdpi updated in place throughout the integration

Definition at line 141 of file integrate.c.

145 {
146 const char funcname[] = "OMF2";
147 const double lambda=0.5-(pow(2.0*sqrt(326.0)+36.0,1.0/3.0)/12.0)+1.0/(6*pow(2.0*sqrt(326.0) + 36.0,1.0/3.0));
148 //const double lambda=1.0/6.0;
149 // const double lambda=0.5;
150
151 //Gauge update by half dt
152 const double dU = dt*0.5;
153
154 //Momentum updates by lambda, 2lambda and (1-2lambda) in the middle
155 const double dp= -lambda*dt;
156 const double dp2= 2.0*dp;
157 const double dpm= -(1.0-2.0*lambda)*dt;
158 //Initial step forward for p
159 //=======================
160#ifdef _DEBUG
161 if(!rank){
162 double ave_dSdpi[3];
163 Force_debug(ave_dSdpi,dSdpi);
164 printf("Before evaluating force on rank %i, dSdpi[0] %e dSdpi[1] %e dSdpi[2] %e\n", rank,ave_dSdpi[0],ave_dSdpi[1],ave_dSdpi[2]);
165 double ave_pp[3];
166 Force_debug(ave_pp,pp);
167 printf("Average momentum pp[0] %e pp[1] %e pp[2] %e\n", ave_pp[0],ave_pp[1],ave_pp[2]);
168 }
169#endif
170 Force(dSdpi, 1, rescgg,X0,X1,Phi,ut,ut_f,iu,id,gamval,gamval_f,gamin,sigval,sigval_f,sigin,dk,dk_f,jqq,akappa,beta,c_sw,ancg);
171#ifdef _DEBUG
172 if(!rank){
173 double ave_dSdpi[3];
174 Force_debug(ave_dSdpi,dSdpi);
175 printf("Average force on rank %i, dSdpi[0] %e dSdpi[1] %e dSdpi[2] %e\n", rank,ave_dSdpi[0],ave_dSdpi[1],ave_dSdpi[2]);
176 }
177#endif
178 //Initial momentum update
179 Momentum_Update(dp,dSdpi,pp);
180#ifdef _DEBUG
181 if(!rank){
182 double ave_pp[3];
183 Force_debug(ave_pp,pp);
184 printf("Average initial momentum on rank %i, pp[0] %e pp[1] %e pp[2] %e\n", rank,ave_pp[0],ave_pp[1],ave_pp[2]);
185 }
186#endif
187
188 //Main loop for classical time evolution
189 //======================================
190 bool end_traj=false; int step =1;
191 // for(int step = 1; step<=stepmax; step++){
192 do{
193#ifdef _DEBUG
194 if(!rank)
195 printf("Step: %d\n", step);
196#endif
197 //First gauge update
198 Gauge_Update(dU,pp,ut,ut_f);
199
200 //Calculate force for middle momentum update
201 Force(dSdpi, 0, rescgg,X0,X1,Phi,ut,ut_f,iu,id,gamval,gamval_f,gamin,sigval,sigval_f,sigin,dk,dk_f,jqq,akappa,beta,c_sw,ancg);
202#ifdef _DEBUG
203 if(!rank){
204 double ave_dSdpi[3];
205 Force_debug(ave_dSdpi,dSdpi);
206 printf("First force update on rank %i, dSdpi[0] %e dSdpi[1] %e dSdpi[2] %e\n", rank,ave_dSdpi[0],ave_dSdpi[1],ave_dSdpi[2]);
207 }
208#endif
209 //Now do the middle momentum update
210 Momentum_Update(dpm,dSdpi,pp);
211#ifdef _DEBUG
212 if(!rank){
213 double ave_pp[3];
214 Force_debug(ave_pp,pp);
215 printf("Average middle momentum on rank %i, pp[0] %e pp[1] %e pp[2] %e\n", rank,ave_pp[0],ave_pp[1],ave_pp[2]);
216 }
217#endif
218
219 //Second gauge update
220 Gauge_Update(dU,pp,ut,ut_f);
221
222 //Calculate force for second momentum update
223 Force(dSdpi, 0, rescgg,X0,X1,Phi,ut,ut_f,iu,id,gamval,gamval_f,gamin,sigval,sigval_f,sigin,dk,dk_f,jqq,akappa,beta,c_sw,ancg);
224#ifdef _DEBUG
225 if(!rank){
226 double ave_dSdpi[3];
227 Force_debug(ave_dSdpi,dSdpi);
228 printf("Second force update on rank %i, dSdpi[0] %e dSdpi[1] %e dSdpi[2] %e\n", rank,ave_dSdpi[0],ave_dSdpi[1],ave_dSdpi[2]);
229 }
230#endif
231
232 //if(step>=stepl*4.0/5.0 && (step>=stepl*(6.0/5.0) || Par_granf()<proby)){
233 if(step==stepl){
234 //Final momentum step
235 Momentum_Update(dp,dSdpi,pp);
236#ifdef _DEBUG
237 if(!rank){
238 double ave_pp[3];
239 Force_debug(ave_pp,pp);
240 printf("Average final momentum on rank %i, pp[0] %e pp[1] %e pp[2] %e\n", rank,ave_pp[0],ave_pp[1],ave_pp[2]);
241 }
242#endif
243 *itot+=step;
244 //Two force terms, so an extra factor of two in the average?
245 //Or leave it as it was, to get the average CG iterations per trajectory rather than force
246 *ancg/=step;
247 end_traj=true;
248 break;
249 }
250 else{
251 //Since we apply the momentum at the start and end of a step we instead apply a double step here
252 Momentum_Update(dp2,dSdpi,pp);
253#ifdef _DEBUG
254 if(!rank){
255 double ave_pp[3];
256 Force_debug(ave_pp,pp);
257 printf("Average intermediate momentum on rank %i, pp[0] %e pp[1] %e pp[2] %e\n", rank,ave_pp[0],ave_pp[1],ave_pp[2]);
258 }
259#endif
260 step++;
261 }
262 }while(!end_traj);
263 return 0;
264 }
void Force_debug(double ave_dSdpi[3], double *dSdpi)
Gets average for each generator of the Lie algebra.
Definition integrate.c:19
int Gauge_Update(const double d, double *pp, Complex *ut[2], Complex_f *ut_f[2])
Gauge update for the integration step of the HMC.
Definition integrate.c:37
int Momentum_Update(const double d, const double *dSdpi, double *pp)
Wrapper for the momentum update during the integration step of the HMC.
Definition integrate.c:71
int Force(double *dSdpi, const bool iflag, double res1, Complex *X0, Complex *X1, Complex *Phi, Complex *ut[2], Complex_f *ut_f[2], unsigned int *iu, unsigned int *id, Complex gamval[20], Complex_f gamval_f[20], const unsigned short gamin[16], Complex *sigval, Complex_f *sigval_f, unsigned short *sigin, double *dk[2], float *dk_f[2], const Complex_f jqq, const float akappa, const float beta, const float c_sw, double *ancg)
Calculates the force at each intermediate time.
Definition force.c:228
#define rescgg
Conjugate gradient residue for update.
Definition sizes.h:251

References Complex, Complex_f, Force(), Force_debug(), Gauge_Update(), Momentum_Update(), rank, and rescgg.

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

◆ OMF4()

int OMF4 ( Complex * ut[2],
Complex_f * ut_f[2],
Complex * X0,
Complex * X1,
Complex * Phi,
double * dk[2],
float * dk_f[2],
double * dSdpi,
double * pp,
unsigned int * iu,
unsigned int * id,
Complex gamval[20],
Complex_f gamval_f[20],
const unsigned short gamin[16],
Complex * sigval,
Complex_f * sigval_f,
unsigned short * sigin,
const Complex jqq,
const float beta,
const float akappa,
const float c_sw,
const int stepl,
const float dt,
double * ancg,
int * itot,
const float proby )

OMF fourth order eleven step integrator.

Parameters
[in,out]utDouble precision colour fields
[in,out]ut_fSingle precision colour fields
[in]X0Up/down partitioned pseudofermion field
[in]X1Holder for the partitioned fermion field, then the conjugate gradient output
[in]PhiPseudofermion field
[in]dk\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\)
[in]dk_f\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)e^\mu\) float
[in,out]dSdpiThe force
[in,out]ppMomentum field
[in]iu,idLattice indices
[in]gaminGamma indices
[in]gamvalDouble precision gamma matrices rescaled by kappa
[in]gamval_fSingle precision gamma matrices rescaled by kappa
[in]sigval,sigval_fDouble/float Commutators of gamma matrices scaled by \(\frac{c_\text{SW}}{2}\)
[in]siginWhat element of the spinor is multiplied by row idirac each sigma matrix?
[in]c_swClover coefficient
[in]jqqDiquark source
[in]akappaHopping parameter
[in]betaInverse gauge coupling
[in]steplSteps per trajectory
[in]dtStep size
[in]ancgCounter for average conjugate gradient iterations
[in,out]itotTotal average conjugate gradient iterations
[in]probyTermination probability for random trajectory length
Returns
Zero on success, integer error code otherwise
Postcondition
ut, ut_f, pp and dSdpi updated in place throughout the integration

References Complex, Complex_f, dimBlock, and dimGrid.

Here is the caller graph for this function:

◆ Plus_staple()

__global__ void Kernels::Plus_staple ( const int mu,
const int nu,
unsigned int * iu,
Complex_f * Sigma11,
Complex_f * Sigma12,
Complex_f * u11t,
Complex_f * u12t )

Calculates the staple in the positive \(\mu\) direction.

Parameters
[in]mu\(\mu\) direction
[in]nu\(\nu\) direction
[in]iuUpper indices
[in,out]Sigma11,Sigma12Staple output
[in]u11t,u12tGauge fields
Postcondition
Staples added to Sigma11 and Sigma12

Definition at line 23 of file cuforce.cu.

23 {
24 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
25 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
26 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
27 const unsigned int threadId= blockId * bsize+(threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
28 for(unsigned int i=threadId;i<kvol;i+=gsize*bsize){
29 const unsigned int uidm = iu[mu*kvol+i];
30 unsigned int indn=uidm+kvolHalo*nu;
31 const unsigned int uidn = iu[nu*kvol+i];
32 unsigned int indm=uidn+kvolHalo*mu;
33 Complex_f a11=u11t[indn]*conj(u11t[indm])+\
34 u12t[indn]*conj(u12t[indm]);
35 Complex_f a12=-u11t[indn]*u12t[indm]+\
36 u12t[indn]*u11t[indm];
37 indn=i+kvolHalo*nu;
38 Sigma11[i]+=a11*conj(u11t[indn])+a12*conj(u12t[indn]);
39 Sigma12[i]+=-a11*u12t[indn]+a12*u11t[indn];
40 }
41 }

References Complex_f, conj(), kvol, and kvolHalo.

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