/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/qcd/action/fermion/MobiusEOFAFermion.cc Copyright (C) 2017 Author: Peter Boyle Author: Peter Boyle Author: Peter Boyle Author: paboyle Author: David Murphy 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 */ #include #include #include namespace Grid { namespace QCD { template MobiusEOFAFermion::MobiusEOFAFermion( GaugeField &_Umu, GridCartesian &FiveDimGrid, GridRedBlackCartesian &FiveDimRedBlackGrid, GridCartesian &FourDimGrid, GridRedBlackCartesian &FourDimRedBlackGrid, RealD _mq1, RealD _mq2, RealD _mq3, RealD _shift, int _pm, RealD _M5, RealD _b, RealD _c, const ImplParams &p) : AbstractEOFAFermion(_Umu, FiveDimGrid, FiveDimRedBlackGrid, FourDimGrid, FourDimRedBlackGrid, _mq1, _mq2, _mq3, _shift, _pm, _M5, _b, _c, p) { int Ls = this->Ls; RealD eps = 1.0; Approx::zolotarev_data *zdata = Approx::higham(eps, this->Ls); assert(zdata->n == this->Ls); std::cout << GridLogMessage << "MobiusEOFAFermion (b=" << _b << ",c=" << _c << ") with Ls=" << Ls << std::endl; this->SetCoefficientsTanh(zdata, _b, _c); std::cout << GridLogMessage << "EOFA parameters: (mq1=" << _mq1 << ",mq2=" << _mq2 << ",mq3=" << _mq3 << ",shift=" << _shift << ",pm=" << _pm << ")" << std::endl; Approx::zolotarev_free(zdata); if(_shift != 0.0){ SetCoefficientsPrecondShiftOps(); } else { Mooee_shift.resize(Ls, 0.0); MooeeInv_shift_lc.resize(Ls, 0.0); MooeeInv_shift_norm.resize(Ls, 0.0); MooeeInvDag_shift_lc.resize(Ls, 0.0); MooeeInvDag_shift_norm.resize(Ls, 0.0); } } /*************************************************************** /* Additional EOFA operators only called outside the inverter. /* Since speed is not essential, simple axpby-style /* implementations should be fine. /***************************************************************/ template void MobiusEOFAFermion::Omega(const FermionField& psi, FermionField& Din, int sign, int dag) { int Ls = this->Ls; RealD alpha = this->alpha; Din = zero; if((sign == 1) && (dag == 0)) { // \Omega_{+} for(int s=0; s void MobiusEOFAFermion::Dtilde(const FermionField& psi, FermionField& chi) { int Ls = this->Ls; RealD b = 0.5 * ( 1.0 + this->alpha ); RealD c = 0.5 * ( 1.0 - this->alpha ); RealD mq1 = this->mq1; for(int s=0; s void MobiusEOFAFermion::DtildeInv(const FermionField& psi, FermionField& chi){ } /*****************************************************************************************************/ template RealD MobiusEOFAFermion::M(const FermionField& psi, FermionField& chi) { int Ls = this->Ls; FermionField Din(psi._grid); this->Meooe5D(psi, Din); this->DW(Din, chi, DaggerNo); axpby(chi, 1.0, 1.0, chi, psi); this->M5D(psi, chi); return(norm2(chi)); } template RealD MobiusEOFAFermion::Mdag(const FermionField& psi, FermionField& chi) { int Ls = this->Ls; FermionField Din(psi._grid); this->DW(psi, Din, DaggerYes); this->MeooeDag5D(Din, chi); this->M5Ddag(psi, chi); axpby(chi, 1.0, 1.0, chi, psi); return(norm2(chi)); } /******************************************************************** /* Performance critical fermion operators called inside the inverter /********************************************************************/ template void MobiusEOFAFermion::M5D(const FermionField& psi, FermionField& chi) { int Ls = this->Ls; std::vector diag(Ls,1.0); std::vector upper(Ls,-1.0); upper[Ls-1] = this->mq1; std::vector lower(Ls,-1.0); lower[0] = this->mq1; // no shift term if(this->shift == 0.0){ this->M5D(psi, chi, chi, lower, diag, upper); } // fused M + shift operation else{ this->M5D_shift(psi, chi, chi, lower, diag, upper, Mooee_shift); } } template void MobiusEOFAFermion::M5Ddag(const FermionField& psi, FermionField& chi) { int Ls = this->Ls; int pm = this->pm; RealD shift = this->shift; RealD mq1 = this->mq1; RealD mq2 = this->mq2; RealD mq3 = this->mq3; // coefficients for shift operator ( = shift*\gamma_{5}*R_{5}*\Delta_{\pm}(mq2,mq3)*P_{\pm} ) Coeff_t shiftp(0.0), shiftm(0.0); if(shift != 0.0){ if(pm == 1){ shiftp = shift*(mq3-mq2); } else{ shiftm = -shift*(mq3-mq2); } } std::vector diag(Ls,1.0); std::vector upper(Ls,-1.0); upper[Ls-1] = mq1 + shiftp; std::vector lower(Ls,-1.0); lower[0] = mq1 + shiftm; #if(0) std::cout << GridLogMessage << "MobiusEOFAFermion::M5Ddag(FF&,FF&):" << std::endl; for(int i=0; i::iscomplex()) { sp[l] = PplusMat (l*istride+s1*ostride,s2); sm[l] = PminusMat(l*istride+s1*ostride,s2); } else { // if real scalar_type tmp; tmp = PplusMat (l*istride+s1*ostride,s2); sp[l] = scalar_type(tmp.real(),tmp.real()); tmp = PminusMat(l*istride+s1*ostride,s2); sm[l] = scalar_type(tmp.real(),tmp.real()); } } Matp[LLs*s2+s1] = Vp; Matm[LLs*s2+s1] = Vm; }} } FermOpTemplateInstantiate(MobiusEOFAFermion); GparityFermOpTemplateInstantiate(MobiusEOFAFermion); }}