#ifndef CPS_FIELD_H #define CPS_FIELD_H #include #include #include #include #include CPS_START_NAMESPACE typedef std::complex ComplexF; typedef std::complex ComplexD; //A wrapper for a CPS-style field. Most functionality is generic so it can do quite a lot of cool things template< typename SiteType, int SiteSize, typename DimensionPolicy, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfield: public DimensionPolicy, public FlavorPolicy, public AllocPolicy{ SiteType* f; protected: int sites; //number of Euclidean sites int flavors; //number of flavors int fsites; //number of generalized sites (including flavor) int fsize; //number of SiteType in the array = SiteSize * fsites void alloc(){ this->_alloc((void**)&f, fsize*sizeof(SiteType)); } void freemem(){ this->_free((void*)f); } public: enum { FieldSiteSize = SiteSize }; typedef SiteType FieldSiteType; typedef DimensionPolicy FieldDimensionPolicy; typedef FlavorPolicy FieldFlavorPolicy; typedef AllocPolicy FieldAllocPolicy; typedef typename DimensionPolicy::ParamType InputParamType; CPSfield(const InputParamType ¶ms): DimensionPolicy(params){ this->setFlavors(flavors); //from FlavorPolicy this->setSites(sites,fsites,flavors); //from DimensionPolicy fsize = fsites * SiteSize; alloc(); } CPSfield(const CPSfield &r): fsize(r.fsize), flavors(r.flavors),sites(r.sites),fsites(r.fsites), DimensionPolicy(r){ alloc(); memcpy(f,r.f,sizeof(SiteType) * fsize); } //Copy from external pointer. Make sure you set the params and policies correctly because it has no way of bounds checking CPSfield(SiteType const* copyme, const InputParamType ¶ms): DimensionPolicy(params){ this->setFlavors(flavors); //from FlavorPolicy this->setSites(sites,fsites,flavors); //from DimensionPolicy fsize = fsites * SiteSize; alloc(); memcpy(f,copyme,sizeof(SiteType) * fsize); } //Set the field to zero void zero(){ memset(f, 0, sizeof(SiteType) * fsize); } CPSfield &operator=(const CPSfield &r){ static_cast(*this) = r; //copy policy info sites = r.sites; fsites = r.fsites; flavors = r.flavors; int old_fsize = fsize; fsize = r.fsize; if(fsize != old_fsize){ freemem(); alloc(); } memcpy(f,r.f,sizeof(SiteType) * fsize); return *this; } static std::size_t byte_size(const InputParamType ¶ms){ CPSfield tmp(params); //doesn't allocate std::size_t out = SiteSize * sizeof(SiteType); return tmp.nfsites() * out; } std::size_t byte_size() const{ return this->nfsites() * SiteSize * sizeof(SiteType); } //Set each element to a uniform random number in the specified range. //WARNING: Uses only the current RNG in LRG, and does not change this based on site. This is therefore only useful for testing* void testRandom(const Float hi = 0.5, const Float lo = -0.5); inline const int nsites() const{ return sites; } inline const int nflavors() const{ return flavors; } inline const int nfsites() const{ return fsites; } //number of generalized sites including flavor //Number of SiteType per site inline const int siteSize() const{ return SiteSize; } //Number of SiteType in field inline const int size() const{ return fsize; } //Accessors inline SiteType* ptr(){ return f; } inline SiteType const* ptr() const{ return f; } //Accessors *do not check bounds* //int fsite is the linearized N-dimensional site/flavorcoordinate with the mapping specified by the policy class inline int fsite_offset(const int fsite) const{ return SiteSize*fsite; } inline SiteType* fsite_ptr(const int fsite){ //fsite is in the internal flavor/Euclidean mapping of the DimensionPolicy. Use only if you know what you are doing return f + SiteSize*fsite; } inline SiteType const* fsite_ptr(const int fsite) const{ //fsite is in the internal flavor/Euclidean mapping of the DimensionPolicy. Use only if you know what you are doing return f + SiteSize*fsite; } //int site is the linearized N-dimension Euclidean coordinate with mapping specified by the policy class inline int site_offset(const int site, const int flav = 0) const{ return SiteSize*this->siteFsiteConvert(site,flav); } inline int site_offset(const int x[], const int flav = 0) const{ return SiteSize*this->fsiteMap(x,flav); } inline SiteType* site_ptr(const int site, const int flav = 0){ //site is in the internal Euclidean mapping of the DimensionPolicy return f + SiteSize*this->siteFsiteConvert(site,flav); } inline SiteType* site_ptr(const int x[], const int flav = 0){ return f + SiteSize*this->fsiteMap(x,flav); } inline SiteType const* site_ptr(const int site, const int flav = 0) const{ //site is in the internal Euclidean mapping of the DimensionPolicy return f + SiteSize*this->siteFsiteConvert(site,flav); } inline SiteType const* site_ptr(const int x[], const int flav = 0) const{ return f + SiteSize*this->fsiteMap(x,flav); } inline int flav_offset() const{ return SiteSize*this->fsiteFlavorOffset(); } //pointer offset between flavors //Set this field to the average of this and a second field, r void average(const CPSfield &r, const bool ¶llel = true); //Self destruct initialized (no more sfree!!) virtual ~CPSfield(){ freemem(); } //Import an export field with arbitrary DimensionPolicy (must have same Euclidean dimension!) and precision. Must have same SiteSize and FlavorPolicy template< typename extSiteType, typename extDimPol, typename extFlavPol, typename extAllocPol> void importField(const CPSfield &r); template< typename extSiteType, typename extDimPol, typename extFlavPol, typename extAllocPol> void exportField(CPSfield &r) const; bool equals(const CPSfield &r) const{ for(int i=0;i::value \ && is_double_or_float::value \ && _equal::value \ && _equal::value template bool equals(const extField &r, typename my_enable_if::type tolerance) const{ for(int i=0;i tolerance) return false; } return true; } #undef CONDITION #define CONDITION is_complex_double_or_float::value \ && is_complex_double_or_float::value \ && _equal::value \ && _equal::value template bool equals(const extField &r, typename my_enable_if::type tolerance, bool verbose = false) const{ for(int i=0;i tolerance || fabs(f[i].imag() - r.f[i].imag()) > tolerance ){ if(verbose && !UniqueID()){ int rem = i; int s = rem % SiteSize; rem /= SiteSize; int x = rem % sites; rem /= sites; int flav = rem; int coor[DimensionPolicy::EuclideanDimension]; this->siteUnmap(x,coor); std::ostringstream os; for(int a=0;a::type , grid_vector_complex_mark>::value \ && _equal::type,grid_vector_complex_mark>::value \ && _equal::value \ && _equal::value template bool equals(const extField &r, typename my_enable_if::type tolerance, bool verbose = false) const{ typedef typename SiteType::scalar_type ThisScalarType; typedef typename extField::FieldSiteType::scalar_type ThatScalarType; typedef typename DimensionPolicy::EquivalentScalarPolicy ScalarDimPol; NullObject null_obj; CPSfield tmp_this(null_obj); CPSfield tmp_that(null_obj); tmp_this.importField(*this); tmp_that.importField(r); return tmp_this.equals(tmp_that,tolerance,verbose); } #undef CONDITION #endif double norm2() const; #ifdef USE_GRID //Import for Grid Lattice types template void importGridField(const GridField &grid); template void exportGridField(GridField &grid) const; #endif CPSfield & operator+=(const CPSfield &r){ #pragma omp parallel for for(int i=0;iCPSfield::operator+=(r); return *this; \ } \ DerivedType & operator-=(const DerivedType &r){ \ this->CPSfield::operator-=(r); return *this; \ } \ DerivedType operator+(const DerivedType &r) const{ \ DerivedType out(*this); out += r; \ return out; \ } \ DerivedType operator-(const DerivedType &r){ \ DerivedType out(*this); out -= r; \ return out; \ } template< typename mf_Complex, typename DimensionPolicy, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion: public CPSfield{ protected: void gauge_fix_site_op(const int x4d[], const int &f, Lattice &lat,const bool dagger = false); static void getMomentumUnits(double punits[3]); //Apply the phase exp(-ip.x) to each site of this vector, where p is a *three momentum* //The units of the momentum are 2pi/L for periodic BCs, pi/L for antiperiodic BCs and pi/2L for G-parity BCs //x_lcl is the site in node lattice coords void apply_phase_site_op(const int x_lcl[], const int &flav, const int p[], const double punits[]); public: INHERIT_TYPEDEFS(CPSfield); CPSfermion(): CPSfield(NullObject()){} //default constructor won't compile if policies need arguments CPSfermion(const InputParamType ¶ms): CPSfield(params){} CPSfermion(const CPSfermion &r): CPSfield(r){} }; template struct GaugeFix3DInfo{}; template<> struct GaugeFix3DInfo{ typedef int InfoType; }; template<> struct GaugeFix3DInfo >{ typedef int InfoType; }; template<> struct GaugeFix3DInfo >{ typedef std::pair InfoType; //time, flavor (latter ignored if no GPBC) }; template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion3D: public CPSfermion{ void apply_phase_site_op(const int &sf,const int p[],double punits[]); template< typename mf_Complex2, typename FlavorPolicy2> friend struct _ferm3d_gfix_impl; public: INHERIT_TYPEDEFS(CPSfermion); CPSfermion3D(): CPSfermion(){} CPSfermion3D(const CPSfermion3D &r): CPSfermion(r){} //Apply gauge fixing matrices to the field //Because this is a 3d field we must also provide a time coordinate. //If the field is one flavor we must also provide the flavor //We make the field_info type dynamic based on the FlavorPolicy for this reason (pretty cool!) void gaugeFix(Lattice &lat, const typename GaugeFix3DInfo::InfoType &field_info, const bool ¶llel); //Apply the phase exp(-ip.x) to each site of this vector, where p is a *three momentum* //The units of the momentum are 2pi/L for periodic BCs, pi/L for antiperiodic BCs and pi/2L for G-parity BCs void applyPhase(const int p[], const bool ¶llel); DEFINE_ADDSUB_DERIVED(CPSfermion3D); }; template< typename mf_Complex, typename DimensionPolicy = FourDpolicy, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion4D: public CPSfermion{ typename my_enable_if::type dummy; void gauge_fix_site_op(int fi, Lattice &lat, const bool dagger = false); void apply_phase_site_op(int sf,const int p[],double punits[]); public: INHERIT_TYPEDEFS(CPSfermion); CPSfermion4D(): CPSfermion(){} CPSfermion4D(const InputParamType ¶ms): CPSfermion(params){} CPSfermion4D(const CPSfermion4D &r): CPSfermion(r){} //Apply gauge fixing matrices to the field. //NOTE: This does not work correctly for GPBC and FlavorPolicy==FixedFlavorPolicy<1> because we need to provide the flavor //that this field represents to obtain the gauge-fixing matrix. I fixed this for CPSfermion3D and a similar implementation will work here //dagger = true applied V^\dagger to the vector to invert a previous gauge fix void gaugeFix(Lattice &lat, const bool parallel, const bool dagger = false); //Apply the phase exp(-ip.x) to each site of this vector, where p is a *three momentum* //The units of the momentum are 2pi/L for periodic BCs, pi/L for antiperiodic BCs and pi/2L for G-parity BCs void applyPhase(const int p[], const bool ¶llel); //Set the real and imaginary parts to uniform random numbers drawn from the appropriate local RNGs void setUniformRandom(const Float &hi = 0.5, const Float &lo = -0.5); void setGaussianRandom(); DEFINE_ADDSUB_DERIVED(CPSfermion4D); }; template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion5D: public CPSfield{ public: INHERIT_TYPEDEFS(CPSfield); CPSfermion5D(): CPSfield(NullObject()){} CPSfermion5D(const CPSfermion5D &r): CPSfield(r){} #ifdef USE_BFM private: template void impexFermion(Fermion_t bfm_field, const int cb, const int do_import, bfm_qdp &dwf){ if(this->flavors == 2) assert(dwf.gparity); const int sc_incr = dwf.nsimd() * 2; //stride between spin-color indices FloatExt * bb = (FloatExt*)bfm_field; typedef typename mf_Complex::value_type mf_Float; #pragma omp parallel for for(int fs=0;fsfsites;fs++){ int x[5], f; this->fsiteUnmap(fs); if( (x[0]+x[1]+x[2]+x[3] + (dwf.precon_5d ? x[4] : 0)) % 2 == cb){ mf_Float* cps_base = (mf_Float*)this->fsite_ptr(fs); int bidx_off = dwf.gparity ? dwf.bagel_gparity_idx5d(x, x[4], 0, 0, 12, 1, f) : dwf.bagel_idx5d(x, x[4], 0, 0, 12, 1); FloatExt * bfm_base = bb + bidx_off; for(int i=0;i<12;i++) for(int reim=0;reim<2;reim++) if(do_import) *(cps_base + 2*i + reim) = *(bfm_base + 2*sc_incr*i + reim); else *(bfm_base + 2*sc_incr*i + reim) = *(cps_base + 2*i + reim); } } } public: enum { FieldSiteSize = 12 }; template void importFermion(const Fermion_t bfm_field, const int cb, bfm_qdp &dwf){ impexFermion(const_cast(bfm_field), cb, 1, dwf); } template void exportFermion(const Fermion_t bfm_field, const int cb, bfm_qdp &dwf) const{ const_cast*>(this)->impexFermion(bfm_field, cb, 0, dwf); } #endif void setGaussianRandom(); DEFINE_ADDSUB_DERIVED(CPSfermion5D); }; template< typename mf_Complex, typename DimensionPolicy = FourDpolicy, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPScomplex4D: public CPSfield{ typename my_enable_if::type dummy; public: INHERIT_TYPEDEFS(CPSfield); CPScomplex4D(): CPSfield(NullObject()){} CPScomplex4D(const InputParamType ¶ms): CPSfield(params){} CPScomplex4D(const CPScomplex4D &r): CPSfield(r){} //Make a random complex scalar field of type void setRandom(const RandomType &type); //Set the real and imaginary parts to uniform random numbers drawn from the appropriate local RNGs void setUniformRandom(const Float &hi = 0.5, const Float &lo = -0.5); DEFINE_ADDSUB_DERIVED(CPScomplex4D); }; //3d complex number field template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPScomplexSpatial: public CPSfield{ public: INHERIT_TYPEDEFS(CPSfield); CPScomplexSpatial(): CPSfield(NullObject()){} CPScomplexSpatial(const CPScomplexSpatial &r): CPSfield(r){} DEFINE_ADDSUB_DERIVED(CPScomplexSpatial); }; //Lattice-spanning 'global' 3d complex field template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSglobalComplexSpatial: public CPSfield{ template< typename _mf_Complex, typename _FlavorPolicy, typename _AllocPolicy, typename extComplex, typename extDimPolicy, typename extAllocPolicy, typename complex_class, int extEuclDim> friend struct _CPSglobalComplexSpatial_scatter_impl; public: INHERIT_TYPEDEFS(CPSfield); CPSglobalComplexSpatial(): CPSfield(NullObject()){} CPSglobalComplexSpatial(const CPSglobalComplexSpatial &r): CPSfield(r){} //Perform the FFT void fft(); //Scatter to a local field template void scatter(CPSfield &to) const; DEFINE_ADDSUB_DERIVED(CPSglobalComplexSpatial); }; //This field contains an entire row of sub-lattices along a particular dimension. Every node along that row contains an identical copy template< typename SiteType, int SiteSize, typename DimensionPolicy, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfieldGlobalInOneDir: public CPSfield{ public: INHERIT_TYPEDEFS(CPSfield); CPSfieldGlobalInOneDir(const int &dir): CPSfield(dir){} CPSfieldGlobalInOneDir(const CPSfieldGlobalInOneDir &r): CPSfield(r){} //Gather up the row. Involves internode communication template void gather(const CPSfield &from); //Scatter back out. Involves no communication template void scatter(CPSfield &to) const; //Perform a fast Fourier transform along the principal direction. It currently assumes the DimensionPolicy has the sites mapped in canonical ordering void fft(const bool inverse_transform = false); DEFINE_ADDSUB_DERIVED(CPSfieldGlobalInOneDir); }; template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion4DglobalInOneDir: public CPSfieldGlobalInOneDir{ public: INHERIT_TYPEDEFS(CPSfieldGlobalInOneDir); CPSfermion4DglobalInOneDir(const int &dir): CPSfieldGlobalInOneDir(dir){} CPSfermion4DglobalInOneDir(const CPSfermion4DglobalInOneDir &r): CPSfieldGlobalInOneDir(r){} DEFINE_ADDSUB_DERIVED(CPSfermion4DglobalInOneDir); }; template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion3DglobalInOneDir: public CPSfieldGlobalInOneDir{ public: INHERIT_TYPEDEFS(CPSfieldGlobalInOneDir); CPSfermion3DglobalInOneDir(const int &dir): CPSfieldGlobalInOneDir(dir){} CPSfermion3DglobalInOneDir(const CPSfermion3DglobalInOneDir &r): CPSfieldGlobalInOneDir(r){} DEFINE_ADDSUB_DERIVED(CPSfermion3DglobalInOneDir); }; ////////Checkerboarded types///////////// template< typename mf_Complex, typename CBpolicy, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion5Dprec: public CPSfield,FlavorPolicy,AllocPolicy>{ public: INHERIT_TYPEDEFS(CPSfield,FlavorPolicy,AllocPolicy>); CPSfermion5Dprec(): CPSfield,FlavorPolicy,AllocPolicy>(NullObject()){} CPSfermion5Dprec(const CPSfermion5Dprec &r): CPSfield,FlavorPolicy,AllocPolicy>(r){} DEFINE_ADDSUB_DERIVED(CPSfermion5Dprec); }; template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion5Dcb4Deven: public CPSfermion5Dprec,FlavorPolicy,AllocPolicy>{ public: INHERIT_TYPEDEFS(CPSfermion5Dprec,FlavorPolicy,AllocPolicy>); CPSfermion5Dcb4Deven(): CPSfermion5Dprec,FlavorPolicy,AllocPolicy>(){} CPSfermion5Dcb4Deven(const CPSfermion5Dcb4Deven &r): CPSfermion5Dprec,FlavorPolicy,AllocPolicy>(r){} DEFINE_ADDSUB_DERIVED(CPSfermion5Dcb4Deven); }; template< typename mf_Complex, typename FlavorPolicy = DynamicFlavorPolicy, typename AllocPolicy = StandardAllocPolicy> class CPSfermion5Dcb4Dodd: public CPSfermion5Dprec,FlavorPolicy,AllocPolicy>{ public: INHERIT_TYPEDEFS(CPSfermion5Dprec,FlavorPolicy,AllocPolicy>); CPSfermion5Dcb4Dodd(): CPSfermion5Dprec,FlavorPolicy,AllocPolicy>(){} CPSfermion5Dcb4Dodd(const CPSfermion5Dcb4Dodd &r): CPSfermion5Dprec,FlavorPolicy,AllocPolicy>(r){} DEFINE_ADDSUB_DERIVED(CPSfermion5Dcb4Dodd); }; #include CPS_END_NAMESPACE #endif