#include namespace Grid { namespace QCD { template void PartialFractionFermion5D::Mdir (const FermionField &psi, FermionField &chi,int dir,int disp){ // this does both dag and undag but is trivial; make a common helper routing int sign = 1; int Ls = this->Ls; this->DhopDir(psi,chi,dir,disp); int nblock=(Ls-1)/2; for(int b=0;b void PartialFractionFermion5D::Meooe_internal(const FermionField &psi, FermionField &chi,int dag) { int Ls = this->Ls; int sign = dag ? (-1) : 1; if ( psi.checkerboard == Odd ) { this->DhopEO(psi,chi,DaggerNo); } else { this->DhopOE(psi,chi,DaggerNo); } int nblock=(Ls-1)/2; for(int b=0;b void PartialFractionFermion5D::Mooee_internal(const FermionField &psi, FermionField &chi,int dag) { // again dag and undag are trivially related int sign = dag ? (-1) : 1; int Ls = this->Ls; int nblock=(Ls-1)/2; for(int b=0;b void PartialFractionFermion5D::MooeeInv_internal(const FermionField &psi, FermionField &chi,int dag) { int sign = dag ? (-1) : 1; int Ls = this->Ls; FermionField tmp(psi._grid); /////////////////////////////////////////////////////////////////////////////////////// //Linv /////////////////////////////////////////////////////////////////////////////////////// int nblock=(Ls-1)/2; axpy(chi,0.0,psi,psi); // Identity piece for(int b=0;b void PartialFractionFermion5D::M_internal(const FermionField &psi, FermionField &chi,int dag) { FermionField D(psi._grid); int Ls = this->Ls; int sign = dag ? (-1) : 1; // For partial frac Hw case (b5=c5=1) chroma quirkily computes // // Conventions for partfrac appear to be a mess. // Tony's Nara lectures have // // BlockDiag( H/p_i 1 | 1 ) // ( 1 p_i H / q_i^2 | 0 ) // --------------------------------- // ( -1 0 | R +p0 H ) // //Chroma ( -2H 2sqrt(q_i) | 0 ) // (2 sqrt(q_i) 2H | 2 sqrt(p_i) ) // --------------------------------- // ( 0 -2 sqrt(p_i) | 2 R gamma_5 + p0 2H // // Edwards/Joo/Kennedy/Wenger // // Here, the "beta's" selected by chroma to scale the unphysical bulk constraint fields // incorporate the approx scale factor. This is obtained by propagating the // scale on "H" out to the off diagonal elements as follows: // // BlockDiag( H/p_i 1 | 1 ) // ( 1 p_i H / q_i^2 | 0 ) // --------------------------------- // ( -1 0 | R + p_0 H ) // // becomes: // BlockDiag( H/ sp_i 1 | 1 ) // ( 1 sp_i H / s^2q_i^2 | 0 ) // --------------------------------- // ( -1 0 | R + p_0/s H ) // // // This is implemented in Chroma by // p0' = p0/approxMax // p_i' = p_i*approxMax // q_i' = q_i*approxMax*approxMax // // After the equivalence transform is applied the matrix becomes // //Chroma ( -2H sqrt(q'_i) | 0 ) // (sqrt(q'_i) 2H | sqrt(p'_i) ) // --------------------------------- // ( 0 -sqrt(p'_i) | 2 R gamma_5 + p'0 2H // // = ( -2H sqrt(q_i)amax | 0 ) // (sqrt(q_i)amax 2H | sqrt(p_i*amax) ) // --------------------------------- // ( 0 -sqrt(p_i)*amax | 2 R gamma_5 + p0/amax 2H // this->DW(psi,D,DaggerNo); int nblock=(Ls-1)/2; for(int b=0;bmass)/(1-this->mass); //R g5 psi[Ls] + p[0] H ag5xpbg5y_ssp(chi,R*scale,psi,p[nblock]*scale/amax,D,Ls-1,Ls-1); for(int b=0;b RealD PartialFractionFermion5D::M (const FermionField &in, FermionField &out) { M_internal(in,out,DaggerNo); return norm2(out); } template RealD PartialFractionFermion5D::Mdag (const FermionField &in, FermionField &out) { M_internal(in,out,DaggerYes); return norm2(out); } template void PartialFractionFermion5D::Meooe (const FermionField &in, FermionField &out) { Meooe_internal(in,out,DaggerNo); } template void PartialFractionFermion5D::MeooeDag (const FermionField &in, FermionField &out) { Meooe_internal(in,out,DaggerYes); } template void PartialFractionFermion5D::Mooee (const FermionField &in, FermionField &out) { Mooee_internal(in,out,DaggerNo); } template void PartialFractionFermion5D::MooeeDag (const FermionField &in, FermionField &out) { Mooee_internal(in,out,DaggerYes); } template void PartialFractionFermion5D::MooeeInv (const FermionField &in, FermionField &out) { MooeeInv_internal(in,out,DaggerNo); } template void PartialFractionFermion5D::MooeeInvDag (const FermionField &in, FermionField &out) { MooeeInv_internal(in,out,DaggerYes); } // force terms; five routines; default to Dhop on diagonal template void PartialFractionFermion5D::MDeriv (GaugeField &mat,const FermionField &U,const FermionField &V,int dag) { int Ls = this->Ls; FermionField D(V._grid); int nblock=(Ls-1)/2; for(int b=0;bDhopDeriv(mat,D,V,DaggerNo); }; template void PartialFractionFermion5D::MoeDeriv(GaugeField &mat,const FermionField &U,const FermionField &V,int dag) { int Ls = this->Ls; FermionField D(V._grid); int nblock=(Ls-1)/2; for(int b=0;bDhopDerivOE(mat,D,V,DaggerNo); }; template void PartialFractionFermion5D::MeoDeriv(GaugeField &mat,const FermionField &U,const FermionField &V,int dag) { int Ls = this->Ls; FermionField D(V._grid); int nblock=(Ls-1)/2; for(int b=0;bDhopDerivEO(mat,D,V,DaggerNo); }; template void PartialFractionFermion5D::SetCoefficientsTanh(Approx::zolotarev_data *zdata,RealD scale){ SetCoefficientsZolotarev(1.0/scale,zdata); } template void PartialFractionFermion5D::SetCoefficientsZolotarev(RealD zolo_hi,Approx::zolotarev_data *zdata){ // check on degree matching // std::cout<n << " - n"<da << " -da "<db << " -db"<dn << " -dn"<dd << " -dd"<Ls; assert(Ls == (2*zdata->da -1) ); // Part frac // RealD R; R=(1+mass)/(1-mass); dw_diag = (4.0-this->M5); // std::vector p; // std::vector q; p.resize(zdata->da); q.resize(zdata->dd); for(int n=0;nda;n++){ p[n] = zdata -> alpha[n]; } for(int n=0;ndd;n++){ q[n] = -zdata -> ap[n]; } scale= part_frac_chroma_convention ? 2.0 : 1.0; // Chroma conventions annoy me amax=zolo_hi; } // Constructors template PartialFractionFermion5D::PartialFractionFermion5D(GaugeField &_Umu, GridCartesian &FiveDimGrid, GridRedBlackCartesian &FiveDimRedBlackGrid, GridCartesian &FourDimGrid, GridRedBlackCartesian &FourDimRedBlackGrid, RealD _mass,RealD M5, const ImplParams &p) : WilsonFermion5D(_Umu, FiveDimGrid, FiveDimRedBlackGrid, FourDimGrid, FourDimRedBlackGrid,M5,p), mass(_mass) { int Ls = this->Ls; assert((Ls&0x1)==1); // Odd Ls required int nrational=Ls-1; Approx::zolotarev_data *zdata = Approx::higham(1.0,nrational); // NB: chroma uses a cast to "float" for the zolotarev range(!?). // this creates a real difference in the operator which I do not like but we can replicate here // to demonstrate compatibility // RealD eps = (zolo_lo / zolo_hi); // zdata = bfm_zolotarev(eps,nrational,0); SetCoefficientsTanh(zdata,1.0); Approx::zolotarev_free(zdata); } FermOpTemplateInstantiate(PartialFractionFermion5D); } }