/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/qcd/action/fermion/FermionOperatorImpl.h Copyright (C) 2015 Author: Peter Boyle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ #pragma once NAMESPACE_BEGIN(Grid); /* Policy implementation for G-parity boundary conditions Rather than treating the gauge field as a flavored field, the Grid implementation of G-parity treats the gauge field as a regular field with complex conjugate boundary conditions. In order to ensure the second flavor interacts with the conjugate links and the first with the regular links we overload the functionality of doubleStore, whose purpose is to store the gauge field and the barrel-shifted gauge field to avoid communicating links when applying the Dirac operator, such that the double-stored field contains also a flavor index which maps to either the link or the conjugate link. This flavored field is then used by multLink to apply the correct link to a spinor. Here the first Nd-1 directions are treated as "spatial", and a twist value of 1 indicates G-parity BCs in that direction. mu=Nd-1 is assumed to be the time direction and a twist value of 1 indicates antiperiodic BCs */ template class GparityWilsonImpl : public ConjugateGaugeImpl > { public: static const int Dimension = Representation::Dimension; static const bool isFundamental = Representation::isFundamental; static const int Nhcs = Options::Nhcs; static const bool LsVectorised=false; static const bool isGparity=true; typedef ConjugateGaugeImpl< GaugeImplTypes > Gimpl; INHERIT_GIMPL_TYPES(Gimpl); typedef typename Options::_Coeff_t Coeff_t; typedef typename Options::template PrecisionMapper::LowerPrecVector SimdL; template using iImplSpinor = iVector, Ns>, Ngp>; template using iImplPropagator = iMatrix, Ns>, Ngp>; template using iImplHalfSpinor = iVector, Nhs>, Ngp>; template using iImplHalfCommSpinor = iVector, Nhcs>, Ngp>; template using iImplDoubledGaugeField = iVector >, Nds>, Ngp>; typedef iImplSpinor SiteSpinor; typedef iImplPropagator SitePropagator; typedef iImplHalfSpinor SiteHalfSpinor; typedef iImplHalfCommSpinor SiteHalfCommSpinor; typedef iImplDoubledGaugeField SiteDoubledGaugeField; typedef Lattice FermionField; typedef Lattice PropagatorField; typedef Lattice DoubledGaugeField; typedef GparityWilsonImplParams ImplParams; typedef WilsonCompressor Compressor; typedef WilsonStencil StencilImpl; typedef typename StencilImpl::View_type StencilView; ImplParams Params; GparityWilsonImpl(const ImplParams &p = ImplParams()) : Params(p){}; // provide the multiply by link that is differentiated between Gparity (with // flavour index) and non-Gparity template static accelerator_inline void multLink(_Spinor &phi, const SiteDoubledGaugeField &U, const _Spinor &chi, int mu) { assert(0); } template static accelerator_inline void multLink(_Spinor &phi, const SiteDoubledGaugeField &U, const _Spinor &chi, int mu, StencilEntry *SE, StencilView &St) { int direction = St._directions[mu]; int distance = St._distances[mu]; int ptype = St._permute_type[mu]; int sl = St._simd_layout[direction]; Coordinate icoor; #ifdef GRID_SIMT const int Nsimd =SiteDoubledGaugeField::Nsimd(); int s = acceleratorSIMTlane(Nsimd); St.iCoorFromIindex(icoor,s); int mmu = mu % Nd; auto UU0=coalescedRead(U(0)(mu)); auto UU1=coalescedRead(U(1)(mu)); //Decide whether we do a G-parity flavor twist //Note: this assumes (but does not check) that sl==1 || sl==2 i.e. max 2 SIMD lanes in G-parity dir //It also assumes (but does not check) that abs(distance) == 1 int permute_lane = (sl==1) || ((distance== 1)&&(icoor[direction]==1)) || ((distance==-1)&&(icoor[direction]==0)); permute_lane = permute_lane && SE->_around_the_world && St.parameters.twists[mmu] && mmu < Nd-1; //only if we are going around the world in a spatial direction //Apply the links int f_upper = permute_lane ? 1 : 0; int f_lower = !f_upper; mult(&phi(0),&UU0,&chi(f_upper)); mult(&phi(1),&UU1,&chi(f_lower)); #else typedef _Spinor vobj; typedef typename SiteHalfSpinor::scalar_object sobj; typedef typename SiteHalfSpinor::vector_type vector_type; vobj vtmp; sobj stmp; const int Nsimd =vector_type::Nsimd(); // Fixme X.Y.Z.T hardcode in stencil int mmu = mu % Nd; // assert our assumptions assert((distance == 1) || (distance == -1)); // nearest neighbour stencil hard code assert((sl == 1) || (sl == 2)); //If this site is an global boundary site, perform the G-parity flavor twist if ( mmu < Nd-1 && SE->_around_the_world && St.parameters.twists[mmu] ) { if ( sl == 2 ) { //Only do the twist for lanes on the edge of the physical node ExtractBuffer vals(Nsimd); extract(chi,vals); for(int s=0;s inline void multLinkField(_SpinorField & out, const DoubledGaugeField &Umu, const _SpinorField & phi, int mu) { assert(0); } template static accelerator_inline void loadLinkElement(Simd ®, ref &memory) { reg = memory; } //Poke 'poke_f0' onto flavor 0 and 'poke_f1' onto flavor 1 in direction mu of the doubled gauge field Uds inline void pokeGparityDoubledGaugeField(DoubledGaugeField &Uds, const GaugeLinkField &poke_f0, const GaugeLinkField &poke_f1, const int mu){ autoView(poke_f0_v, poke_f0, CpuRead); autoView(poke_f1_v, poke_f1, CpuRead); autoView(Uds_v, Uds, CpuWrite); thread_foreach(ss,poke_f0_v,{ Uds_v[ss](0)(mu) = poke_f0_v[ss](); Uds_v[ss](1)(mu) = poke_f1_v[ss](); }); } inline void DoubleStore(GridBase *GaugeGrid,DoubledGaugeField &Uds,const GaugeField &Umu) { conformable(Uds.Grid(),GaugeGrid); conformable(Umu.Grid(),GaugeGrid); GaugeLinkField Utmp (GaugeGrid); GaugeLinkField U (GaugeGrid); GaugeLinkField Uconj(GaugeGrid); Lattice > coor(GaugeGrid); //Here the first Nd-1 directions are treated as "spatial", and a twist value of 1 indicates G-parity BCs in that direction. //mu=Nd-1 is assumed to be the time direction and a twist value of 1 indicates antiperiodic BCs for(int mu=0;mu(Umu,mu); Uconj = conjugate(U); // Implement the isospin rotation sign on the boundary between f=1 and f=0 // This phase could come from a simple bc 1,1,-1,1 .. int neglink = GaugeGrid->GlobalDimensions()[mu]-1; if ( Params.twists[mu] ) { Uconj = where(coor==neglink,-Uconj,Uconj); } { autoView( U_v , U, CpuRead); autoView( Uconj_v , Uconj, CpuRead); autoView( Uds_v , Uds, CpuWrite); autoView( Utmp_v, Utmp, CpuWrite); thread_foreach(ss,U_v,{ Uds_v[ss](0)(mu) = U_v[ss](); Uds_v[ss](1)(mu) = Uconj_v[ss](); }); } U = adj(Cshift(U ,mu,-1)); // correct except for spanning the boundary Uconj = adj(Cshift(Uconj,mu,-1)); Utmp = U; if ( Params.twists[mu] ) { Utmp = where(coor==0,Uconj,Utmp); } { autoView( Uds_v , Uds, CpuWrite); autoView( Utmp_v, Utmp, CpuWrite); thread_foreach(ss,Utmp_v,{ Uds_v[ss](0)(mu+4) = Utmp_v[ss](); }); } Utmp = Uconj; if ( Params.twists[mu] ) { Utmp = where(coor==0,U,Utmp); } { autoView( Uds_v , Uds, CpuWrite); autoView( Utmp_v, Utmp, CpuWrite); thread_foreach(ss,Utmp_v,{ Uds_v[ss](1)(mu+4) = Utmp_v[ss](); }); } } { //periodic / antiperiodic temporal BCs int mu = Nd-1; int L = GaugeGrid->GlobalDimensions()[mu]; int Lmu = L - 1; LatticeCoordinate(coor, mu); U = PeekIndex(Umu, mu); //Get t-directed links GaugeLinkField *Upoke = &U; if(Params.twists[mu]){ //antiperiodic Utmp = where(coor == Lmu, -U, U); Upoke = &Utmp; } Uconj = conjugate(*Upoke); //second flavor interacts with conjugate links pokeGparityDoubledGaugeField(Uds, *Upoke, Uconj, mu); //Get the barrel-shifted field Utmp = adj(Cshift(U, mu, -1)); //is a forward shift! Upoke = &Utmp; if(Params.twists[mu]){ U = where(coor == 0, -Utmp, Utmp); //boundary phase Upoke = &U; } Uconj = conjugate(*Upoke); pokeGparityDoubledGaugeField(Uds, *Upoke, Uconj, mu + 4); } } inline void InsertForce4D(GaugeField &mat, FermionField &Btilde, FermionField &A, int mu) { // DhopDir provides U or Uconj depending on coor/flavour. GaugeLinkField link(mat.Grid()); // use lorentz for flavour as hack. auto tmp = TraceIndex(outerProduct(Btilde, A)); { autoView( link_v , link, CpuWrite); autoView( tmp_v , tmp, CpuRead); thread_foreach(ss,tmp_v,{ link_v[ss]() = tmp_v[ss](0, 0) + conjugate(tmp_v[ss](1, 1)); }); } PokeIndex(mat, link, mu); return; } inline void outerProductImpl(PropagatorField &mat, const FermionField &Btilde, const FermionField &A){ //mat = outerProduct(Btilde, A); assert(0); } inline void TraceSpinImpl(GaugeLinkField &mat, PropagatorField&P) { assert(0); /* auto tmp = TraceIndex(P); parallel_for(auto ss = tmp.begin(); ss < tmp.end(); ss++) { mat[ss]() = tmp[ss](0, 0) + conjugate(tmp[ss](1, 1)); } */ } inline void extractLinkField(std::vector &mat, DoubledGaugeField &Uds){ assert(0); } inline void InsertForce5D(GaugeField &mat, FermionField &Btilde, FermionField Ã, int mu) { int Ls=Btilde.Grid()->_fdimensions[0]; { GridBase *GaugeGrid = mat.Grid(); Lattice > coor(GaugeGrid); if( Params.twists[mu] ){ LatticeCoordinate(coor,mu); } autoView( mat_v , mat, AcceleratorWrite); autoView( Btilde_v , Btilde, AcceleratorRead); autoView( Atilde_v , Atilde, AcceleratorRead); accelerator_for(sss,mat.Grid()->oSites(), FermionField::vector_type::Nsimd(),{ int sU=sss; typedef decltype(coalescedRead(mat_v[sU](mu)() )) ColorMatrixType; ColorMatrixType sum; zeroit(sum); for(int s=0;s GparityWilsonImplR; // Real.. whichever prec typedef GparityWilsonImpl GparityWilsonImplF; // Float typedef GparityWilsonImpl GparityWilsonImplD; // Double //typedef GparityWilsonImpl GparityWilsonImplRL; // Real.. whichever prec //typedef GparityWilsonImpl GparityWilsonImplFH; // Float //typedef GparityWilsonImpl GparityWilsonImplDF; // Double NAMESPACE_END(Grid);