/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/qcd/action/pseudofermion/GeneralEvenOddRationalRatio.h Copyright (C) 2015 Author: Christopher Kelly 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 */ #ifndef QCD_PSEUDOFERMION_GENERAL_EVEN_ODD_RATIONAL_RATIO_H #define QCD_PSEUDOFERMION_GENERAL_EVEN_ODD_RATIONAL_RATIO_H NAMESPACE_BEGIN(Grid); ///////////////////////////////////////////////////////// // Generic rational approximation for ratios of operators ///////////////////////////////////////////////////////// /* S_f = -log( det( [M^dag M]/[V^dag V] )^{1/inv_pow} ) = chi^dag ( [M^dag M]/[V^dag V] )^{-1/inv_pow} chi\ = chi^dag ( [V^dag V]^{-1/2} [M^dag M] [V^dag V]^{-1/2} )^{-1/inv_pow} chi\ = chi^dag [V^dag V]^{1/(2*inv_pow)} [M^dag M]^{-1/inv_pow} [V^dag V]^{1/(2*inv_pow)} chi\ S_f = chi^dag* P(V^dag*V)/Q(V^dag*V)* N(M^dag*M)/D(M^dag*M)* P(V^dag*V)/Q(V^dag*V)* chi BIG WARNING: Here V^dag V is referred to in this code as the "numerator" operator and M^dag M is the *denominator* operator. this refers to their position in the pseudofermion action, which is the *inverse* of what appears in the determinant Thus for DWF the numerator operator is the Pauli-Villars operator Here P/Q \sim R_{1/(2*inv_pow)} ~ (V^dagV)^{1/(2*inv_pow)} Here N/D \sim R_{-1/inv_pow} ~ (M^dagM)^{-1/inv_pow} */ template class GeneralEvenOddRatioRationalPseudoFermionAction : public Action { public: INHERIT_IMPL_TYPES(Impl); typedef RationalActionParams Params; Params param; RealD RefreshAction; //For action evaluation MultiShiftFunction ApproxPowerAction ; //rational approx for X^{1/inv_pow} MultiShiftFunction ApproxNegPowerAction; //rational approx for X^{-1/inv_pow} MultiShiftFunction ApproxHalfPowerAction; //rational approx for X^{1/(2*inv_pow)} MultiShiftFunction ApproxNegHalfPowerAction; //rational approx for X^{-1/(2*inv_pow)} //For the MD integration MultiShiftFunction ApproxPowerMD ; //rational approx for X^{1/inv_pow} MultiShiftFunction ApproxNegPowerMD; //rational approx for X^{-1/inv_pow} MultiShiftFunction ApproxHalfPowerMD; //rational approx for X^{1/(2*inv_pow)} MultiShiftFunction ApproxNegHalfPowerMD; //rational approx for X^{-1/(2*inv_pow)} private: FermionOperator & NumOp;// the basic operator FermionOperator & DenOp;// the basic operator FermionField PhiEven; // the pseudo fermion field for this trajectory FermionField PhiOdd; // the pseudo fermion field for this trajectory //Generate the approximation to x^{1/inv_pow} (->approx) and x^{-1/inv_pow} (-> approx_inv) by an approx_degree degree rational approximation //CG_tolerance is used to issue a warning if the approximation error is larger than the tolerance of the CG and is otherwise just stored in the MultiShiftFunction for use by the multi-shift static void generateApprox(MultiShiftFunction &approx, MultiShiftFunction &approx_inv, int inv_pow, int approx_degree, double CG_tolerance, AlgRemez &remez){ std::cout< CG_tolerance) std::cout< schurOp(numerator ? NumOp : DenOp); ConjugateGradientMultiShift msCG(MaxIter, approx); msCG(schurOp,in, out); } virtual void multiShiftInverse(bool numerator, const MultiShiftFunction &approx, const Integer MaxIter, const FermionField &in, std::vector &out_elems, FermionField &out){ SchurDifferentiableOperator schurOp(numerator ? NumOp : DenOp); ConjugateGradientMultiShift msCG(MaxIter, approx); msCG(schurOp,in, out_elems, out); } //Allow derived classes to override the gauge import virtual void ImportGauge(const GaugeField &U){ NumOp.ImportGauge(U); DenOp.ImportGauge(U); } public: // allow non-uniform tolerances void SetTolerances(std::vector action_tolerance,std::vector md_tolerance) { assert(action_tolerance.size()==ApproxPowerAction.tolerances.size()); assert( md_tolerance.size()==ApproxPowerMD.tolerances.size()); // Fix up the tolerances for(int i=0;i &_NumOp, FermionOperator &_DenOp, const Params & p ) : NumOp(_NumOp), DenOp(_DenOp), PhiOdd (_NumOp.FermionRedBlackGrid()), PhiEven(_NumOp.FermionRedBlackGrid()), param(p) { std::cout< action_tolerance(ApproxHalfPowerAction.tolerances.size(),param.action_tolerance); std::vector md_tolerance (ApproxHalfPowerMD.tolerances.size(),param.md_tolerance); SetTolerances(action_tolerance, md_tolerance); std::cout<Broadcast(0,r); if ( param.BoundsCheckFreq != 0 && (r % param.BoundsCheckFreq)==0 ) { std::cout< MdagM(DenOp); std::cout< MpvPhi_k (n_pv,NumOp.FermionRedBlackGrid()); std::vector MpvMfMpvPhi_k(n_pv,NumOp.FermionRedBlackGrid()); std::vector MfMpvPhi_k (n_f ,NumOp.FermionRedBlackGrid()); FermionField MpvPhi(NumOp.FermionRedBlackGrid()); FermionField MfMpvPhi(NumOp.FermionRedBlackGrid()); FermionField MpvMfMpvPhi(NumOp.FermionRedBlackGrid()); FermionField Y(NumOp.FermionRedBlackGrid()); GaugeField tmp(NumOp.GaugeGrid()); ImportGauge(U); std::cout< MdagM(DenOp); SchurDifferentiableOperator VdagV(NumOp); RealD ak; dSdU = Zero(); // With these building blocks // // dS/dU = // \sum_k -ak MfMpvPhi_k^dag [ dM^dag M + M^dag dM ] MfMpvPhi_k (1) // + \sum_k -ak MpvMfMpvPhi_k^\dag [ dV^dag V + V^dag dV ] MpvPhi_k (2) // -ak MpvPhi_k^dag [ dV^dag V + V^dag dV ] MpvMfMpvPhi_k (3) //(1) std::cout<