#ifndef _CK_INNER_PRODUCT_H #define _CK_INNER_PRODUCT_H #include #include #include #include #include #include CPS_START_NAMESPACE //Classes that perform the inner product of two spin-color-flavor vectors on a given (momentum-space) site //Class must have an //complex operator()(const SCFvectorPtr &l, const SCFvectorPtr &r, const int &p, const int &t) const //p is the *local* 3-momentum coordinate in canonical ordering //t is the local time coordinate //mf_Complex is the base complex type for the vectors //Output should be *double precision complex* even if the vectors are stored in single precision. Do this to avoid finite prec errors on spatial sum inline void doAccum(std::complex &to, const std::complex &from){ to += from; } #ifdef USE_GRID inline void doAccum(std::complex &to, const Grid::vComplexD &from){ to += Reduce(from); } inline void doAccum(Grid::vComplexD &to, const Grid::vComplexD &from){ to += from; } #endif //Simple inner product of a momentum-space scalar source function and a constant spin matrix //Assumed diagonal matrix in flavor space if G-parity template class SCmatrixInnerProduct{ const WilsonMatrix ≻ const SourceType &src; bool conj[2]; public: typedef SourceType InnerProductSourceType; SCmatrixInnerProduct(const WilsonMatrix &_sc, const SourceType &_src): sc(_sc), src(_src){ } void operator()(std::complex &into, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ std::complex out(0.0,0.0); for(int f=0;f<1+GJP.Gparity();f++){ // Mr std::complex tvec[4][3]; for(int s1=0;s1<4;s1++) for(int c1=0;c1<3;c1++){ tvec[s1][c1] = std::complex(0.0,0.0); for(int s2=0;s2<4;s2++) for(int c2=0;c2<3;c2++) tvec[s1][c1] += sc(s1,c1,s2,c2) * ( conj_right ? std::conj(r(s2,c2,f)) : r(s2,c2,f) ); } //l.(Mr) std::complex outf(0.0,0.0); for(int s1=0;s1<4;s1++) for(int c1=0;c1<3;c1++) outf += ( conj_left ? std::conj(l(s1,c1,f)) : l(s1,c1,f) ) * tvec[s1][c1]; out += outf; } //Multiply by momentum-space source structure into += out * src.siteComplex(p); } }; //Optimized gamma^5 inner product with unit flavor matrix template class SCg5InnerProduct{ const SourceType &src; public: typedef SourceType InnerProductSourceType; SCg5InnerProduct(const SourceType &_src): src(_src){ } void operator()(std::complex &into, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ std::complex out(0.0,0.0); for(int f=0;f<1+GJP.Gparity();f++) out += OptimizedSpinColorContract::g5(l.getPtr(f),r.getPtr(f)); into += out * src.siteComplex(p); } }; //Optimized inner product for general spin matrix //Spin matrix indexed in range (0..15) following QDP convention: integer representation of binary(n4 n3 n2 n1) for spin structure gamma1^n1 gamma2^n2 gamma3^n3 gamma4^n4 //Thus idx matrix // 0 Unit // 1 gamma1 // 2 gamma2 // 3 gamma1 gamma2 // 4 gamma3 // 5 gamma1 gamma3 // 6 gamma2 gamma3 // 7 gamma1 gamma2 gamma3 = gamma5 gamma4 // 8 gamma4 // 9 gamma1 gamma4 // 10 gamma2 gamma4 // 11 gamma1 gamma2 gamma4 = -gamma5 gamma3 // 12 gamma3 gamma4 // 13 gamma1 gamma3 gamma4 = gamma5 gamma2 // 14 gamma2 gamma3 gamma4 = -gamma5 gamma1 // 15 gamma1 gamma2 gamma3 gamma4 = gamma5 template class SCspinInnerProduct{ const SourceType &src; public: typedef SourceType InnerProductSourceType; SCspinInnerProduct(const SourceType &_src): src(_src){ } //When running with a multisrc type this returns the number of meson fields per timeslice = nSources template inline typename my_enable_if::value, int>::type mfPerTimeSlice() const{ return SourceType::nSources; } template inline typename my_enable_if::value, int>::type mfPerTimeSlice() const{ return 1; } template void operator()(AccumType &into, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ assert(!GJP.Gparity()); ComplexType out = GeneralSpinColorContractSelect::type>::doit(l.getPtr(0),r.getPtr(0)); doAccum(into,out * src.siteComplex(p)); } }; //Constant spin-color-flavor matrix source structure with position-dependent flavor matrix from source // l M N r where l,r are the vectors, M is the constant matrix and N the position-dependent //For use with GPBC template class SCFfmatSrcInnerProduct{ const SourceType &src; const SpinColorFlavorMatrix &scf; public: typedef SourceType InnerProductSourceType; SCFfmatSrcInnerProduct(const SpinColorFlavorMatrix &_scf, const SourceType &_src): scf(_scf), src(_src){ if(!GJP.Gparity()) ERR.General("SCFfmatSrcInnerProduct","SCFfmatSrcInnerProduct","Only for G-parity BCs"); } void operator()(std::complex &into, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ //Get source flavor matrix structure for this momentum site FlavorMatrix N = src.siteFmat(p); //Nr std::complex rvec[4][3][2]; for(int s1=0;s1<4;s1++) for(int c1=0;c1<3;c1++) for(int f1=0;f1<2;f1++){ rvec[s1][c1][f1] = std::complex(0.0,0.0); for(int f2=0;f2<2;f2++){ std::complex rr = ( conj_right ? std::conj(r(s1,c1,f2)) : r(s1,c1,f2) ); rvec[s1][c1][f1] += N(f1,f2) * rr; } } //lM std::complex lvec[4][3][2]; for(int s1=0;s1<4;s1++) for(int c1=0;c1<3;c1++) for(int f1=0;f1<2;f1++){ lvec[s1][c1][f1] = std::complex(0.0,0.0); for(int s2=0;s2<4;s2++) for(int c2=0;c2<3;c2++) for(int f2=0;f2<2;f2++){ std::complex ll = ( conj_left ? std::conj(l(s2,c2,f2)) : l(s2,c2,f2) ); lvec[s1][c1][f1] += ll * scf(s2,c2,f2,s1,c1,f1); } } std::complex out(0.0,0.0); for(int s1=0;s1<4;s1++) for(int c1=0;c1<3;c1++) for(int f1=0;f1<2;f1++) out += lvec[s1][c1][f1] * rvec[s1][c1][f1]; into += out; } }; template struct _siteFmatRecurse{ template static inline void doit(AccumVtype &into, const SourceType &src, const FlavorMatrixType sigma, const int p, const FlavorMatrixGeneral &lMr){ FlavorMatrixGeneral phi; src.template getSource().siteFmat(phi,p); phi.pl(sigma); doAccum(into[Idx], TransLeftTrace(lMr, phi)); _siteFmatRecurse::doit(into,src,sigma,p,lMr); } }; template struct _siteFmatRecurse{ template static inline void doit(AccumVtype &into, const SourceType &src, const FlavorMatrixType sigma, const int p, const FlavorMatrixGeneral &lMr){} }; //All of the inner products for G-parity can be separated into a part involving only the spin-color structure of the source and a part involving the flavor and smearing function. //This case class implements the flavor/smearing function part and leaves the spin-color part to the derived class template class GparityInnerProduct: public SpinColorContractPolicy{ const SourceType &src; FlavorMatrixType sigma; public: typedef SourceType InnerProductSourceType; GparityInnerProduct(const FlavorMatrixType &_sigma, const SourceType &_src): sigma(_sigma),src(_src){ } //When running with a multisrc type this returns the number of meson fields per timeslice = nSources template inline typename my_enable_if::value, int>::type mfPerTimeSlice() const{ return SourceType::nSources; } template inline typename my_enable_if::value, int>::type mfPerTimeSlice() const{ return 1; } //Single source template inline void operator()(AccumType &out, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ #ifndef MEMTEST_MODE FlavorMatrixGeneral lMr; //is vectorized this->spinColorContract(lMr,l,r); //Compute lMr[f1,f3] s3[f1,f2] phi[f2,f3] = lMr^T[f3,f1] s3[f1,f2] phi[f2,f3] FlavorMatrixGeneral phi; src.siteFmat(phi,p); phi.pl(sigma); //Do the sum over the SIMD vectorized sites doAccum(out, TransLeftTrace(lMr, phi)); #endif } //Multi source //Does out += op(l,r,p,t); template inline void operator()(std::vector &out, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ #ifndef MEMTEST_MODE FlavorMatrixGeneral lMr; //is vectorized this->spinColorContract(lMr,l,r); _siteFmatRecurse::doit(out,src,sigma,p,lMr); #endif } }; template class SCFspinflavorInnerProduct: public GparityInnerProduct >{ public: typedef SourceType InnerProductSourceType; SCFspinflavorInnerProduct(const FlavorMatrixType &_sigma, SourceType &_src): GparityInnerProduct >(_sigma,_src){} }; template struct _siteFmatRecurseShift{ template static inline void doit(AccumVtype &into, const std::vector &shifted_sources, const FlavorMatrixType sigma, const int p, const FlavorMatrixGeneral &lMr){ FlavorMatrixGeneral phi; for(int i=0;itemplate getSource().siteFmat(phi,p); phi.pl(sigma); doAccum(into[Idx+SourceType::nSources*i], TransLeftTrace(lMr, phi)); } _siteFmatRecurseShift::doit(into,shifted_sources,sigma,p,lMr); } }; template struct _siteFmatRecurseShift{ template static inline void doit(AccumVtype &into, const std::vector &shifted_sources, const FlavorMatrixType sigma, const int p, const FlavorMatrixGeneral &lMr){} }; template struct _shiftRecurse{ static void inline doit(SourceType &what, const std::vector &shift){ shiftPeriodicField( what.template getSource().getSource(), what.template getSource().getSource(), shift); _shiftRecurse::doit(what,shift); } }; template struct _shiftRecurse{ static void inline doit(SourceType &what, const std::vector &shift){} }; template class GparitySourceShiftInnerProduct: public SpinColorContractPolicy{ const SourceType &src; FlavorMatrixType sigma; std::vector< std::vector > shifts; //should be a set of 3-vectors std::vector shifted_sources; std::vector cur_shift; template inline typename my_enable_if::value, void>::type shiftTheSource(SourceType &what, const std::vector &shift){ shiftPeriodicField(what.getSource(),what.getSource(), shift); } template inline typename my_enable_if::value, void>::type shiftTheSource(SourceType &what, const std::vector &shift){ _shiftRecurse::doit(what, shift); } void shiftSource(SourceType &what, const std::vector &shift){ std::vector actual_shift(shift); for(int i=0;i<3;i++) actual_shift[i] -= cur_shift[i]; //remove current shift in process shiftTheSource(what,actual_shift); } public: typedef SourceType InnerProductSourceType; GparitySourceShiftInnerProduct(const FlavorMatrixType &_sigma, const SourceType &_src): sigma(_sigma),src(_src), shifts(0), cur_shift(3,0){ } GparitySourceShiftInnerProduct(const FlavorMatrixType &_sigma, const SourceType &_src, const std::vector< std::vector > &_shifts): sigma(_sigma),src(_src), shifts(_shifts), cur_shift(3,0){ } ~GparitySourceShiftInnerProduct(){ for(int i=0;i inline typename my_enable_if::value, int>::type mfPerTimeSlice() const{ return shifts.size() * SourceType::nSources; } //indexed by source_idx + nSources*shift_idx //When running with a single src type this returns the number of meson fields per timeslice = nshift template inline typename my_enable_if::value, int>::type mfPerTimeSlice() const{ return shifts.size(); } void setShifts(const std::vector< std::vector > &to_shifts){ shifts = to_shifts; for(int i=0;i inline typename my_enable_if::value, void>::type operator()(AccumVtype &out, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ #ifndef MEMTEST_MODE FlavorMatrixGeneral lMr; this->spinColorContract(lMr,l,r); FlavorMatrixGeneral phi; for(int i=0;isiteFmat(phi,p); phi.pl(sigma); doAccum(out[i],TransLeftTrace(lMr, phi)); } #endif } //Multi src. output indexed by source_idx + nSources*shift_idx template inline typename my_enable_if::value, void>::type operator()(AccumVtype &out, const SCFvectorPtr &l, const SCFvectorPtr &r, const int p, const int t) const{ #ifndef MEMTEST_MODE FlavorMatrixGeneral lMr; this->spinColorContract(lMr,l,r); _siteFmatRecurseShift::doit(out,shifted_sources,sigma,p,lMr); #endif } }; CPS_END_NAMESPACE #endif