mirror of
https://github.com/paboyle/Grid.git
synced 2024-11-10 07:55:35 +00:00
Merge branch 'feature/dirichlet-gparity' of https://github.com/paboyle/Grid into feature/dirichlet-gparity
This commit is contained in:
commit
4df1e0987f
@ -37,6 +37,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
// These can move into a params header and be given MacroMagic serialisation
|
// These can move into a params header and be given MacroMagic serialisation
|
||||||
struct GparityWilsonImplParams {
|
struct GparityWilsonImplParams {
|
||||||
Coordinate twists;
|
Coordinate twists;
|
||||||
|
//mu=Nd-1 is assumed to be the time direction and a twist value of 1 indicates antiperiodic BCs
|
||||||
GparityWilsonImplParams() : twists(Nd, 0) {};
|
GparityWilsonImplParams() : twists(Nd, 0) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,7 +67,8 @@ struct StaggeredImplParams {
|
|||||||
RealD, mdtolerance,
|
RealD, mdtolerance,
|
||||||
int, degree,
|
int, degree,
|
||||||
int, precision,
|
int, precision,
|
||||||
int, BoundsCheckFreq);
|
int, BoundsCheckFreq,
|
||||||
|
RealD, BoundsCheckTol);
|
||||||
|
|
||||||
// MaxIter and tolerance, vectors??
|
// MaxIter and tolerance, vectors??
|
||||||
|
|
||||||
@ -78,7 +80,8 @@ struct StaggeredImplParams {
|
|||||||
int _degree = 10,
|
int _degree = 10,
|
||||||
int _precision = 64,
|
int _precision = 64,
|
||||||
int _BoundsCheckFreq=20,
|
int _BoundsCheckFreq=20,
|
||||||
RealD mdtol = 1.0e-6)
|
RealD mdtol = 1.0e-6,
|
||||||
|
double _BoundsCheckTol=1e-6)
|
||||||
: lo(_lo),
|
: lo(_lo),
|
||||||
hi(_hi),
|
hi(_hi),
|
||||||
MaxIter(_maxit),
|
MaxIter(_maxit),
|
||||||
@ -86,9 +89,52 @@ struct StaggeredImplParams {
|
|||||||
mdtolerance(mdtol),
|
mdtolerance(mdtol),
|
||||||
degree(_degree),
|
degree(_degree),
|
||||||
precision(_precision),
|
precision(_precision),
|
||||||
BoundsCheckFreq(_BoundsCheckFreq){};
|
BoundsCheckFreq(_BoundsCheckFreq),
|
||||||
|
BoundsCheckTol(_BoundsCheckTol){};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*Action parameters for the generalized rational action
|
||||||
|
The approximation is for (M^dag M)^{1/inv_pow}
|
||||||
|
where inv_pow is the denominator of the fractional power.
|
||||||
|
Default inv_pow=2 for square root, making this equivalent to
|
||||||
|
the OneFlavourRational action
|
||||||
|
*/
|
||||||
|
struct RationalActionParams : Serializable {
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(RationalActionParams,
|
||||||
|
int, inv_pow,
|
||||||
|
RealD, lo, //low eigenvalue bound of rational approx
|
||||||
|
RealD, hi, //high eigenvalue bound of rational approx
|
||||||
|
int, MaxIter, //maximum iterations in msCG
|
||||||
|
RealD, action_tolerance, //msCG tolerance in action evaluation
|
||||||
|
int, action_degree, //rational approx tolerance in action evaluation
|
||||||
|
RealD, md_tolerance, //msCG tolerance in MD integration
|
||||||
|
int, md_degree, //rational approx tolerance in MD integration
|
||||||
|
int, precision, //precision of floating point arithmetic
|
||||||
|
int, BoundsCheckFreq); //frequency the approximation is tested (with Metropolis degree/tolerance); 0 disables the check
|
||||||
|
// constructor
|
||||||
|
RationalActionParams(int _inv_pow = 2,
|
||||||
|
RealD _lo = 0.0,
|
||||||
|
RealD _hi = 1.0,
|
||||||
|
int _maxit = 1000,
|
||||||
|
RealD _action_tolerance = 1.0e-8,
|
||||||
|
int _action_degree = 10,
|
||||||
|
RealD _md_tolerance = 1.0e-8,
|
||||||
|
int _md_degree = 10,
|
||||||
|
int _precision = 64,
|
||||||
|
int _BoundsCheckFreq=20)
|
||||||
|
: inv_pow(_inv_pow),
|
||||||
|
lo(_lo),
|
||||||
|
hi(_hi),
|
||||||
|
MaxIter(_maxit),
|
||||||
|
action_tolerance(_action_tolerance),
|
||||||
|
action_degree(_action_degree),
|
||||||
|
md_tolerance(_md_tolerance),
|
||||||
|
md_degree(_md_degree),
|
||||||
|
precision(_precision),
|
||||||
|
BoundsCheckFreq(_BoundsCheckFreq){};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,13 +65,65 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
X=X-Y;
|
X=X-Y;
|
||||||
RealD Nd = norm2(X);
|
RealD Nd = norm2(X);
|
||||||
std::cout << "************************* "<<std::endl;
|
std::cout << "************************* "<<std::endl;
|
||||||
std::cout << " noise = "<<Nx<<std::endl;
|
std::cout << " | noise |^2 = "<<Nx<<std::endl;
|
||||||
std::cout << " (MdagM^-1/2)^2 noise = "<<Nz<<std::endl;
|
std::cout << " | (MdagM^-1/2)^2 noise |^2 = "<<Nz<<std::endl;
|
||||||
std::cout << " MdagM (MdagM^-1/2)^2 noise = "<<Ny<<std::endl;
|
std::cout << " | MdagM (MdagM^-1/2)^2 noise |^2 = "<<Ny<<std::endl;
|
||||||
std::cout << " noise - MdagM (MdagM^-1/2)^2 noise = "<<Nd<<std::endl;
|
std::cout << " | noise - MdagM (MdagM^-1/2)^2 noise |^2 = "<<Nd<<std::endl;
|
||||||
|
std::cout << " | noise - MdagM (MdagM^-1/2)^2 noise|/|noise| = " << std::sqrt(Nd/Nx) << std::endl;
|
||||||
std::cout << "************************* "<<std::endl;
|
std::cout << "************************* "<<std::endl;
|
||||||
assert( (std::sqrt(Nd/Nx)<tol) && " InverseSqrtBoundsCheck ");
|
assert( (std::sqrt(Nd/Nx)<tol) && " InverseSqrtBoundsCheck ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For a HermOp = M^dag M, check the approximation of HermOp^{-1/inv_pow}
|
||||||
|
by computing |X - HermOp * [ Hermop^{-1/inv_pow} ]^{inv_pow} X| < tol
|
||||||
|
for noise X (aka GaussNoise).
|
||||||
|
ApproxNegPow should be the rational approximation for X^{-1/inv_pow}
|
||||||
|
*/
|
||||||
|
template<class Field> void InversePowerBoundsCheck(int inv_pow,
|
||||||
|
int MaxIter,double tol,
|
||||||
|
LinearOperatorBase<Field> &HermOp,
|
||||||
|
Field &GaussNoise,
|
||||||
|
MultiShiftFunction &ApproxNegPow)
|
||||||
|
{
|
||||||
|
GridBase *FermionGrid = GaussNoise.Grid();
|
||||||
|
|
||||||
|
Field X(FermionGrid);
|
||||||
|
Field Y(FermionGrid);
|
||||||
|
Field Z(FermionGrid);
|
||||||
|
|
||||||
|
Field tmp1(FermionGrid), tmp2(FermionGrid);
|
||||||
|
|
||||||
|
X=GaussNoise;
|
||||||
|
RealD Nx = norm2(X);
|
||||||
|
|
||||||
|
ConjugateGradientMultiShift<Field> msCG(MaxIter,ApproxNegPow);
|
||||||
|
|
||||||
|
tmp1 = X;
|
||||||
|
|
||||||
|
Field* in = &tmp1;
|
||||||
|
Field* out = &tmp2;
|
||||||
|
for(int i=0;i<inv_pow;i++){ //apply [ Hermop^{-1/inv_pow} ]^{inv_pow} X = HermOp^{-1} X
|
||||||
|
msCG(HermOp, *in, *out); //backwards conventions!
|
||||||
|
if(i!=inv_pow-1) std::swap(in, out);
|
||||||
|
}
|
||||||
|
Z = *out;
|
||||||
|
|
||||||
|
RealD Nz = norm2(Z);
|
||||||
|
|
||||||
|
HermOp.HermOp(Z,Y);
|
||||||
|
RealD Ny = norm2(Y);
|
||||||
|
|
||||||
|
X=X-Y;
|
||||||
|
RealD Nd = norm2(X);
|
||||||
|
std::cout << "************************* "<<std::endl;
|
||||||
|
std::cout << " | noise |^2 = "<<Nx<<std::endl;
|
||||||
|
std::cout << " | (MdagM^-1/" << inv_pow << ")^" << inv_pow << " noise |^2 = "<<Nz<<std::endl;
|
||||||
|
std::cout << " | MdagM (MdagM^-1/" << inv_pow << ")^" << inv_pow << " noise |^2 = "<<Ny<<std::endl;
|
||||||
|
std::cout << " | noise - MdagM (MdagM^-1/" << inv_pow << ")^" << inv_pow << " noise |^2 = "<<Nd<<std::endl;
|
||||||
|
std::cout << " | noise - MdagM (MdagM^-1/" << inv_pow << ")^" << inv_pow << " noise |/| noise | = "<<std::sqrt(Nd/Nx)<<std::endl;
|
||||||
|
std::cout << "************************* "<<std::endl;
|
||||||
|
assert( (std::sqrt(Nd/Nx)<tol) && " InversePowerBoundsCheck ");
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
@ -44,6 +44,10 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
// Exact one flavour implementation of DWF determinant ratio //
|
// Exact one flavour implementation of DWF determinant ratio //
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Note: using mixed prec CG for the heatbath solver in this action class will not work
|
||||||
|
// because the L, R operators must have their shift coefficients updated throughout the heatbath step
|
||||||
|
// You will find that the heatbath solver simply won't converge.
|
||||||
|
// To use mixed precision here use the ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction variant below
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
class ExactOneFlavourRatioPseudoFermionAction : public Action<typename Impl::GaugeField>
|
class ExactOneFlavourRatioPseudoFermionAction : public Action<typename Impl::GaugeField>
|
||||||
{
|
{
|
||||||
@ -57,37 +61,60 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
bool use_heatbath_forecasting;
|
bool use_heatbath_forecasting;
|
||||||
AbstractEOFAFermion<Impl>& Lop; // the basic LH operator
|
AbstractEOFAFermion<Impl>& Lop; // the basic LH operator
|
||||||
AbstractEOFAFermion<Impl>& Rop; // the basic RH operator
|
AbstractEOFAFermion<Impl>& Rop; // the basic RH operator
|
||||||
SchurRedBlackDiagMooeeSolve<FermionField> SolverHB;
|
SchurRedBlackDiagMooeeSolve<FermionField> SolverHBL;
|
||||||
|
SchurRedBlackDiagMooeeSolve<FermionField> SolverHBR;
|
||||||
SchurRedBlackDiagMooeeSolve<FermionField> SolverL;
|
SchurRedBlackDiagMooeeSolve<FermionField> SolverL;
|
||||||
SchurRedBlackDiagMooeeSolve<FermionField> SolverR;
|
SchurRedBlackDiagMooeeSolve<FermionField> SolverR;
|
||||||
SchurRedBlackDiagMooeeSolve<FermionField> DerivativeSolverL;
|
SchurRedBlackDiagMooeeSolve<FermionField> DerivativeSolverL;
|
||||||
SchurRedBlackDiagMooeeSolve<FermionField> DerivativeSolverR;
|
SchurRedBlackDiagMooeeSolve<FermionField> DerivativeSolverR;
|
||||||
FermionField Phi; // the pseudofermion field for this trajectory
|
FermionField Phi; // the pseudofermion field for this trajectory
|
||||||
|
|
||||||
|
RealD norm2_eta; //|eta|^2 where eta is the random gaussian field used to generate the pseudofermion field
|
||||||
|
bool initial_action; //true for the first call to S after refresh, for which the identity S = |eta|^2 holds provided the rational approx is good
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
//Used in the heatbath, refresh the shift coefficients of the L (LorR=0) or R (LorR=1) operator
|
||||||
|
virtual void heatbathRefreshShiftCoefficients(int LorR, RealD to){
|
||||||
|
AbstractEOFAFermion<Impl>&op = LorR == 0 ? Lop : Rop;
|
||||||
|
op.RefreshShiftCoefficients(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Use the same solver for L,R in all cases
|
||||||
ExactOneFlavourRatioPseudoFermionAction(AbstractEOFAFermion<Impl>& _Lop,
|
ExactOneFlavourRatioPseudoFermionAction(AbstractEOFAFermion<Impl>& _Lop,
|
||||||
AbstractEOFAFermion<Impl>& _Rop,
|
AbstractEOFAFermion<Impl>& _Rop,
|
||||||
OperatorFunction<FermionField>& CG,
|
OperatorFunction<FermionField>& CG,
|
||||||
Params& p,
|
Params& p,
|
||||||
bool use_fc=false)
|
bool use_fc=false)
|
||||||
: ExactOneFlavourRatioPseudoFermionAction(_Lop,_Rop,CG,CG,CG,CG,CG,p,use_fc) {};
|
: ExactOneFlavourRatioPseudoFermionAction(_Lop,_Rop,CG,CG,CG,CG,CG,CG,p,use_fc) {};
|
||||||
|
|
||||||
|
//Use the same solver for L,R in the heatbath but different solvers elsewhere
|
||||||
ExactOneFlavourRatioPseudoFermionAction(AbstractEOFAFermion<Impl>& _Lop,
|
ExactOneFlavourRatioPseudoFermionAction(AbstractEOFAFermion<Impl>& _Lop,
|
||||||
AbstractEOFAFermion<Impl>& _Rop,
|
AbstractEOFAFermion<Impl>& _Rop,
|
||||||
OperatorFunction<FermionField>& HeatbathCG,
|
OperatorFunction<FermionField>& HeatbathCG,
|
||||||
|
OperatorFunction<FermionField>& ActionCGL, OperatorFunction<FermionField>& ActionCGR,
|
||||||
|
OperatorFunction<FermionField>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,
|
||||||
|
Params& p,
|
||||||
|
bool use_fc=false)
|
||||||
|
: ExactOneFlavourRatioPseudoFermionAction(_Lop,_Rop,HeatbathCG,HeatbathCG, ActionCGL, ActionCGR, DerivCGL,DerivCGR,p,use_fc) {};
|
||||||
|
|
||||||
|
//Use different solvers for L,R in all cases
|
||||||
|
ExactOneFlavourRatioPseudoFermionAction(AbstractEOFAFermion<Impl>& _Lop,
|
||||||
|
AbstractEOFAFermion<Impl>& _Rop,
|
||||||
|
OperatorFunction<FermionField>& HeatbathCGL, OperatorFunction<FermionField>& HeatbathCGR,
|
||||||
OperatorFunction<FermionField>& ActionCGL, OperatorFunction<FermionField>& ActionCGR,
|
OperatorFunction<FermionField>& ActionCGL, OperatorFunction<FermionField>& ActionCGR,
|
||||||
OperatorFunction<FermionField>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,
|
OperatorFunction<FermionField>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,
|
||||||
Params& p,
|
Params& p,
|
||||||
bool use_fc=false) :
|
bool use_fc=false) :
|
||||||
Lop(_Lop),
|
Lop(_Lop),
|
||||||
Rop(_Rop),
|
Rop(_Rop),
|
||||||
SolverHB(HeatbathCG,false,true),
|
SolverHBL(HeatbathCGL,false,true), SolverHBR(HeatbathCGR,false,true),
|
||||||
SolverL(ActionCGL, false, true), SolverR(ActionCGR, false, true),
|
SolverL(ActionCGL, false, true), SolverR(ActionCGR, false, true),
|
||||||
DerivativeSolverL(DerivCGL, false, true), DerivativeSolverR(DerivCGR, false, true),
|
DerivativeSolverL(DerivCGL, false, true), DerivativeSolverR(DerivCGR, false, true),
|
||||||
Phi(_Lop.FermionGrid()),
|
Phi(_Lop.FermionGrid()),
|
||||||
param(p),
|
param(p),
|
||||||
use_heatbath_forecasting(use_fc)
|
use_heatbath_forecasting(use_fc),
|
||||||
|
initial_action(false)
|
||||||
{
|
{
|
||||||
AlgRemez remez(param.lo, param.hi, param.precision);
|
AlgRemez remez(param.lo, param.hi, param.precision);
|
||||||
|
|
||||||
@ -97,6 +124,8 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
PowerNegHalf.Init(remez, param.tolerance, true);
|
PowerNegHalf.Init(remez, param.tolerance, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FermionField &getPhi() const{ return Phi; }
|
||||||
|
|
||||||
virtual std::string action_name() { return "ExactOneFlavourRatioPseudoFermionAction"; }
|
virtual std::string action_name() { return "ExactOneFlavourRatioPseudoFermionAction"; }
|
||||||
|
|
||||||
virtual std::string LogParameters() {
|
virtual std::string LogParameters() {
|
||||||
@ -117,6 +146,19 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
else{ for(int s=0; s<Ls; ++s){ axpby_ssp_pminus(out, 0.0, in, 1.0, in, s, s); } }
|
else{ for(int s=0; s<Ls; ++s){ axpby_ssp_pminus(out, 0.0, in, 1.0, in, s, s); } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
|
// P(eta_o) = e^{- eta_o^dag eta_o}
|
||||||
|
//
|
||||||
|
// e^{x^2/2 sig^2} => sig^2 = 0.5.
|
||||||
|
//
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
|
||||||
|
FermionField eta (Lop.FermionGrid());
|
||||||
|
gaussian(pRNG,eta); eta = eta * scale;
|
||||||
|
|
||||||
|
refresh(U,eta);
|
||||||
|
}
|
||||||
|
|
||||||
// EOFA heatbath: see Eqn. (29) of arXiv:1706.05843
|
// EOFA heatbath: see Eqn. (29) of arXiv:1706.05843
|
||||||
// We generate a Gaussian noise vector \eta, and then compute
|
// We generate a Gaussian noise vector \eta, and then compute
|
||||||
// \Phi = M_{\rm EOFA}^{-1/2} * \eta
|
// \Phi = M_{\rm EOFA}^{-1/2} * \eta
|
||||||
@ -124,12 +166,10 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
//
|
//
|
||||||
// As a check of rational require \Phi^dag M_{EOFA} \Phi == eta^dag M^-1/2^dag M M^-1/2 eta = eta^dag eta
|
// As a check of rational require \Phi^dag M_{EOFA} \Phi == eta^dag M^-1/2^dag M M^-1/2 eta = eta^dag eta
|
||||||
//
|
//
|
||||||
virtual void refresh(const GaugeField& U, GridSerialRNG &sRNG, GridParallelRNG& pRNG)
|
void refresh(const GaugeField &U, const FermionField &eta) {
|
||||||
{
|
|
||||||
Lop.ImportGauge(U);
|
Lop.ImportGauge(U);
|
||||||
Rop.ImportGauge(U);
|
Rop.ImportGauge(U);
|
||||||
|
|
||||||
FermionField eta (Lop.FermionGrid());
|
|
||||||
FermionField CG_src (Lop.FermionGrid());
|
FermionField CG_src (Lop.FermionGrid());
|
||||||
FermionField CG_soln (Lop.FermionGrid());
|
FermionField CG_soln (Lop.FermionGrid());
|
||||||
FermionField Forecast_src(Lop.FermionGrid());
|
FermionField Forecast_src(Lop.FermionGrid());
|
||||||
@ -140,11 +180,6 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
if(use_heatbath_forecasting){ prev_solns.reserve(param.degree); }
|
if(use_heatbath_forecasting){ prev_solns.reserve(param.degree); }
|
||||||
ChronoForecast<AbstractEOFAFermion<Impl>, FermionField> Forecast;
|
ChronoForecast<AbstractEOFAFermion<Impl>, FermionField> Forecast;
|
||||||
|
|
||||||
// Seed with Gaussian noise vector (var = 0.5)
|
|
||||||
RealD scale = std::sqrt(0.5);
|
|
||||||
gaussian(pRNG,eta);
|
|
||||||
eta = eta * scale;
|
|
||||||
|
|
||||||
// \Phi = ( \alpha_{0} + \sum_{k=1}^{N_{p}} \alpha_{l} * \gamma_{l} ) * \eta
|
// \Phi = ( \alpha_{0} + \sum_{k=1}^{N_{p}} \alpha_{l} * \gamma_{l} ) * \eta
|
||||||
RealD N(PowerNegHalf.norm);
|
RealD N(PowerNegHalf.norm);
|
||||||
for(int k=0; k<param.degree; ++k){ N += PowerNegHalf.residues[k] / ( 1.0 + PowerNegHalf.poles[k] ); }
|
for(int k=0; k<param.degree; ++k){ N += PowerNegHalf.residues[k] / ( 1.0 + PowerNegHalf.poles[k] ); }
|
||||||
@ -160,15 +195,15 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
tmp[1] = Zero();
|
tmp[1] = Zero();
|
||||||
for(int k=0; k<param.degree; ++k){
|
for(int k=0; k<param.degree; ++k){
|
||||||
gamma_l = 1.0 / ( 1.0 + PowerNegHalf.poles[k] );
|
gamma_l = 1.0 / ( 1.0 + PowerNegHalf.poles[k] );
|
||||||
Lop.RefreshShiftCoefficients(-gamma_l);
|
heatbathRefreshShiftCoefficients(0, -gamma_l);
|
||||||
if(use_heatbath_forecasting){ // Forecast CG guess using solutions from previous poles
|
if(use_heatbath_forecasting){ // Forecast CG guess using solutions from previous poles
|
||||||
Lop.Mdag(CG_src, Forecast_src);
|
Lop.Mdag(CG_src, Forecast_src);
|
||||||
CG_soln = Forecast(Lop, Forecast_src, prev_solns);
|
CG_soln = Forecast(Lop, Forecast_src, prev_solns);
|
||||||
SolverHB(Lop, CG_src, CG_soln);
|
SolverHBL(Lop, CG_src, CG_soln);
|
||||||
prev_solns.push_back(CG_soln);
|
prev_solns.push_back(CG_soln);
|
||||||
} else {
|
} else {
|
||||||
CG_soln = Zero(); // Just use zero as the initial guess
|
CG_soln = Zero(); // Just use zero as the initial guess
|
||||||
SolverHB(Lop, CG_src, CG_soln);
|
SolverHBL(Lop, CG_src, CG_soln);
|
||||||
}
|
}
|
||||||
Lop.Dtilde(CG_soln, tmp[0]); // We actually solved Cayley preconditioned system: transform back
|
Lop.Dtilde(CG_soln, tmp[0]); // We actually solved Cayley preconditioned system: transform back
|
||||||
tmp[1] = tmp[1] + ( PowerNegHalf.residues[k]*gamma_l*gamma_l*Lop.k ) * tmp[0];
|
tmp[1] = tmp[1] + ( PowerNegHalf.residues[k]*gamma_l*gamma_l*Lop.k ) * tmp[0];
|
||||||
@ -187,15 +222,15 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
if(use_heatbath_forecasting){ prev_solns.clear(); } // empirically, LH solns don't help for RH solves
|
if(use_heatbath_forecasting){ prev_solns.clear(); } // empirically, LH solns don't help for RH solves
|
||||||
for(int k=0; k<param.degree; ++k){
|
for(int k=0; k<param.degree; ++k){
|
||||||
gamma_l = 1.0 / ( 1.0 + PowerNegHalf.poles[k] );
|
gamma_l = 1.0 / ( 1.0 + PowerNegHalf.poles[k] );
|
||||||
Rop.RefreshShiftCoefficients(-gamma_l*PowerNegHalf.poles[k]);
|
heatbathRefreshShiftCoefficients(1, -gamma_l*PowerNegHalf.poles[k]);
|
||||||
if(use_heatbath_forecasting){
|
if(use_heatbath_forecasting){
|
||||||
Rop.Mdag(CG_src, Forecast_src);
|
Rop.Mdag(CG_src, Forecast_src);
|
||||||
CG_soln = Forecast(Rop, Forecast_src, prev_solns);
|
CG_soln = Forecast(Rop, Forecast_src, prev_solns);
|
||||||
SolverHB(Rop, CG_src, CG_soln);
|
SolverHBR(Rop, CG_src, CG_soln);
|
||||||
prev_solns.push_back(CG_soln);
|
prev_solns.push_back(CG_soln);
|
||||||
} else {
|
} else {
|
||||||
CG_soln = Zero();
|
CG_soln = Zero();
|
||||||
SolverHB(Rop, CG_src, CG_soln);
|
SolverHBR(Rop, CG_src, CG_soln);
|
||||||
}
|
}
|
||||||
Rop.Dtilde(CG_soln, tmp[0]); // We actually solved Cayley preconditioned system: transform back
|
Rop.Dtilde(CG_soln, tmp[0]); // We actually solved Cayley preconditioned system: transform back
|
||||||
tmp[1] = tmp[1] - ( PowerNegHalf.residues[k]*gamma_l*gamma_l*Rop.k ) * tmp[0];
|
tmp[1] = tmp[1] - ( PowerNegHalf.residues[k]*gamma_l*gamma_l*Rop.k ) * tmp[0];
|
||||||
@ -205,49 +240,117 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
Phi = Phi + tmp[1];
|
Phi = Phi + tmp[1];
|
||||||
|
|
||||||
// Reset shift coefficients for energy and force evals
|
// Reset shift coefficients for energy and force evals
|
||||||
Lop.RefreshShiftCoefficients(0.0);
|
heatbathRefreshShiftCoefficients(0, 0.0);
|
||||||
Rop.RefreshShiftCoefficients(-1.0);
|
heatbathRefreshShiftCoefficients(1, -1.0);
|
||||||
|
|
||||||
|
//Mark that the next call to S is the first after refresh
|
||||||
|
initial_action = true;
|
||||||
|
|
||||||
|
|
||||||
// Bounds check
|
// Bounds check
|
||||||
RealD EtaDagEta = norm2(eta);
|
RealD EtaDagEta = norm2(eta);
|
||||||
|
norm2_eta = EtaDagEta;
|
||||||
|
|
||||||
// RealD PhiDagMPhi= norm2(eta);
|
// RealD PhiDagMPhi= norm2(eta);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void Meofa(const GaugeField& U,const FermionField &phi, FermionField & Mphi)
|
void Meofa(const GaugeField& U,const FermionField &in, FermionField & out)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
Lop.ImportGauge(U);
|
Lop.ImportGauge(U);
|
||||||
Rop.ImportGauge(U);
|
Rop.ImportGauge(U);
|
||||||
|
|
||||||
FermionField spProj_Phi(Lop.FermionGrid());
|
FermionField spProj_in(Lop.FermionGrid());
|
||||||
FermionField mPhi(Lop.FermionGrid());
|
|
||||||
std::vector<FermionField> tmp(2, Lop.FermionGrid());
|
std::vector<FermionField> tmp(2, Lop.FermionGrid());
|
||||||
mPhi = phi;
|
out = in;
|
||||||
|
|
||||||
// LH term: S = S - k <\Phi| P_{-} \Omega_{-}^{\dagger} H(mf)^{-1} \Omega_{-} P_{-} |\Phi>
|
// LH term: S = S - k <\Phi| P_{-} \Omega_{-}^{\dagger} H(mf)^{-1} \Omega_{-} P_{-} |\Phi>
|
||||||
spProj(Phi, spProj_Phi, -1, Lop.Ls);
|
spProj(in, spProj_in, -1, Lop.Ls);
|
||||||
Lop.Omega(spProj_Phi, tmp[0], -1, 0);
|
Lop.Omega(spProj_in, tmp[0], -1, 0);
|
||||||
G5R5(tmp[1], tmp[0]);
|
G5R5(tmp[1], tmp[0]);
|
||||||
tmp[0] = Zero();
|
tmp[0] = Zero();
|
||||||
SolverL(Lop, tmp[1], tmp[0]);
|
SolverL(Lop, tmp[1], tmp[0]);
|
||||||
Lop.Dtilde(tmp[0], tmp[1]); // We actually solved Cayley preconditioned system: transform back
|
Lop.Dtilde(tmp[0], tmp[1]); // We actually solved Cayley preconditioned system: transform back
|
||||||
Lop.Omega(tmp[1], tmp[0], -1, 1);
|
Lop.Omega(tmp[1], tmp[0], -1, 1);
|
||||||
mPhi = mPhi - Lop.k * innerProduct(spProj_Phi, tmp[0]).real();
|
spProj(tmp[0], tmp[1], -1, Lop.Ls);
|
||||||
|
|
||||||
|
out = out - Lop.k * tmp[1];
|
||||||
|
|
||||||
// RH term: S = S + k <\Phi| P_{+} \Omega_{+}^{\dagger} ( H(mb)
|
// RH term: S = S + k <\Phi| P_{+} \Omega_{+}^{\dagger} ( H(mb)
|
||||||
// - \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{-} P_{-} |\Phi>
|
// - \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{+} P_{+} |\Phi>
|
||||||
spProj(Phi, spProj_Phi, 1, Rop.Ls);
|
spProj(in, spProj_in, 1, Rop.Ls);
|
||||||
Rop.Omega(spProj_Phi, tmp[0], 1, 0);
|
Rop.Omega(spProj_in, tmp[0], 1, 0);
|
||||||
G5R5(tmp[1], tmp[0]);
|
G5R5(tmp[1], tmp[0]);
|
||||||
tmp[0] = Zero();
|
tmp[0] = Zero();
|
||||||
SolverR(Rop, tmp[1], tmp[0]);
|
SolverR(Rop, tmp[1], tmp[0]);
|
||||||
Rop.Dtilde(tmp[0], tmp[1]);
|
Rop.Dtilde(tmp[0], tmp[1]);
|
||||||
Rop.Omega(tmp[1], tmp[0], 1, 1);
|
Rop.Omega(tmp[1], tmp[0], 1, 1);
|
||||||
action += Rop.k * innerProduct(spProj_Phi, tmp[0]).real();
|
spProj(tmp[0], tmp[1], 1, Rop.Ls);
|
||||||
#endif
|
|
||||||
|
out = out + Rop.k * tmp[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Due to the structure of EOFA, it is no more expensive to compute the inverse of Meofa
|
||||||
|
//To ensure correctness we can simply reuse the heatbath code but use the rational approx
|
||||||
|
//f(x) = 1/x which corresponds to alpha_0=0, alpha_1=1, beta_1=0 => gamma_1=1
|
||||||
|
void MeofaInv(const GaugeField &U, const FermionField &in, FermionField &out) {
|
||||||
|
Lop.ImportGauge(U);
|
||||||
|
Rop.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField CG_src (Lop.FermionGrid());
|
||||||
|
FermionField CG_soln (Lop.FermionGrid());
|
||||||
|
std::vector<FermionField> tmp(2, Lop.FermionGrid());
|
||||||
|
|
||||||
|
// \Phi = ( \alpha_{0} + \sum_{k=1}^{N_{p}} \alpha_{l} * \gamma_{l} ) * \eta
|
||||||
|
// = 1 * \eta
|
||||||
|
out = in;
|
||||||
|
|
||||||
|
// LH terms:
|
||||||
|
// \Phi = \Phi + k \sum_{k=1}^{N_{p}} P_{-} \Omega_{-}^{\dagger} ( H(mf)
|
||||||
|
// - \gamma_{l} \Delta_{-}(mf,mb) P_{-} )^{-1} \Omega_{-} P_{-} \eta
|
||||||
|
spProj(in, tmp[0], -1, Lop.Ls);
|
||||||
|
Lop.Omega(tmp[0], tmp[1], -1, 0);
|
||||||
|
G5R5(CG_src, tmp[1]);
|
||||||
|
{
|
||||||
|
heatbathRefreshShiftCoefficients(0, -1.); //-gamma_1 = -1.
|
||||||
|
|
||||||
|
CG_soln = Zero(); // Just use zero as the initial guess
|
||||||
|
SolverHBL(Lop, CG_src, CG_soln);
|
||||||
|
|
||||||
|
Lop.Dtilde(CG_soln, tmp[0]); // We actually solved Cayley preconditioned system: transform back
|
||||||
|
tmp[1] = Lop.k * tmp[0];
|
||||||
|
}
|
||||||
|
Lop.Omega(tmp[1], tmp[0], -1, 1);
|
||||||
|
spProj(tmp[0], tmp[1], -1, Lop.Ls);
|
||||||
|
out = out + tmp[1];
|
||||||
|
|
||||||
|
// RH terms:
|
||||||
|
// \Phi = \Phi - k \sum_{k=1}^{N_{p}} P_{+} \Omega_{+}^{\dagger} ( H(mb)
|
||||||
|
// - \beta_l\gamma_{l} \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{+} P_{+} \eta
|
||||||
|
spProj(in, tmp[0], 1, Rop.Ls);
|
||||||
|
Rop.Omega(tmp[0], tmp[1], 1, 0);
|
||||||
|
G5R5(CG_src, tmp[1]);
|
||||||
|
{
|
||||||
|
heatbathRefreshShiftCoefficients(1, 0.); //-gamma_1 * beta_1 = 0
|
||||||
|
|
||||||
|
CG_soln = Zero();
|
||||||
|
SolverHBR(Rop, CG_src, CG_soln);
|
||||||
|
|
||||||
|
Rop.Dtilde(CG_soln, tmp[0]); // We actually solved Cayley preconditioned system: transform back
|
||||||
|
tmp[1] = - Rop.k * tmp[0];
|
||||||
|
}
|
||||||
|
Rop.Omega(tmp[1], tmp[0], 1, 1);
|
||||||
|
spProj(tmp[0], tmp[1], 1, Rop.Ls);
|
||||||
|
out = out + tmp[1];
|
||||||
|
|
||||||
|
// Reset shift coefficients for energy and force evals
|
||||||
|
heatbathRefreshShiftCoefficients(0, 0.0);
|
||||||
|
heatbathRefreshShiftCoefficients(1, -1.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// EOFA action: see Eqn. (10) of arXiv:1706.05843
|
// EOFA action: see Eqn. (10) of arXiv:1706.05843
|
||||||
virtual RealD S(const GaugeField& U)
|
virtual RealD S(const GaugeField& U)
|
||||||
{
|
{
|
||||||
@ -271,7 +374,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
action -= Lop.k * innerProduct(spProj_Phi, tmp[0]).real();
|
action -= Lop.k * innerProduct(spProj_Phi, tmp[0]).real();
|
||||||
|
|
||||||
// RH term: S = S + k <\Phi| P_{+} \Omega_{+}^{\dagger} ( H(mb)
|
// RH term: S = S + k <\Phi| P_{+} \Omega_{+}^{\dagger} ( H(mb)
|
||||||
// - \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{-} P_{-} |\Phi>
|
// - \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{+} P_{+} |\Phi>
|
||||||
spProj(Phi, spProj_Phi, 1, Rop.Ls);
|
spProj(Phi, spProj_Phi, 1, Rop.Ls);
|
||||||
Rop.Omega(spProj_Phi, tmp[0], 1, 0);
|
Rop.Omega(spProj_Phi, tmp[0], 1, 0);
|
||||||
G5R5(tmp[1], tmp[0]);
|
G5R5(tmp[1], tmp[0]);
|
||||||
@ -281,6 +384,26 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
Rop.Omega(tmp[1], tmp[0], 1, 1);
|
Rop.Omega(tmp[1], tmp[0], 1, 1);
|
||||||
action += Rop.k * innerProduct(spProj_Phi, tmp[0]).real();
|
action += Rop.k * innerProduct(spProj_Phi, tmp[0]).real();
|
||||||
|
|
||||||
|
if(initial_action){
|
||||||
|
//For the first call to S after refresh, S = |eta|^2. We can use this to ensure the rational approx is good
|
||||||
|
RealD diff = action - norm2_eta;
|
||||||
|
|
||||||
|
//S_init = eta^dag M^{-1/2} M M^{-1/2} eta
|
||||||
|
//S_init - eta^dag eta = eta^dag ( M^{-1/2} M M^{-1/2} - 1 ) eta
|
||||||
|
|
||||||
|
//If approximate solution
|
||||||
|
//S_init - eta^dag eta = eta^dag ( [M^{-1/2}+\delta M^{-1/2}] M [M^{-1/2}+\delta M^{-1/2}] - 1 ) eta
|
||||||
|
// \approx eta^dag ( \delta M^{-1/2} M^{1/2} + M^{1/2}\delta M^{-1/2} ) eta
|
||||||
|
// We divide out |eta|^2 to remove source scaling but the tolerance on this check should still be somewhat higher than the actual approx tolerance
|
||||||
|
RealD test = fabs(diff)/norm2_eta; //test the quality of the rational approx
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << action_name() << " initial action " << action << " expect " << norm2_eta << "; diff " << diff << std::endl;
|
||||||
|
std::cout << GridLogMessage << action_name() << "[ eta^dag ( M^{-1/2} M M^{-1/2} - 1 ) eta ]/|eta^2| = " << test << " expect 0 (tol " << param.BoundsCheckTol << ")" << std::endl;
|
||||||
|
|
||||||
|
assert( ( test < param.BoundsCheckTol ) && " Initial action check failed" );
|
||||||
|
initial_action = false;
|
||||||
|
}
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -329,6 +452,40 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class ImplD, class ImplF>
|
||||||
|
class ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction : public ExactOneFlavourRatioPseudoFermionAction<ImplD>{
|
||||||
|
public:
|
||||||
|
INHERIT_IMPL_TYPES(ImplD);
|
||||||
|
typedef OneFlavourRationalParams Params;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractEOFAFermion<ImplF>& LopF; // the basic LH operator
|
||||||
|
AbstractEOFAFermion<ImplF>& RopF; // the basic RH operator
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual std::string action_name() { return "ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction"; }
|
||||||
|
|
||||||
|
//Used in the heatbath, refresh the shift coefficients of the L (LorR=0) or R (LorR=1) operator
|
||||||
|
virtual void heatbathRefreshShiftCoefficients(int LorR, RealD to){
|
||||||
|
AbstractEOFAFermion<ImplF> &op = LorR == 0 ? LopF : RopF;
|
||||||
|
op.RefreshShiftCoefficients(to);
|
||||||
|
this->ExactOneFlavourRatioPseudoFermionAction<ImplD>::heatbathRefreshShiftCoefficients(LorR,to);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction(AbstractEOFAFermion<ImplF>& _LopF,
|
||||||
|
AbstractEOFAFermion<ImplF>& _RopF,
|
||||||
|
AbstractEOFAFermion<ImplD>& _LopD,
|
||||||
|
AbstractEOFAFermion<ImplD>& _RopD,
|
||||||
|
OperatorFunction<FermionField>& HeatbathCGL, OperatorFunction<FermionField>& HeatbathCGR,
|
||||||
|
OperatorFunction<FermionField>& ActionCGL, OperatorFunction<FermionField>& ActionCGR,
|
||||||
|
OperatorFunction<FermionField>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,
|
||||||
|
Params& p,
|
||||||
|
bool use_fc=false) :
|
||||||
|
LopF(_LopF), RopF(_RopF), ExactOneFlavourRatioPseudoFermionAction<ImplD>(_LopD, _RopD, HeatbathCGL, HeatbathCGR, ActionCGL, ActionCGR, DerivCGL, DerivCGR, p, use_fc){}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
372
Grid/qcd/action/pseudofermion/GeneralEvenOddRationalRatio.h
Normal file
372
Grid/qcd/action/pseudofermion/GeneralEvenOddRationalRatio.h
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/qcd/action/pseudofermion/GeneralEvenOddRationalRatio.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Christopher Kelly <ckelly@bnl.gov>
|
||||||
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
|
||||||
|
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 Impl>
|
||||||
|
class GeneralEvenOddRatioRationalPseudoFermionAction : public Action<typename Impl::GaugeField> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
INHERIT_IMPL_TYPES(Impl);
|
||||||
|
|
||||||
|
typedef RationalActionParams Params;
|
||||||
|
Params param;
|
||||||
|
|
||||||
|
//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<Impl> & NumOp;// the basic operator
|
||||||
|
FermionOperator<Impl> & 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<<GridLogMessage << "Generating degree "<< approx_degree<<" approximation for x^(1/" << inv_pow << ")"<<std::endl;
|
||||||
|
double error = remez.generateApprox(approx_degree,1,inv_pow);
|
||||||
|
if(error > CG_tolerance)
|
||||||
|
std::cout<<GridLogMessage << "WARNING: Remez approximation has a larger error " << error << " than the CG tolerance " << CG_tolerance << "! Try increasing the number of poles" << std::endl;
|
||||||
|
|
||||||
|
approx.Init(remez, CG_tolerance,false);
|
||||||
|
approx_inv.Init(remez, CG_tolerance,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static constexpr bool Numerator = true;
|
||||||
|
static constexpr bool Denominator = false;
|
||||||
|
|
||||||
|
//Allow derived classes to override the multishift CG
|
||||||
|
virtual void multiShiftInverse(bool numerator, const MultiShiftFunction &approx, const Integer MaxIter, const FermionField &in, FermionField &out){
|
||||||
|
SchurDifferentiableOperator<Impl> schurOp(numerator ? NumOp : DenOp);
|
||||||
|
ConjugateGradientMultiShift<FermionField> msCG(MaxIter, approx);
|
||||||
|
msCG(schurOp,in, out);
|
||||||
|
}
|
||||||
|
virtual void multiShiftInverse(bool numerator, const MultiShiftFunction &approx, const Integer MaxIter, const FermionField &in, std::vector<FermionField> &out_elems, FermionField &out){
|
||||||
|
SchurDifferentiableOperator<Impl> schurOp(numerator ? NumOp : DenOp);
|
||||||
|
ConjugateGradientMultiShift<FermionField> 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:
|
||||||
|
|
||||||
|
GeneralEvenOddRatioRationalPseudoFermionAction(FermionOperator<Impl> &_NumOp,
|
||||||
|
FermionOperator<Impl> &_DenOp,
|
||||||
|
const Params & p
|
||||||
|
) :
|
||||||
|
NumOp(_NumOp),
|
||||||
|
DenOp(_DenOp),
|
||||||
|
PhiOdd (_NumOp.FermionRedBlackGrid()),
|
||||||
|
PhiEven(_NumOp.FermionRedBlackGrid()),
|
||||||
|
param(p)
|
||||||
|
{
|
||||||
|
std::cout<<GridLogMessage << action_name() << " initialize: starting" << std::endl;
|
||||||
|
AlgRemez remez(param.lo,param.hi,param.precision);
|
||||||
|
|
||||||
|
//Generate approximations for action eval
|
||||||
|
generateApprox(ApproxPowerAction, ApproxNegPowerAction, param.inv_pow, param.action_degree, param.action_tolerance, remez);
|
||||||
|
generateApprox(ApproxHalfPowerAction, ApproxNegHalfPowerAction, 2*param.inv_pow, param.action_degree, param.action_tolerance, remez);
|
||||||
|
|
||||||
|
//Generate approximations for MD
|
||||||
|
if(param.md_degree != param.action_degree){ //note the CG tolerance is unrelated to the stopping condition of the Remez algorithm
|
||||||
|
generateApprox(ApproxPowerMD, ApproxNegPowerMD, param.inv_pow, param.md_degree, param.md_tolerance, remez);
|
||||||
|
generateApprox(ApproxHalfPowerMD, ApproxNegHalfPowerMD, 2*param.inv_pow, param.md_degree, param.md_tolerance, remez);
|
||||||
|
}else{
|
||||||
|
std::cout<<GridLogMessage << "Using same rational approximations for MD as for action evaluation" << std::endl;
|
||||||
|
ApproxPowerMD = ApproxPowerAction;
|
||||||
|
ApproxNegPowerMD = ApproxNegPowerAction;
|
||||||
|
for(int i=0;i<ApproxPowerMD.tolerances.size();i++)
|
||||||
|
ApproxNegPowerMD.tolerances[i] = ApproxPowerMD.tolerances[i] = param.md_tolerance; //used for multishift
|
||||||
|
|
||||||
|
ApproxHalfPowerMD = ApproxHalfPowerAction;
|
||||||
|
ApproxNegHalfPowerMD = ApproxNegHalfPowerAction;
|
||||||
|
for(int i=0;i<ApproxPowerMD.tolerances.size();i++)
|
||||||
|
ApproxNegHalfPowerMD.tolerances[i] = ApproxHalfPowerMD.tolerances[i] = param.md_tolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage << action_name() << " initialize: complete" << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual std::string action_name(){return "GeneralEvenOddRatioRationalPseudoFermionAction";}
|
||||||
|
|
||||||
|
virtual std::string LogParameters(){
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Power : 1/" << param.inv_pow << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Low :" << param.lo << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] High :" << param.hi << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Max iterations :" << param.MaxIter << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Tolerance (Action) :" << param.action_tolerance << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Degree (Action) :" << param.action_degree << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Tolerance (MD) :" << param.md_tolerance << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Degree (MD) :" << param.md_degree << std::endl;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] Precision :" << param.precision << std::endl;
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Access the fermion field
|
||||||
|
const FermionField &getPhiOdd() const{ return PhiOdd; }
|
||||||
|
|
||||||
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
|
std::cout<<GridLogMessage << action_name() << " refresh: starting" << std::endl;
|
||||||
|
FermionField eta(NumOp.FermionGrid());
|
||||||
|
|
||||||
|
// P(eta) \propto e^{- eta^dag eta}
|
||||||
|
//
|
||||||
|
// The gaussian function draws from P(x) \propto e^{- x^2 / 2 } [i.e. sigma=1]
|
||||||
|
// Thus eta = x/sqrt{2} = x * sqrt(1/2)
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
gaussian(pRNG,eta); eta=eta*scale;
|
||||||
|
|
||||||
|
refresh(U,eta);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Allow for manual specification of random field for testing
|
||||||
|
void refresh(const GaugeField &U, const FermionField &eta) {
|
||||||
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// P(phi) = e^{- phi^dag (VdagV)^1/(2*inv_pow) (MdagM)^-1/inv_pow (VdagV)^1/(2*inv_pow) phi}
|
||||||
|
// = e^{- phi^dag (VdagV)^1/(2*inv_pow) (MdagM)^-1/(2*inv_pow) (MdagM)^-1/(2*inv_pow) (VdagV)^1/(2*inv_pow) phi}
|
||||||
|
//
|
||||||
|
// Phi = (VdagV)^-1/(2*inv_pow) Mdag^{1/(2*inv_pow)} eta
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage << action_name() << " refresh: starting" << std::endl;
|
||||||
|
|
||||||
|
FermionField etaOdd (NumOp.FermionRedBlackGrid());
|
||||||
|
FermionField etaEven(NumOp.FermionRedBlackGrid());
|
||||||
|
FermionField tmp(NumOp.FermionRedBlackGrid());
|
||||||
|
|
||||||
|
pickCheckerboard(Even,etaEven,eta);
|
||||||
|
pickCheckerboard(Odd,etaOdd,eta);
|
||||||
|
|
||||||
|
ImportGauge(U);
|
||||||
|
|
||||||
|
// MdagM^1/(2*inv_pow) eta
|
||||||
|
std::cout<<GridLogMessage << action_name() << " refresh: doing (M^dag M)^{1/" << 2*param.inv_pow << "} eta" << std::endl;
|
||||||
|
multiShiftInverse(Denominator, ApproxHalfPowerAction, param.MaxIter, etaOdd, tmp);
|
||||||
|
|
||||||
|
// VdagV^-1/(2*inv_pow) MdagM^1/(2*inv_pow) eta
|
||||||
|
std::cout<<GridLogMessage << action_name() << " refresh: doing (V^dag V)^{-1/" << 2*param.inv_pow << "} ( (M^dag M)^{1/" << 2*param.inv_pow << "} eta)" << std::endl;
|
||||||
|
multiShiftInverse(Numerator, ApproxNegHalfPowerAction, param.MaxIter, tmp, PhiOdd);
|
||||||
|
|
||||||
|
assert(NumOp.ConstEE() == 1);
|
||||||
|
assert(DenOp.ConstEE() == 1);
|
||||||
|
PhiEven = Zero();
|
||||||
|
std::cout<<GridLogMessage << action_name() << " refresh: starting" << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// 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
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual RealD S(const GaugeField &U) {
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: starting" << std::endl;
|
||||||
|
ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField X(NumOp.FermionRedBlackGrid());
|
||||||
|
FermionField Y(NumOp.FermionRedBlackGrid());
|
||||||
|
|
||||||
|
// VdagV^1/(2*inv_pow) Phi
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: doing (V^dag V)^{1/" << 2*param.inv_pow << "} Phi" << std::endl;
|
||||||
|
multiShiftInverse(Numerator, ApproxHalfPowerAction, param.MaxIter, PhiOdd,X);
|
||||||
|
|
||||||
|
// MdagM^-1/(2*inv_pow) VdagV^1/(2*inv_pow) Phi
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: doing (M^dag M)^{-1/" << 2*param.inv_pow << "} ( (V^dag V)^{1/" << 2*param.inv_pow << "} Phi)" << std::endl;
|
||||||
|
multiShiftInverse(Denominator, ApproxNegHalfPowerAction, param.MaxIter, X,Y);
|
||||||
|
|
||||||
|
// Randomly apply rational bounds checks.
|
||||||
|
int rcheck = rand();
|
||||||
|
auto grid = NumOp.FermionGrid();
|
||||||
|
auto r=rand();
|
||||||
|
grid->Broadcast(0,r);
|
||||||
|
|
||||||
|
if ( param.BoundsCheckFreq != 0 && (r % param.BoundsCheckFreq)==0 ) {
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: doing bounds check" << std::endl;
|
||||||
|
FermionField gauss(NumOp.FermionRedBlackGrid());
|
||||||
|
gauss = PhiOdd;
|
||||||
|
SchurDifferentiableOperator<Impl> MdagM(DenOp);
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: checking high bounds" << std::endl;
|
||||||
|
HighBoundCheck(MdagM,gauss,param.hi);
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: full approximation" << std::endl;
|
||||||
|
InversePowerBoundsCheck(param.inv_pow,param.MaxIter,param.action_tolerance*100,MdagM,gauss,ApproxNegPowerAction);
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: bounds check complete" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phidag VdagV^1/(2*inv_pow) MdagM^-1/(2*inv_pow) MdagM^-1/(2*inv_pow) VdagV^1/(2*inv_pow) Phi
|
||||||
|
RealD action = norm2(Y);
|
||||||
|
std::cout<<GridLogMessage << action_name() << " compute action: complete" << std::endl;
|
||||||
|
|
||||||
|
return action;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Here, M is some 5D operator and V is the Pauli-Villars field
|
||||||
|
// N and D makeup the rat. poly of the M term and P and & makeup the rat.poly of the denom term
|
||||||
|
//
|
||||||
|
// Need
|
||||||
|
// dS_f/dU = chi^dag d[P/Q] N/D P/Q chi
|
||||||
|
// + chi^dag P/Q d[N/D] P/Q chi
|
||||||
|
// + chi^dag P/Q N/D d[P/Q] chi
|
||||||
|
//
|
||||||
|
// P/Q is expressed as partial fraction expansion:
|
||||||
|
//
|
||||||
|
// a0 + \sum_k ak/(V^dagV + bk)
|
||||||
|
//
|
||||||
|
// d[P/Q] is then
|
||||||
|
//
|
||||||
|
// \sum_k -ak [V^dagV+bk]^{-1} [ dV^dag V + V^dag dV ] [V^dag V + bk]^{-1}
|
||||||
|
//
|
||||||
|
// and similar for N/D.
|
||||||
|
//
|
||||||
|
// Need
|
||||||
|
// MpvPhi_k = [Vdag V + bk]^{-1} chi
|
||||||
|
// MpvPhi = {a0 + \sum_k ak [Vdag V + bk]^{-1} }chi
|
||||||
|
//
|
||||||
|
// MfMpvPhi_k = [MdagM+bk]^{-1} MpvPhi
|
||||||
|
// MfMpvPhi = {a0 + \sum_k ak [Mdag M + bk]^{-1} } MpvPhi
|
||||||
|
//
|
||||||
|
// MpvMfMpvPhi_k = [Vdag V + bk]^{-1} MfMpvchi
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual void deriv(const GaugeField &U,GaugeField & dSdU) {
|
||||||
|
std::cout<<GridLogMessage << action_name() << " deriv: starting" << std::endl;
|
||||||
|
const int n_f = ApproxNegPowerMD.poles.size();
|
||||||
|
const int n_pv = ApproxHalfPowerMD.poles.size();
|
||||||
|
|
||||||
|
std::vector<FermionField> MpvPhi_k (n_pv,NumOp.FermionRedBlackGrid());
|
||||||
|
std::vector<FermionField> MpvMfMpvPhi_k(n_pv,NumOp.FermionRedBlackGrid());
|
||||||
|
std::vector<FermionField> 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<<GridLogMessage << action_name() << " deriv: doing (V^dag V)^{1/" << 2*param.inv_pow << "} Phi" << std::endl;
|
||||||
|
multiShiftInverse(Numerator, ApproxHalfPowerMD, param.MaxIter, PhiOdd,MpvPhi_k,MpvPhi);
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage << action_name() << " deriv: doing (M^dag M)^{-1/" << param.inv_pow << "} ( (V^dag V)^{1/" << 2*param.inv_pow << "} Phi)" << std::endl;
|
||||||
|
multiShiftInverse(Denominator, ApproxNegPowerMD, param.MaxIter, MpvPhi,MfMpvPhi_k,MfMpvPhi);
|
||||||
|
|
||||||
|
std::cout<<GridLogMessage << action_name() << " deriv: doing (V^dag V)^{1/" << 2*param.inv_pow << "} ( (M^dag M)^{-1/" << param.inv_pow << "} (V^dag V)^{1/" << 2*param.inv_pow << "} Phi)" << std::endl;
|
||||||
|
multiShiftInverse(Numerator, ApproxHalfPowerMD, param.MaxIter, MfMpvPhi,MpvMfMpvPhi_k,MpvMfMpvPhi);
|
||||||
|
|
||||||
|
|
||||||
|
SchurDifferentiableOperator<Impl> MdagM(DenOp);
|
||||||
|
SchurDifferentiableOperator<Impl> 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<<GridLogMessage << action_name() << " deriv: doing dS/dU part (1)" << std::endl;
|
||||||
|
for(int k=0;k<n_f;k++){
|
||||||
|
ak = ApproxNegPowerMD.residues[k];
|
||||||
|
MdagM.Mpc(MfMpvPhi_k[k],Y);
|
||||||
|
MdagM.MpcDagDeriv(tmp , MfMpvPhi_k[k], Y ); dSdU=dSdU+ak*tmp;
|
||||||
|
MdagM.MpcDeriv(tmp , Y, MfMpvPhi_k[k] ); dSdU=dSdU+ak*tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(2)
|
||||||
|
//(3)
|
||||||
|
std::cout<<GridLogMessage << action_name() << " deriv: doing dS/dU part (2)+(3)" << std::endl;
|
||||||
|
for(int k=0;k<n_pv;k++){
|
||||||
|
|
||||||
|
ak = ApproxHalfPowerMD.residues[k];
|
||||||
|
|
||||||
|
VdagV.Mpc(MpvPhi_k[k],Y);
|
||||||
|
VdagV.MpcDagDeriv(tmp,MpvMfMpvPhi_k[k],Y); dSdU=dSdU+ak*tmp;
|
||||||
|
VdagV.MpcDeriv (tmp,Y,MpvMfMpvPhi_k[k]); dSdU=dSdU+ak*tmp;
|
||||||
|
|
||||||
|
VdagV.Mpc(MpvMfMpvPhi_k[k],Y); // V as we take Ydag
|
||||||
|
VdagV.MpcDeriv (tmp,Y, MpvPhi_k[k]); dSdU=dSdU+ak*tmp;
|
||||||
|
VdagV.MpcDagDeriv(tmp,MpvPhi_k[k], Y); dSdU=dSdU+ak*tmp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//dSdU = Ta(dSdU);
|
||||||
|
std::cout<<GridLogMessage << action_name() << " deriv: complete" << std::endl;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,93 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/qcd/action/pseudofermion/GeneralEvenOddRationalRatioMixedPrec.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Christopher Kelly <ckelly@bnl.gov>
|
||||||
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
|
||||||
|
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_MIXED_PREC_H
|
||||||
|
#define QCD_PSEUDOFERMION_GENERAL_EVEN_ODD_RATIONAL_RATIO_MIXED_PREC_H
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Generic rational approximation for ratios of operators utilizing the mixed precision multishift algorithm
|
||||||
|
// cf. GeneralEvenOddRational.h for details
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template<class ImplD, class ImplF>
|
||||||
|
class GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction : public GeneralEvenOddRatioRationalPseudoFermionAction<ImplD> {
|
||||||
|
private:
|
||||||
|
typedef typename ImplD::FermionField FermionFieldD;
|
||||||
|
typedef typename ImplF::FermionField FermionFieldF;
|
||||||
|
|
||||||
|
FermionOperator<ImplD> & NumOpD;
|
||||||
|
FermionOperator<ImplD> & DenOpD;
|
||||||
|
|
||||||
|
FermionOperator<ImplF> & NumOpF;
|
||||||
|
FermionOperator<ImplF> & DenOpF;
|
||||||
|
|
||||||
|
Integer ReliableUpdateFreq;
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//Allow derived classes to override the multishift CG
|
||||||
|
virtual void multiShiftInverse(bool numerator, const MultiShiftFunction &approx, const Integer MaxIter, const FermionFieldD &in, FermionFieldD &out){
|
||||||
|
SchurDifferentiableOperator<ImplD> schurOpD(numerator ? NumOpD : DenOpD);
|
||||||
|
SchurDifferentiableOperator<ImplF> schurOpF(numerator ? NumOpF : DenOpF);
|
||||||
|
|
||||||
|
ConjugateGradientMultiShiftMixedPrec<FermionFieldD, FermionFieldF> msCG(MaxIter, approx, NumOpF.FermionRedBlackGrid(), schurOpF, ReliableUpdateFreq);
|
||||||
|
msCG(schurOpD, in, out);
|
||||||
|
}
|
||||||
|
virtual void multiShiftInverse(bool numerator, const MultiShiftFunction &approx, const Integer MaxIter, const FermionFieldD &in, std::vector<FermionFieldD> &out_elems, FermionFieldD &out){
|
||||||
|
SchurDifferentiableOperator<ImplD> schurOpD(numerator ? NumOpD : DenOpD);
|
||||||
|
SchurDifferentiableOperator<ImplF> schurOpF(numerator ? NumOpF : DenOpF);
|
||||||
|
|
||||||
|
ConjugateGradientMultiShiftMixedPrec<FermionFieldD, FermionFieldF> msCG(MaxIter, approx, NumOpF.FermionRedBlackGrid(), schurOpF, ReliableUpdateFreq);
|
||||||
|
msCG(schurOpD, in, out_elems, out);
|
||||||
|
}
|
||||||
|
//Allow derived classes to override the gauge import
|
||||||
|
virtual void ImportGauge(const typename ImplD::GaugeField &Ud){
|
||||||
|
typename ImplF::GaugeField Uf(NumOpF.GaugeGrid());
|
||||||
|
precisionChange(Uf, Ud);
|
||||||
|
|
||||||
|
NumOpD.ImportGauge(Ud);
|
||||||
|
DenOpD.ImportGauge(Ud);
|
||||||
|
|
||||||
|
NumOpF.ImportGauge(Uf);
|
||||||
|
DenOpF.ImportGauge(Uf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction(FermionOperator<ImplD> &_NumOpD, FermionOperator<ImplD> &_DenOpD,
|
||||||
|
FermionOperator<ImplF> &_NumOpF, FermionOperator<ImplF> &_DenOpF,
|
||||||
|
const RationalActionParams & p, Integer _ReliableUpdateFreq
|
||||||
|
) : GeneralEvenOddRatioRationalPseudoFermionAction<ImplD>(_NumOpD, _DenOpD, p),
|
||||||
|
ReliableUpdateFreq(_ReliableUpdateFreq), NumOpD(_NumOpD), DenOpD(_DenOpD), NumOpF(_NumOpF), DenOpF(_DenOpF){}
|
||||||
|
|
||||||
|
virtual std::string action_name(){return "GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction";}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
#endif
|
@ -40,262 +40,31 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
// Here N/D \sim R_{-1/2} ~ (M^dagM)^{-1/2}
|
// Here N/D \sim R_{-1/2} ~ (M^dagM)^{-1/2}
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
class OneFlavourEvenOddRatioRationalPseudoFermionAction : public Action<typename Impl::GaugeField> {
|
class OneFlavourEvenOddRatioRationalPseudoFermionAction : public GeneralEvenOddRatioRationalPseudoFermionAction<Impl> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
INHERIT_IMPL_TYPES(Impl);
|
|
||||||
|
|
||||||
typedef OneFlavourRationalParams Params;
|
typedef OneFlavourRationalParams Params;
|
||||||
Params param;
|
|
||||||
|
|
||||||
MultiShiftFunction PowerHalf ;
|
|
||||||
MultiShiftFunction PowerNegHalf;
|
|
||||||
MultiShiftFunction PowerQuarter;
|
|
||||||
MultiShiftFunction PowerNegQuarter;
|
|
||||||
|
|
||||||
MultiShiftFunction MDPowerNegHalf;
|
|
||||||
MultiShiftFunction MDPowerQuarter;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static RationalActionParams transcribe(const Params &in){
|
||||||
FermionOperator<Impl> & NumOp;// the basic operator
|
RationalActionParams out;
|
||||||
FermionOperator<Impl> & DenOp;// the basic operator
|
out.inv_pow = 2;
|
||||||
FermionField PhiEven; // the pseudo fermion field for this trajectory
|
out.lo = in.lo;
|
||||||
FermionField PhiOdd; // the pseudo fermion field for this trajectory
|
out.hi = in.hi;
|
||||||
FermionField Noise; // spare noise field for bounds check
|
out.MaxIter = in.MaxIter;
|
||||||
|
out.action_tolerance = out.md_tolerance = in.tolerance;
|
||||||
|
out.action_degree = out.md_degree = in.degree;
|
||||||
|
out.precision = in.precision;
|
||||||
|
out.BoundsCheckFreq = in.BoundsCheckFreq;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OneFlavourEvenOddRatioRationalPseudoFermionAction(FermionOperator<Impl> &_NumOp,
|
OneFlavourEvenOddRatioRationalPseudoFermionAction(FermionOperator<Impl> &_NumOp,
|
||||||
FermionOperator<Impl> &_DenOp,
|
FermionOperator<Impl> &_DenOp,
|
||||||
Params & p
|
const Params & p
|
||||||
) :
|
) :
|
||||||
NumOp(_NumOp),
|
GeneralEvenOddRatioRationalPseudoFermionAction<Impl>(_NumOp, _DenOp, transcribe(p)){}
|
||||||
DenOp(_DenOp),
|
|
||||||
PhiOdd (_NumOp.FermionRedBlackGrid()),
|
|
||||||
PhiEven(_NumOp.FermionRedBlackGrid()),
|
|
||||||
Noise(_NumOp.FermionRedBlackGrid()),
|
|
||||||
param(p)
|
|
||||||
{
|
|
||||||
AlgRemez remez(param.lo,param.hi,param.precision);
|
|
||||||
|
|
||||||
// MdagM^(+- 1/2)
|
virtual std::string action_name(){return "OneFlavourEvenOddRatioRationalPseudoFermionAction";}
|
||||||
std::cout<<GridLogMessage << "Generating degree "<<param.degree<<" for x^(1/2)"<<std::endl;
|
|
||||||
remez.generateApprox(param.degree,1,2);
|
|
||||||
PowerHalf.Init(remez,param.tolerance,false);
|
|
||||||
PowerNegHalf.Init(remez,param.tolerance,true);
|
|
||||||
MDPowerNegHalf.Init(remez,param.mdtolerance,true);
|
|
||||||
|
|
||||||
// MdagM^(+- 1/4)
|
|
||||||
std::cout<<GridLogMessage << "Generating degree "<<param.degree<<" for x^(1/4)"<<std::endl;
|
|
||||||
remez.generateApprox(param.degree,1,4);
|
|
||||||
PowerQuarter.Init(remez,param.tolerance,false);
|
|
||||||
MDPowerQuarter.Init(remez,param.mdtolerance,false);
|
|
||||||
PowerNegQuarter.Init(remez,param.tolerance,true);
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual std::string action_name(){
|
|
||||||
std::stringstream sstream;
|
|
||||||
sstream<< "OneFlavourEvenOddRatioRationalPseudoFermionAction det("<< DenOp.Mass() << ") / det("<<NumOp.Mass()<<")";
|
|
||||||
return sstream.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string LogParameters(){
|
|
||||||
std::stringstream sstream;
|
|
||||||
sstream << GridLogMessage << "["<<action_name()<<"] Low :" << param.lo << std::endl;
|
|
||||||
sstream << GridLogMessage << "["<<action_name()<<"] High :" << param.hi << std::endl;
|
|
||||||
sstream << GridLogMessage << "["<<action_name()<<"] Max iterations :" << param.MaxIter << std::endl;
|
|
||||||
sstream << GridLogMessage << "["<<action_name()<<"] Tolerance :" << param.tolerance << std::endl;
|
|
||||||
sstream << GridLogMessage << "["<<action_name()<<"] Degree :" << param.degree << std::endl;
|
|
||||||
sstream << GridLogMessage << "["<<action_name()<<"] Precision :" << param.precision << std::endl;
|
|
||||||
return sstream.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
|
||||||
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
// P(phi) = e^{- phi^dag (VdagV)^1/4 (MdagM)^-1/2 (VdagV)^1/4 phi}
|
|
||||||
// = e^{- phi^dag (VdagV)^1/4 (MdagM)^-1/4 (MdagM)^-1/4 (VdagV)^1/4 phi}
|
|
||||||
//
|
|
||||||
// Phi = (VdagV)^-1/4 Mdag^{1/4} eta
|
|
||||||
//
|
|
||||||
// P(eta) = e^{- eta^dag eta}
|
|
||||||
//
|
|
||||||
// e^{x^2/2 sig^2} => sig^2 = 0.5.
|
|
||||||
//
|
|
||||||
// So eta should be of width sig = 1/sqrt(2).
|
|
||||||
|
|
||||||
RealD scale = std::sqrt(0.5);
|
|
||||||
|
|
||||||
FermionField eta(NumOp.FermionGrid());
|
|
||||||
FermionField etaOdd (NumOp.FermionRedBlackGrid());
|
|
||||||
FermionField etaEven(NumOp.FermionRedBlackGrid());
|
|
||||||
FermionField tmp(NumOp.FermionRedBlackGrid());
|
|
||||||
|
|
||||||
gaussian(pRNG,eta); eta=eta*scale;
|
|
||||||
|
|
||||||
pickCheckerboard(Even,etaEven,eta);
|
|
||||||
pickCheckerboard(Odd,etaOdd,eta);
|
|
||||||
|
|
||||||
Noise = etaOdd;
|
|
||||||
NumOp.ImportGauge(U);
|
|
||||||
DenOp.ImportGauge(U);
|
|
||||||
|
|
||||||
|
|
||||||
// MdagM^1/4 eta
|
|
||||||
SchurDifferentiableOperator<Impl> MdagM(DenOp);
|
|
||||||
ConjugateGradientMultiShift<FermionField> msCG_M(param.MaxIter,PowerQuarter);
|
|
||||||
msCG_M(MdagM,etaOdd,tmp);
|
|
||||||
|
|
||||||
// VdagV^-1/4 MdagM^1/4 eta
|
|
||||||
SchurDifferentiableOperator<Impl> VdagV(NumOp);
|
|
||||||
ConjugateGradientMultiShift<FermionField> msCG_V(param.MaxIter,PowerNegQuarter);
|
|
||||||
msCG_V(VdagV,tmp,PhiOdd);
|
|
||||||
|
|
||||||
assert(NumOp.ConstEE() == 1);
|
|
||||||
assert(DenOp.ConstEE() == 1);
|
|
||||||
PhiEven = Zero();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
// 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
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
virtual RealD S(const GaugeField &U) {
|
|
||||||
|
|
||||||
NumOp.ImportGauge(U);
|
|
||||||
DenOp.ImportGauge(U);
|
|
||||||
|
|
||||||
FermionField X(NumOp.FermionRedBlackGrid());
|
|
||||||
FermionField Y(NumOp.FermionRedBlackGrid());
|
|
||||||
|
|
||||||
// VdagV^1/4 Phi
|
|
||||||
SchurDifferentiableOperator<Impl> VdagV(NumOp);
|
|
||||||
ConjugateGradientMultiShift<FermionField> msCG_V(param.MaxIter,PowerQuarter);
|
|
||||||
msCG_V(VdagV,PhiOdd,X);
|
|
||||||
|
|
||||||
// MdagM^-1/4 VdagV^1/4 Phi
|
|
||||||
SchurDifferentiableOperator<Impl> MdagM(DenOp);
|
|
||||||
ConjugateGradientMultiShift<FermionField> msCG_M(param.MaxIter,PowerNegQuarter);
|
|
||||||
msCG_M(MdagM,X,Y);
|
|
||||||
|
|
||||||
// Randomly apply rational bounds checks.
|
|
||||||
auto grid = NumOp.FermionGrid();
|
|
||||||
auto r=rand();
|
|
||||||
grid->Broadcast(0,r);
|
|
||||||
if ( (r%param.BoundsCheckFreq)==0 ) {
|
|
||||||
FermionField gauss(NumOp.FermionRedBlackGrid());
|
|
||||||
gauss = Noise;
|
|
||||||
HighBoundCheck(MdagM,gauss,param.hi);
|
|
||||||
InverseSqrtBoundsCheck(param.MaxIter,param.tolerance*100,MdagM,gauss,PowerNegHalf);
|
|
||||||
ChebyBoundsCheck(MdagM,Noise,param.lo,param.hi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phidag VdagV^1/4 MdagM^-1/4 MdagM^-1/4 VdagV^1/4 Phi
|
|
||||||
RealD action = norm2(Y);
|
|
||||||
|
|
||||||
return action;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
// Here, M is some 5D operator and V is the Pauli-Villars field
|
|
||||||
// N and D makeup the rat. poly of the M term and P and & makeup the rat.poly of the denom term
|
|
||||||
//
|
|
||||||
// Need
|
|
||||||
// dS_f/dU = chi^dag d[P/Q] N/D P/Q chi
|
|
||||||
// + chi^dag P/Q d[N/D] P/Q chi
|
|
||||||
// + chi^dag P/Q N/D d[P/Q] chi
|
|
||||||
//
|
|
||||||
// P/Q is expressed as partial fraction expansion:
|
|
||||||
//
|
|
||||||
// a0 + \sum_k ak/(V^dagV + bk)
|
|
||||||
//
|
|
||||||
// d[P/Q] is then
|
|
||||||
//
|
|
||||||
// \sum_k -ak [V^dagV+bk]^{-1} [ dV^dag V + V^dag dV ] [V^dag V + bk]^{-1}
|
|
||||||
//
|
|
||||||
// and similar for N/D.
|
|
||||||
//
|
|
||||||
// Need
|
|
||||||
// MpvPhi_k = [Vdag V + bk]^{-1} chi
|
|
||||||
// MpvPhi = {a0 + \sum_k ak [Vdag V + bk]^{-1} }chi
|
|
||||||
//
|
|
||||||
// MfMpvPhi_k = [MdagM+bk]^{-1} MpvPhi
|
|
||||||
// MfMpvPhi = {a0 + \sum_k ak [Mdag M + bk]^{-1} } MpvPhi
|
|
||||||
//
|
|
||||||
// MpvMfMpvPhi_k = [Vdag V + bk]^{-1} MfMpvchi
|
|
||||||
//
|
|
||||||
|
|
||||||
virtual void deriv(const GaugeField &U,GaugeField & dSdU) {
|
|
||||||
|
|
||||||
const int n_f = MDPowerNegHalf.poles.size();
|
|
||||||
const int n_pv = MDPowerQuarter.poles.size();
|
|
||||||
|
|
||||||
std::vector<FermionField> MpvPhi_k (n_pv,NumOp.FermionRedBlackGrid());
|
|
||||||
std::vector<FermionField> MpvMfMpvPhi_k(n_pv,NumOp.FermionRedBlackGrid());
|
|
||||||
std::vector<FermionField> 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());
|
|
||||||
|
|
||||||
NumOp.ImportGauge(U);
|
|
||||||
DenOp.ImportGauge(U);
|
|
||||||
|
|
||||||
SchurDifferentiableOperator<Impl> VdagV(NumOp);
|
|
||||||
SchurDifferentiableOperator<Impl> MdagM(DenOp);
|
|
||||||
|
|
||||||
ConjugateGradientMultiShift<FermionField> msCG_V(param.MaxIter,MDPowerQuarter);
|
|
||||||
ConjugateGradientMultiShift<FermionField> msCG_M(param.MaxIter,MDPowerNegHalf);
|
|
||||||
|
|
||||||
msCG_V(VdagV,PhiOdd,MpvPhi_k,MpvPhi);
|
|
||||||
msCG_M(MdagM,MpvPhi,MfMpvPhi_k,MfMpvPhi);
|
|
||||||
msCG_V(VdagV,MfMpvPhi,MpvMfMpvPhi_k,MpvMfMpvPhi);
|
|
||||||
|
|
||||||
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)
|
|
||||||
for(int k=0;k<n_f;k++){
|
|
||||||
ak = MDPowerNegHalf.residues[k];
|
|
||||||
MdagM.Mpc(MfMpvPhi_k[k],Y);
|
|
||||||
MdagM.MpcDagDeriv(tmp , MfMpvPhi_k[k], Y ); dSdU=dSdU+ak*tmp;
|
|
||||||
MdagM.MpcDeriv(tmp , Y, MfMpvPhi_k[k] ); dSdU=dSdU+ak*tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//(2)
|
|
||||||
//(3)
|
|
||||||
for(int k=0;k<n_pv;k++){
|
|
||||||
|
|
||||||
ak = MDPowerQuarter.residues[k];
|
|
||||||
|
|
||||||
VdagV.Mpc(MpvPhi_k[k],Y);
|
|
||||||
VdagV.MpcDagDeriv(tmp,MpvMfMpvPhi_k[k],Y); dSdU=dSdU+ak*tmp;
|
|
||||||
VdagV.MpcDeriv (tmp,Y,MpvMfMpvPhi_k[k]); dSdU=dSdU+ak*tmp;
|
|
||||||
|
|
||||||
VdagV.Mpc(MpvMfMpvPhi_k[k],Y); // V as we take Ydag
|
|
||||||
VdagV.MpcDeriv (tmp,Y, MpvPhi_k[k]); dSdU=dSdU+ak*tmp;
|
|
||||||
VdagV.MpcDagDeriv(tmp,MpvPhi_k[k], Y); dSdU=dSdU+ak*tmp;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//dSdU = Ta(dSdU);
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
@ -40,6 +40,8 @@ directory
|
|||||||
#include <Grid/qcd/action/pseudofermion/OneFlavourRational.h>
|
#include <Grid/qcd/action/pseudofermion/OneFlavourRational.h>
|
||||||
#include <Grid/qcd/action/pseudofermion/OneFlavourRationalRatio.h>
|
#include <Grid/qcd/action/pseudofermion/OneFlavourRationalRatio.h>
|
||||||
#include <Grid/qcd/action/pseudofermion/OneFlavourEvenOddRational.h>
|
#include <Grid/qcd/action/pseudofermion/OneFlavourEvenOddRational.h>
|
||||||
|
#include <Grid/qcd/action/pseudofermion/GeneralEvenOddRationalRatio.h>
|
||||||
|
#include <Grid/qcd/action/pseudofermion/GeneralEvenOddRationalRatioMixedPrec.h>
|
||||||
#include <Grid/qcd/action/pseudofermion/OneFlavourEvenOddRationalRatio.h>
|
#include <Grid/qcd/action/pseudofermion/OneFlavourEvenOddRationalRatio.h>
|
||||||
#include <Grid/qcd/action/pseudofermion/ExactOneFlavourRatio.h>
|
#include <Grid/qcd/action/pseudofermion/ExactOneFlavourRatio.h>
|
||||||
|
|
||||||
|
@ -88,15 +88,9 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
const FermionField &getPhiOdd() const{ return PhiOdd; }
|
||||||
|
|
||||||
// P(phi) = e^{- phi^dag Vpc (MpcdagMpc)^-1 Vpcdag phi}
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
//
|
|
||||||
// NumOp == V
|
|
||||||
// DenOp == M
|
|
||||||
//
|
|
||||||
// Take phi_o = Vpcdag^{-1} Mpcdag eta_o ; eta_o = Mpcdag^{-1} Vpcdag Phi
|
|
||||||
//
|
|
||||||
// P(eta_o) = e^{- eta_o^dag eta_o}
|
// P(eta_o) = e^{- eta_o^dag eta_o}
|
||||||
//
|
//
|
||||||
// e^{x^2/2 sig^2} => sig^2 = 0.5.
|
// e^{x^2/2 sig^2} => sig^2 = 0.5.
|
||||||
@ -104,12 +98,22 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
RealD scale = std::sqrt(0.5);
|
RealD scale = std::sqrt(0.5);
|
||||||
|
|
||||||
FermionField eta (NumOp.FermionGrid());
|
FermionField eta (NumOp.FermionGrid());
|
||||||
|
gaussian(pRNG,eta); eta = eta * scale;
|
||||||
|
|
||||||
|
refresh(U,eta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh(const GaugeField &U, const FermionField &eta) {
|
||||||
|
|
||||||
|
// P(phi) = e^{- phi^dag Vpc (MpcdagMpc)^-1 Vpcdag phi}
|
||||||
|
//
|
||||||
|
// NumOp == V
|
||||||
|
// DenOp == M
|
||||||
|
//
|
||||||
FermionField etaOdd (NumOp.FermionRedBlackGrid());
|
FermionField etaOdd (NumOp.FermionRedBlackGrid());
|
||||||
FermionField etaEven(NumOp.FermionRedBlackGrid());
|
FermionField etaEven(NumOp.FermionRedBlackGrid());
|
||||||
FermionField tmp (NumOp.FermionRedBlackGrid());
|
FermionField tmp (NumOp.FermionRedBlackGrid());
|
||||||
|
|
||||||
gaussian(pRNG,eta);
|
|
||||||
|
|
||||||
pickCheckerboard(Even,etaEven,eta);
|
pickCheckerboard(Even,etaEven,eta);
|
||||||
pickCheckerboard(Odd,etaOdd,eta);
|
pickCheckerboard(Odd,etaOdd,eta);
|
||||||
|
|
||||||
@ -128,10 +132,6 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
// Even det factors
|
// Even det factors
|
||||||
DenOp.MooeeDag(etaEven,tmp);
|
DenOp.MooeeDag(etaEven,tmp);
|
||||||
NumOp.MooeeInvDag(tmp,PhiEven);
|
NumOp.MooeeInvDag(tmp,PhiEven);
|
||||||
|
|
||||||
PhiOdd =PhiOdd*scale;
|
|
||||||
PhiEven=PhiEven*scale;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
|
@ -151,12 +151,22 @@ public:
|
|||||||
Resources.GetCheckPointer()->CheckpointRestore(Parameters.StartTrajectory, U,
|
Resources.GetCheckPointer()->CheckpointRestore(Parameters.StartTrajectory, U,
|
||||||
Resources.GetSerialRNG(),
|
Resources.GetSerialRNG(),
|
||||||
Resources.GetParallelRNG());
|
Resources.GetParallelRNG());
|
||||||
|
} else if (Parameters.StartingType == "CheckpointStartReseed") {
|
||||||
|
// Same as CheckpointRestart but reseed the RNGs using the fixed integer seeding used for ColdStart and HotStart
|
||||||
|
// Useful for creating new evolution streams from an existing stream
|
||||||
|
|
||||||
|
// WARNING: Unfortunately because the checkpointer doesn't presently allow us to separately restore the RNG and gauge fields we have to load
|
||||||
|
// an existing RNG checkpoint first; make sure one is available and named correctly
|
||||||
|
Resources.GetCheckPointer()->CheckpointRestore(Parameters.StartTrajectory, U,
|
||||||
|
Resources.GetSerialRNG(),
|
||||||
|
Resources.GetParallelRNG());
|
||||||
|
Resources.SeedFixedIntegers();
|
||||||
} else {
|
} else {
|
||||||
// others
|
// others
|
||||||
std::cout << GridLogError << "Unrecognized StartingType\n";
|
std::cout << GridLogError << "Unrecognized StartingType\n";
|
||||||
std::cout
|
std::cout
|
||||||
<< GridLogError
|
<< GridLogError
|
||||||
<< "Valid [HotStart, ColdStart, TepidStart, CheckpointStart]\n";
|
<< "Valid [HotStart, ColdStart, TepidStart, CheckpointStart, CheckpointStartReseed]\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,9 @@ public:
|
|||||||
std::cout << GridLogError << "Seeds not initialized" << std::endl;
|
std::cout << GridLogError << "Seeds not initialized" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
std::cout << GridLogMessage << "Reseeding serial RNG with seed vector " << SerialSeeds << std::endl;
|
||||||
sRNG_.SeedFixedIntegers(SerialSeeds);
|
sRNG_.SeedFixedIntegers(SerialSeeds);
|
||||||
|
std::cout << GridLogMessage << "Reseeding parallel RNG with seed vector " << ParallelSeeds << std::endl;
|
||||||
pRNG_->SeedFixedIntegers(ParallelSeeds);
|
pRNG_->SeedFixedIntegers(ParallelSeeds);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -334,15 +334,19 @@ public:
|
|||||||
void refresh(Field& U, GridSerialRNG & sRNG, GridParallelRNG& pRNG)
|
void refresh(Field& U, GridSerialRNG & sRNG, GridParallelRNG& pRNG)
|
||||||
{
|
{
|
||||||
assert(P.Grid() == U.Grid());
|
assert(P.Grid() == U.Grid());
|
||||||
std::cout << GridLogIntegrator << "Integrator refresh\n";
|
std::cout << GridLogIntegrator << "Integrator refresh" << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogIntegrator << "Generating momentum" << std::endl;
|
||||||
FieldImplementation::generate_momenta(P, sRNG, pRNG);
|
FieldImplementation::generate_momenta(P, sRNG, pRNG);
|
||||||
|
|
||||||
// Update the smeared fields, can be implemented as observer
|
// Update the smeared fields, can be implemented as observer
|
||||||
// necessary to keep the fields updated even after a reject
|
// necessary to keep the fields updated even after a reject
|
||||||
// of the Metropolis
|
// of the Metropolis
|
||||||
|
std::cout << GridLogIntegrator << "Updating smeared fields" << std::endl;
|
||||||
Smearer.set_Field(U);
|
Smearer.set_Field(U);
|
||||||
// Set the (eventual) representations gauge fields
|
// Set the (eventual) representations gauge fields
|
||||||
|
|
||||||
|
std::cout << GridLogIntegrator << "Updating representations" << std::endl;
|
||||||
Representations.update(U);
|
Representations.update(U);
|
||||||
|
|
||||||
// The Smearer is attached to a pointer of the gauge field
|
// The Smearer is attached to a pointer of the gauge field
|
||||||
|
446
tests/forces/Test_gpdwf_force_1f_2f.cc
Normal file
446
tests/forces/Test_gpdwf_force_1f_2f.cc
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./forces/Test_gpdwf_force_1f_2f.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Christopher Kelly <ckelly@bnl.gov>
|
||||||
|
Author: paboyle <paboyle@ph.ed.ac.uk>
|
||||||
|
|
||||||
|
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 <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
|
||||||
|
//Here we test the G-parity action and force between the 1f (doubled-lattice) and 2f approaches
|
||||||
|
|
||||||
|
|
||||||
|
void copyConjGauge(LatticeGaugeFieldD &Umu_1f, const LatticeGaugeFieldD &Umu_2f, const int nu){
|
||||||
|
GridBase* UGrid_2f = Umu_2f.Grid();
|
||||||
|
GridBase* UGrid_1f = Umu_1f.Grid();
|
||||||
|
|
||||||
|
Replicate(Umu_2f,Umu_1f);
|
||||||
|
|
||||||
|
int L_2f = UGrid_2f->FullDimensions()[nu];
|
||||||
|
int L_1f = UGrid_1f->FullDimensions()[nu];
|
||||||
|
assert(L_1f == 2 * L_2f);
|
||||||
|
|
||||||
|
//Coordinate grid for reference
|
||||||
|
LatticeInteger xcoor_1f(UGrid_1f);
|
||||||
|
LatticeCoordinate(xcoor_1f,nu);
|
||||||
|
|
||||||
|
//Copy-conjugate the gauge field
|
||||||
|
//First C-shift the lattice by Lx/2
|
||||||
|
{
|
||||||
|
LatticeGaugeField Umu_shift = conjugate( Cshift(Umu_1f,nu,L_2f) );
|
||||||
|
Umu_1f = where( xcoor_1f >= Integer(L_2f), Umu_shift, Umu_1f );
|
||||||
|
|
||||||
|
//We use the in built APBC
|
||||||
|
//Make the gauge field antiperiodic in nu-direction
|
||||||
|
//decltype(PeekIndex<LorentzIndex>(Umu_1f,nu)) Unu(UGrid_1f);
|
||||||
|
//Unu = PeekIndex<LorentzIndex>(Umu_1f,nu);
|
||||||
|
//Unu = where(xcoor_1f == Integer(2*L_2f-1), -Unu, Unu);
|
||||||
|
//PokeIndex<LorentzIndex>(Umu_1f,Unu,nu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FermionField2f, typename FermionField1f>
|
||||||
|
void convertFermion1f_from_2f(FermionField1f &out_1f, const FermionField2f &in_2f, const int nu, bool is_4d){
|
||||||
|
GridBase* FGrid_1f = out_1f.Grid();
|
||||||
|
GridBase* FGrid_2f = in_2f.Grid();
|
||||||
|
|
||||||
|
int nuoff = is_4d ? 0 : 1; //s in 0 direction
|
||||||
|
|
||||||
|
int L_2f = FGrid_2f->FullDimensions()[nu+nuoff];
|
||||||
|
int L_1f = FGrid_1f->FullDimensions()[nu+nuoff];
|
||||||
|
assert(L_1f == 2 * L_2f);
|
||||||
|
|
||||||
|
auto in_f0_2fgrid = PeekIndex<GparityFlavourIndex>(in_2f,0); //flavor 0 on 2f Grid
|
||||||
|
FermionField1f in_f0_1fgrid(FGrid_1f);
|
||||||
|
Replicate(in_f0_2fgrid, in_f0_1fgrid); //has flavor 0 on both halves
|
||||||
|
|
||||||
|
auto in_f1_2fgrid = PeekIndex<GparityFlavourIndex>(in_2f,1); //flavor 1 on 2f Grid
|
||||||
|
FermionField1f in_f1_1fgrid(FGrid_1f);
|
||||||
|
Replicate(in_f1_2fgrid, in_f1_1fgrid); //has flavor 1 on both halves
|
||||||
|
|
||||||
|
LatticeInteger xcoor_1f(FGrid_1f);
|
||||||
|
LatticeCoordinate(xcoor_1f,nu+nuoff);
|
||||||
|
|
||||||
|
out_1f = where(xcoor_1f < L_2f, in_f0_1fgrid, in_f1_1fgrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename GparityAction, typename StandardAction>
|
||||||
|
class RatioActionSetupBase{
|
||||||
|
protected:
|
||||||
|
TwoFlavourEvenOddRatioPseudoFermionAction<WilsonImplD> *pf_1f;
|
||||||
|
TwoFlavourEvenOddRatioPseudoFermionAction<GparityWilsonImplD> *pf_2f;
|
||||||
|
|
||||||
|
GparityAction* action_2f;
|
||||||
|
GparityAction* action_PV_2f;
|
||||||
|
StandardAction* action_1f;
|
||||||
|
StandardAction* action_PV_1f;
|
||||||
|
|
||||||
|
ConjugateGradient<typename StandardAction::FermionField> CG_1f;
|
||||||
|
ConjugateGradient<typename GparityAction::FermionField> CG_2f;
|
||||||
|
|
||||||
|
RatioActionSetupBase(): CG_1f(1.0e-8,10000), CG_2f(1.0e-8,10000){}
|
||||||
|
|
||||||
|
void setupPseudofermion(){
|
||||||
|
pf_1f = new TwoFlavourEvenOddRatioPseudoFermionAction<WilsonImplD>(*action_PV_1f, *action_1f, CG_1f, CG_1f);
|
||||||
|
pf_2f = new TwoFlavourEvenOddRatioPseudoFermionAction<GparityWilsonImplD>(*action_PV_2f, *action_2f, CG_2f, CG_2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
GparityAction & action2f(){ return *action_2f; }
|
||||||
|
StandardAction & action1f(){ return *action_1f; }
|
||||||
|
|
||||||
|
void refreshAction(LatticeGaugeField &Umu_2f, typename GparityAction::FermionField &eta_2f,
|
||||||
|
LatticeGaugeField &Umu_1f, typename StandardAction::FermionField &eta_1f){
|
||||||
|
pf_1f->refresh(Umu_1f, eta_1f);
|
||||||
|
pf_2f->refresh(Umu_2f, eta_2f);
|
||||||
|
|
||||||
|
//Compare PhiOdd
|
||||||
|
RealD norm_1f = norm2(pf_1f->getPhiOdd());
|
||||||
|
RealD norm_2f = norm2(pf_2f->getPhiOdd());
|
||||||
|
|
||||||
|
std::cout << "Test PhiOdd 2f: " << norm_2f << " 1f: " << norm_1f << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeAction(RealD &S_2f, RealD &S_1f, LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f){
|
||||||
|
S_1f = pf_1f->S(Umu_1f);
|
||||||
|
S_2f = pf_2f->S(Umu_2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeDeriv(LatticeGaugeField &deriv_2f, LatticeGaugeField &deriv_1f, LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f){
|
||||||
|
pf_1f->deriv(Umu_1f, deriv_1f);
|
||||||
|
pf_2f->deriv(Umu_2f, deriv_2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename GparityAction, typename StandardAction>
|
||||||
|
struct setupAction{};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct setupAction<GparityWilsonTMFermionD, WilsonTMFermionD>: public RatioActionSetupBase<GparityWilsonTMFermionD, WilsonTMFermionD>{
|
||||||
|
typedef GparityWilsonTMFermionD GparityAction;
|
||||||
|
typedef WilsonTMFermionD StandardAction;
|
||||||
|
|
||||||
|
setupAction(GridCartesian* UGrid_2f, GridRedBlackCartesian* UrbGrid_2f, GridCartesian* FGrid_2f, GridRedBlackCartesian* FrbGrid_2f,
|
||||||
|
GridCartesian* UGrid_1f, GridRedBlackCartesian* UrbGrid_1f, GridCartesian* FGrid_1f, GridRedBlackCartesian* FrbGrid_1f,
|
||||||
|
LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f, int nu): RatioActionSetupBase(){
|
||||||
|
RealD mass=-1.8;
|
||||||
|
//Use same DSDR twists as https://arxiv.org/pdf/1208.4412.pdf
|
||||||
|
RealD epsilon_f = 0.02; //numerator (in determinant)
|
||||||
|
RealD epsilon_b = 0.5;
|
||||||
|
|
||||||
|
std::vector<int> twists(Nd,0);
|
||||||
|
twists[nu] = 1; //GPBC in y
|
||||||
|
twists[3] = 1; //APBC
|
||||||
|
GparityAction::ImplParams params_2f; params_2f.twists = twists;
|
||||||
|
action_2f = new GparityWilsonTMFermionD(Umu_2f,*UGrid_2f,*UrbGrid_2f, mass, epsilon_f, params_2f);
|
||||||
|
action_PV_2f = new GparityWilsonTMFermionD(Umu_2f,*UGrid_2f,*UrbGrid_2f, mass, epsilon_b, params_2f);
|
||||||
|
|
||||||
|
DomainWallFermionD::ImplParams params_1f;
|
||||||
|
params_1f.boundary_phases[nu] = -1;
|
||||||
|
params_1f.boundary_phases[3] = -1;
|
||||||
|
|
||||||
|
action_1f = new WilsonTMFermionD(Umu_1f,*UGrid_1f,*UrbGrid_1f, mass, epsilon_f, params_1f);
|
||||||
|
action_PV_1f = new WilsonTMFermionD(Umu_1f,*UGrid_1f,*UrbGrid_1f, mass, epsilon_b, params_1f);
|
||||||
|
|
||||||
|
setupPseudofermion();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is4d(){ return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct setupAction<GparityDomainWallFermionD, DomainWallFermionD>: public RatioActionSetupBase<GparityDomainWallFermionD, DomainWallFermionD>{
|
||||||
|
typedef GparityDomainWallFermionD GparityAction;
|
||||||
|
typedef DomainWallFermionD StandardAction;
|
||||||
|
|
||||||
|
setupAction(GridCartesian* UGrid_2f, GridRedBlackCartesian* UrbGrid_2f, GridCartesian* FGrid_2f, GridRedBlackCartesian* FrbGrid_2f,
|
||||||
|
GridCartesian* UGrid_1f, GridRedBlackCartesian* UrbGrid_1f, GridCartesian* FGrid_1f, GridRedBlackCartesian* FrbGrid_1f,
|
||||||
|
LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f, int nu): RatioActionSetupBase(){
|
||||||
|
RealD mass=0.01;
|
||||||
|
RealD M5=1.8;
|
||||||
|
|
||||||
|
std::vector<int> twists(Nd,0);
|
||||||
|
twists[nu] = 1; //GPBC in y
|
||||||
|
twists[3] = 1; //APBC
|
||||||
|
GparityDomainWallFermionD::ImplParams params_2f; params_2f.twists = twists;
|
||||||
|
action_2f = new GparityDomainWallFermionD(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f,mass,M5,params_2f);
|
||||||
|
action_PV_2f = new GparityDomainWallFermionD(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f,1.0,M5,params_2f);
|
||||||
|
|
||||||
|
DomainWallFermionD::ImplParams params_1f;
|
||||||
|
params_1f.boundary_phases[nu] = -1;
|
||||||
|
params_1f.boundary_phases[3] = -1;
|
||||||
|
|
||||||
|
action_1f = new DomainWallFermionD(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f,mass,M5,params_1f);
|
||||||
|
action_PV_1f = new DomainWallFermionD(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f,1.0,M5,params_1f);
|
||||||
|
|
||||||
|
setupPseudofermion();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is4d(){ return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//For EOFA we need a different pseudofermion type
|
||||||
|
template<>
|
||||||
|
struct setupAction<GparityDomainWallEOFAFermionD, DomainWallEOFAFermionD>{
|
||||||
|
typedef GparityDomainWallEOFAFermionD GparityAction;
|
||||||
|
typedef DomainWallEOFAFermionD StandardAction;
|
||||||
|
|
||||||
|
ExactOneFlavourRatioPseudoFermionAction<WilsonImplD> *pf_1f;
|
||||||
|
ExactOneFlavourRatioPseudoFermionAction<GparityWilsonImplD> *pf_2f;
|
||||||
|
|
||||||
|
GparityAction* action_2f;
|
||||||
|
GparityAction* action_PV_2f;
|
||||||
|
StandardAction* action_1f;
|
||||||
|
StandardAction* action_PV_1f;
|
||||||
|
|
||||||
|
ConjugateGradient<typename StandardAction::FermionField> CG_1f;
|
||||||
|
ConjugateGradient<typename GparityAction::FermionField> CG_2f;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GparityAction & action2f(){ return *action_2f; }
|
||||||
|
StandardAction & action1f(){ return *action_1f; }
|
||||||
|
|
||||||
|
void refreshAction(LatticeGaugeField &Umu_2f, typename GparityAction::FermionField &eta_2f,
|
||||||
|
LatticeGaugeField &Umu_1f, typename StandardAction::FermionField &eta_1f){
|
||||||
|
pf_1f->refresh(Umu_1f, eta_1f);
|
||||||
|
pf_2f->refresh(Umu_2f, eta_2f);
|
||||||
|
|
||||||
|
//Compare PhiOdd
|
||||||
|
RealD norm_1f = norm2(pf_1f->getPhi());
|
||||||
|
RealD norm_2f = norm2(pf_2f->getPhi());
|
||||||
|
|
||||||
|
std::cout << "Test Phi 2f: " << norm_2f << " 1f: " << norm_1f << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeAction(RealD &S_2f, RealD &S_1f, LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f){
|
||||||
|
S_1f = pf_1f->S(Umu_1f);
|
||||||
|
S_2f = pf_2f->S(Umu_2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeDeriv(LatticeGaugeField &deriv_2f, LatticeGaugeField &deriv_1f, LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f){
|
||||||
|
pf_1f->deriv(Umu_1f, deriv_1f);
|
||||||
|
pf_2f->deriv(Umu_2f, deriv_2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setupAction(GridCartesian* UGrid_2f, GridRedBlackCartesian* UrbGrid_2f, GridCartesian* FGrid_2f, GridRedBlackCartesian* FrbGrid_2f,
|
||||||
|
GridCartesian* UGrid_1f, GridRedBlackCartesian* UrbGrid_1f, GridCartesian* FGrid_1f, GridRedBlackCartesian* FrbGrid_1f,
|
||||||
|
LatticeGaugeField &Umu_2f, LatticeGaugeField &Umu_1f, int nu): CG_1f(1.0e-8,10000), CG_2f(1.0e-8,10000){
|
||||||
|
RealD mass=0.01;
|
||||||
|
RealD M5=1.8;
|
||||||
|
|
||||||
|
std::vector<int> twists(Nd,0);
|
||||||
|
twists[nu] = 1; //GPBC in y
|
||||||
|
twists[3] = 1; //APBC
|
||||||
|
GparityAction::ImplParams params_2f; params_2f.twists = twists;
|
||||||
|
action_2f = new GparityAction(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f, mass, mass, 1.0, 0.0, -1, M5, params_2f);
|
||||||
|
action_PV_2f = new GparityAction(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f, 1.0, mass, 1.0, -1.0, 1, M5, params_2f); //cf Test_dwf_gpforce_eofa.cc
|
||||||
|
|
||||||
|
StandardAction::ImplParams params_1f;
|
||||||
|
params_1f.boundary_phases[nu] = -1;
|
||||||
|
params_1f.boundary_phases[3] = -1;
|
||||||
|
|
||||||
|
action_1f = new StandardAction(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f, mass, mass, 1.0, 0.0, -1, M5, params_1f);
|
||||||
|
action_PV_1f = new StandardAction(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f, 1.0, mass, 1.0, -1.0, 1, M5, params_1f);
|
||||||
|
|
||||||
|
OneFlavourRationalParams RationalParams(0.95, 100.0, 5000, 1.0e-12, 12);
|
||||||
|
|
||||||
|
pf_1f = new ExactOneFlavourRatioPseudoFermionAction<WilsonImplD>(*action_1f, *action_PV_1f, CG_1f, CG_1f, CG_1f, CG_1f, CG_1f, RationalParams, true);
|
||||||
|
pf_2f = new ExactOneFlavourRatioPseudoFermionAction<GparityWilsonImplD>(*action_2f, *action_PV_2f, CG_2f, CG_2f, CG_2f, CG_2f, CG_2f, RationalParams, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is4d(){ return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename GparityAction, typename StandardAction>
|
||||||
|
void runTest(int argc, char** argv){
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
const int nu = 1;
|
||||||
|
Coordinate latt_2f = GridDefaultLatt();
|
||||||
|
Coordinate latt_1f = latt_2f;
|
||||||
|
latt_1f[nu] *= 2;
|
||||||
|
|
||||||
|
Coordinate simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
Coordinate mpi_layout = GridDefaultMpi();
|
||||||
|
|
||||||
|
const int Ls=8;
|
||||||
|
|
||||||
|
GridCartesian * UGrid_1f = SpaceTimeGrid::makeFourDimGrid(latt_1f, simd_layout, mpi_layout);
|
||||||
|
GridRedBlackCartesian * UrbGrid_1f = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid_1f);
|
||||||
|
GridCartesian * FGrid_1f = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid_1f);
|
||||||
|
GridRedBlackCartesian * FrbGrid_1f = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid_1f);
|
||||||
|
|
||||||
|
|
||||||
|
GridCartesian * UGrid_2f = SpaceTimeGrid::makeFourDimGrid(latt_2f, simd_layout, mpi_layout);
|
||||||
|
GridRedBlackCartesian * UrbGrid_2f = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid_2f);
|
||||||
|
GridCartesian * FGrid_2f = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid_2f);
|
||||||
|
GridRedBlackCartesian * FrbGrid_2f = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid_2f);
|
||||||
|
|
||||||
|
std::vector<int> seeds4({1,2,3,4});
|
||||||
|
std::vector<int> seeds5({5,6,7,8});
|
||||||
|
GridParallelRNG RNG5_2f(FGrid_2f); RNG5_2f.SeedFixedIntegers(seeds5);
|
||||||
|
GridParallelRNG RNG4_2f(UGrid_2f); RNG4_2f.SeedFixedIntegers(seeds4);
|
||||||
|
|
||||||
|
LatticeGaugeField Umu_2f(UGrid_2f);
|
||||||
|
SU<Nc>::HotConfiguration(RNG4_2f,Umu_2f);
|
||||||
|
|
||||||
|
LatticeGaugeField Umu_1f(UGrid_1f);
|
||||||
|
copyConjGauge(Umu_1f, Umu_2f, nu);
|
||||||
|
|
||||||
|
typedef typename GparityAction::FermionField GparityFermionField;
|
||||||
|
typedef typename StandardAction::FermionField StandardFermionField;
|
||||||
|
|
||||||
|
setupAction<GparityAction, StandardAction> setup(UGrid_2f, UrbGrid_2f, FGrid_2f, FrbGrid_2f,
|
||||||
|
UGrid_1f, UrbGrid_1f, FGrid_1f, FrbGrid_1f,
|
||||||
|
Umu_2f, Umu_1f, nu);
|
||||||
|
GridBase* FGrid_2f_a = setup.action2f().FermionGrid();
|
||||||
|
GridBase* FGrid_1f_a = setup.action1f().FermionGrid();
|
||||||
|
GridBase* FrbGrid_2f_a = setup.action2f().FermionRedBlackGrid();
|
||||||
|
GridBase* FrbGrid_1f_a = setup.action1f().FermionRedBlackGrid();
|
||||||
|
bool is_4d = setup.is4d();
|
||||||
|
|
||||||
|
//Check components by doing an inversion
|
||||||
|
{
|
||||||
|
setup.action2f().ImportGauge(Umu_2f);
|
||||||
|
setup.action1f().ImportGauge(Umu_1f);
|
||||||
|
|
||||||
|
GparityFermionField src_2f(FGrid_2f_a);
|
||||||
|
gaussian(is_4d ? RNG4_2f : RNG5_2f, src_2f);
|
||||||
|
|
||||||
|
StandardFermionField src_1f(FGrid_1f_a);
|
||||||
|
convertFermion1f_from_2f(src_1f, src_2f, nu, is_4d);
|
||||||
|
|
||||||
|
StandardFermionField src_o_1f(FrbGrid_1f_a);
|
||||||
|
StandardFermionField result_o_1f(FrbGrid_1f_a);
|
||||||
|
pickCheckerboard(Odd,src_o_1f,src_1f);
|
||||||
|
result_o_1f=Zero();
|
||||||
|
|
||||||
|
SchurDiagMooeeOperator<StandardAction,StandardFermionField> HermOpEO_1f(setup.action1f());
|
||||||
|
ConjugateGradient<StandardFermionField> CG_1f(1.0e-8,10000);
|
||||||
|
CG_1f(HermOpEO_1f,src_o_1f,result_o_1f);
|
||||||
|
|
||||||
|
|
||||||
|
GparityFermionField src_o_2f(FrbGrid_2f_a);
|
||||||
|
GparityFermionField result_o_2f(FrbGrid_2f_a);
|
||||||
|
pickCheckerboard(Odd,src_o_2f,src_2f);
|
||||||
|
result_o_2f=Zero();
|
||||||
|
|
||||||
|
SchurDiagMooeeOperator<GparityAction,GparityFermionField> HermOpEO_2f(setup.action2f());
|
||||||
|
ConjugateGradient<GparityFermionField> CG_2f(1.0e-8,10000);
|
||||||
|
CG_2f(HermOpEO_2f,src_o_2f,result_o_2f);
|
||||||
|
|
||||||
|
RealD norm_1f = norm2(result_o_1f);
|
||||||
|
RealD norm_2f = norm2(result_o_2f);
|
||||||
|
|
||||||
|
std::cout << "Test fermion inversion 2f: " << norm_2f << " 1f: " << norm_1f << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate eta
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
|
||||||
|
GparityFermionField eta_2f(FGrid_2f_a);
|
||||||
|
gaussian(is_4d ? RNG4_2f : RNG5_2f,eta_2f); eta_2f = eta_2f * scale;
|
||||||
|
|
||||||
|
StandardFermionField eta_1f(FGrid_1f_a);
|
||||||
|
convertFermion1f_from_2f(eta_1f, eta_2f, nu, is_4d);
|
||||||
|
|
||||||
|
setup.refreshAction(Umu_2f, eta_2f, Umu_1f, eta_1f);
|
||||||
|
|
||||||
|
//Initial action is just |eta^2|
|
||||||
|
RealD S_1f, S_2f;
|
||||||
|
|
||||||
|
setup.computeAction(S_2f, S_1f, Umu_2f, Umu_1f);
|
||||||
|
|
||||||
|
std::cout << "Test Initial action 2f: " << S_2f << " 1f: " << S_1f << " diff: " << S_2f - S_1f << std::endl;
|
||||||
|
|
||||||
|
//Do a random gauge field refresh
|
||||||
|
SU<Nc>::HotConfiguration(RNG4_2f,Umu_2f);
|
||||||
|
copyConjGauge(Umu_1f, Umu_2f, nu);
|
||||||
|
|
||||||
|
//Compute the action again
|
||||||
|
setup.computeAction(S_2f, S_1f, Umu_2f, Umu_1f);
|
||||||
|
|
||||||
|
std::cout << "Test Action after gauge field randomize 2f: " << S_2f << " 1f: " << S_1f << " diff: " << S_2f - S_1f << std::endl;
|
||||||
|
|
||||||
|
//Compute the derivative and test the conjugate relation
|
||||||
|
LatticeGaugeField deriv_2f(UGrid_2f);
|
||||||
|
LatticeGaugeField deriv_1f(UGrid_1f);
|
||||||
|
setup.computeDeriv(deriv_2f, deriv_1f, Umu_2f, Umu_1f);
|
||||||
|
|
||||||
|
//Have to combine the two forces on the 1f by symmetrizing under the complex conjugate
|
||||||
|
{
|
||||||
|
RealD norm2_pre = norm2(deriv_1f);
|
||||||
|
LatticeGaugeField deriv_1f_shift = conjugate( Cshift(deriv_1f, nu, latt_2f[nu]) );
|
||||||
|
deriv_1f = deriv_1f + deriv_1f_shift;
|
||||||
|
std::cout << "Test combine/symmetrize forces on 1f lattice, dS/dU : " << norm2_pre << " -> " << norm2(deriv_1f) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
LatticeGaugeField deriv_1f_from_2f(UGrid_1f);
|
||||||
|
copyConjGauge(deriv_1f_from_2f, deriv_2f, nu);
|
||||||
|
std::cout << "Test copy-conj 2f dS/dU to obtain equivalent 1f force : " << norm2(deriv_2f) << " -> " << norm2(deriv_1f_from_2f) << std::endl;
|
||||||
|
|
||||||
|
LatticeGaugeField diff_deriv_1f = deriv_1f - deriv_1f_from_2f;
|
||||||
|
|
||||||
|
std::cout << "Test dS/dU 1f constructed from 2f derivative: " << norm2(deriv_1f_from_2f) << " dS/dU 1f actual: " << norm2(deriv_1f) << " Norm of difference: " << norm2(diff_deriv_1f) << std::endl;
|
||||||
|
|
||||||
|
std::cout<< GridLogMessage << "Done" <<std::endl;
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
std::string action = "DWF";
|
||||||
|
for(int i=1;i<argc;i++){
|
||||||
|
if(std::string(argv[i]) == "--action"){
|
||||||
|
action = argv[i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action == "DWF"){
|
||||||
|
runTest<GparityDomainWallFermionD, DomainWallFermionD>(argc, argv);
|
||||||
|
}else if(action == "EOFA"){
|
||||||
|
runTest<GparityDomainWallEOFAFermionD, DomainWallEOFAFermionD>(argc, argv);
|
||||||
|
}else if(action == "DSDR"){
|
||||||
|
runTest<GparityWilsonTMFermionD, WilsonTMFermionD>(argc,argv);
|
||||||
|
}else{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
@ -89,7 +89,49 @@ int main (int argc, char** argv)
|
|||||||
ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, CG, CG, CG, CG, Params, false);
|
ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, CG, CG, CG, CG, Params, false);
|
||||||
|
|
||||||
GridSerialRNG sRNG; sRNG.SeedFixedIntegers(seeds4);
|
GridSerialRNG sRNG; sRNG.SeedFixedIntegers(seeds4);
|
||||||
|
|
||||||
|
//Check the rational approximation
|
||||||
|
{
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
LatticeFermion eta (Lop.FermionGrid());
|
||||||
|
gaussian(RNG5,eta); eta = eta * scale;
|
||||||
|
|
||||||
|
Meofa.refresh(U, eta);
|
||||||
|
|
||||||
|
//Phi = M^{-1/2} eta
|
||||||
|
//M is Hermitian
|
||||||
|
//(Phi, M Phi) = eta^\dagger M^{-1/2} M M^{-1/2} eta = eta^\dagger eta
|
||||||
|
LatticeFermion phi = Meofa.getPhi();
|
||||||
|
LatticeFermion Mphi(FGrid);
|
||||||
|
|
||||||
|
Meofa.Meofa(U, phi, Mphi);
|
||||||
|
std::cout << "Computing inner product" << std::endl;
|
||||||
|
ComplexD inner = innerProduct(phi, Mphi);
|
||||||
|
ComplexD test = inner - norm2(eta);
|
||||||
|
|
||||||
|
std::cout << "(phi, Mphi) - (eta,eta): " << test << " expect 0" << std::endl;
|
||||||
|
|
||||||
|
assert(test.real() < 1e-8);
|
||||||
|
assert(test.imag() < 1e-8);
|
||||||
|
|
||||||
|
//Another test is to use heatbath twice to apply M^{-1/2} to Phi then apply M
|
||||||
|
// M Phi'
|
||||||
|
//= M M^{-1/2} Phi
|
||||||
|
//= M M^{-1/2} M^{-1/2} eta
|
||||||
|
//= eta
|
||||||
|
Meofa.refresh(U, phi);
|
||||||
|
LatticeFermion phi2 = Meofa.getPhi();
|
||||||
|
LatticeFermion test2(FGrid);
|
||||||
|
Meofa.Meofa(U, phi2, test2);
|
||||||
|
test2 = test2 - eta;
|
||||||
|
RealD test2_norm = norm2(test2);
|
||||||
|
std::cout << "|M M^{-1/2} M^{-1/2} eta - eta|^2 = " << test2_norm << " expect 0" << std::endl;
|
||||||
|
assert( test2_norm < 1e-8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Meofa.refresh(U, sRNG, RNG5 );
|
Meofa.refresh(U, sRNG, RNG5 );
|
||||||
|
|
||||||
RealD S = Meofa.S(U); // pdag M p
|
RealD S = Meofa.S(U); // pdag M p
|
||||||
|
|
||||||
// get the deriv of phidag M phi with respect to "U"
|
// get the deriv of phidag M phi with respect to "U"
|
||||||
|
233
tests/forces/Test_mobius_gparity_eofa_mixed.cc
Normal file
233
tests/forces/Test_mobius_gparity_eofa_mixed.cc
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/forces/Test_mobius_gparity_eofa_mixed.cc
|
||||||
|
|
||||||
|
Copyright (C) 2017
|
||||||
|
|
||||||
|
Author: Christopher Kelly <ckelly@bnl.gov>
|
||||||
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
Author: David Murphy <dmurphy@phys.columbia.edu>
|
||||||
|
|
||||||
|
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 <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
;
|
||||||
|
|
||||||
|
typedef GparityWilsonImplD FermionImplPolicyD;
|
||||||
|
typedef GparityMobiusEOFAFermionD FermionActionD;
|
||||||
|
typedef typename FermionActionD::FermionField FermionFieldD;
|
||||||
|
|
||||||
|
typedef GparityWilsonImplF FermionImplPolicyF;
|
||||||
|
typedef GparityMobiusEOFAFermionF FermionActionF;
|
||||||
|
typedef typename FermionActionF::FermionField FermionFieldF;
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
template<class FermionOperatorD, class FermionOperatorF, class SchurOperatorD, class SchurOperatorF>
|
||||||
|
class MixedPrecisionConjugateGradientOperatorFunction : public OperatorFunction<typename FermionOperatorD::FermionField> {
|
||||||
|
public:
|
||||||
|
typedef typename FermionOperatorD::FermionField FieldD;
|
||||||
|
typedef typename FermionOperatorF::FermionField FieldF;
|
||||||
|
|
||||||
|
using OperatorFunction<FieldD>::operator();
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
RealD InnerTolerance; //Initial tolerance for inner CG. Defaults to Tolerance but can be changed
|
||||||
|
Integer MaxInnerIterations;
|
||||||
|
Integer MaxOuterIterations;
|
||||||
|
GridBase* SinglePrecGrid4; //Grid for single-precision fields
|
||||||
|
GridBase* SinglePrecGrid5; //Grid for single-precision fields
|
||||||
|
RealD OuterLoopNormMult; //Stop the outer loop and move to a final double prec solve when the residual is OuterLoopNormMult * Tolerance
|
||||||
|
|
||||||
|
FermionOperatorF &FermOpF;
|
||||||
|
FermionOperatorD &FermOpD;;
|
||||||
|
SchurOperatorF &LinOpF;
|
||||||
|
SchurOperatorD &LinOpD;
|
||||||
|
|
||||||
|
Integer TotalInnerIterations; //Number of inner CG iterations
|
||||||
|
Integer TotalOuterIterations; //Number of restarts
|
||||||
|
Integer TotalFinalStepIterations; //Number of CG iterations in final patch-up step
|
||||||
|
|
||||||
|
MixedPrecisionConjugateGradientOperatorFunction(RealD tol,
|
||||||
|
Integer maxinnerit,
|
||||||
|
Integer maxouterit,
|
||||||
|
GridBase* _sp_grid4,
|
||||||
|
GridBase* _sp_grid5,
|
||||||
|
FermionOperatorF &_FermOpF,
|
||||||
|
FermionOperatorD &_FermOpD,
|
||||||
|
SchurOperatorF &_LinOpF,
|
||||||
|
SchurOperatorD &_LinOpD):
|
||||||
|
LinOpF(_LinOpF),
|
||||||
|
LinOpD(_LinOpD),
|
||||||
|
FermOpF(_FermOpF),
|
||||||
|
FermOpD(_FermOpD),
|
||||||
|
Tolerance(tol),
|
||||||
|
InnerTolerance(tol),
|
||||||
|
MaxInnerIterations(maxinnerit),
|
||||||
|
MaxOuterIterations(maxouterit),
|
||||||
|
SinglePrecGrid4(_sp_grid4),
|
||||||
|
SinglePrecGrid5(_sp_grid5),
|
||||||
|
OuterLoopNormMult(100.)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<FieldD> &LinOpU, const FieldD &src, FieldD &psi) {
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << " Mixed precision CG wrapper operator() "<<std::endl;
|
||||||
|
|
||||||
|
SchurOperatorD * SchurOpU = static_cast<SchurOperatorD *>(&LinOpU);
|
||||||
|
assert(&(SchurOpU->_Mat)==&(LinOpD._Mat));
|
||||||
|
|
||||||
|
precisionChange(FermOpF.Umu, FermOpD.Umu);
|
||||||
|
|
||||||
|
pickCheckerboard(Even,FermOpF.UmuEven,FermOpF.Umu);
|
||||||
|
pickCheckerboard(Odd ,FermOpF.UmuOdd ,FermOpF.Umu);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Make a mixed precision conjugate gradient
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
MixedPrecisionConjugateGradient<FieldD,FieldF> MPCG(Tolerance,MaxInnerIterations,MaxOuterIterations,SinglePrecGrid5,LinOpF,LinOpD);
|
||||||
|
MPCG.InnerTolerance = InnerTolerance;
|
||||||
|
std::cout << GridLogMessage << "Calling mixed precision Conjugate Gradient" <<std::endl;
|
||||||
|
MPCG(src,psi);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
|
||||||
|
Coordinate latt_size = GridDefaultLatt();
|
||||||
|
Coordinate mpi_layout = GridDefaultMpi();
|
||||||
|
|
||||||
|
const int Ls = 8;
|
||||||
|
|
||||||
|
GridCartesian *UGridD = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplexD::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *UrbGridD = SpaceTimeGrid::makeFourDimRedBlackGrid(UGridD);
|
||||||
|
GridCartesian *FGridD = SpaceTimeGrid::makeFiveDimGrid(Ls, UGridD);
|
||||||
|
GridRedBlackCartesian *FrbGridD = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGridD);
|
||||||
|
|
||||||
|
GridCartesian *UGridF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplexF::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *UrbGridF = SpaceTimeGrid::makeFourDimRedBlackGrid(UGridF);
|
||||||
|
GridCartesian *FGridF = SpaceTimeGrid::makeFiveDimGrid(Ls, UGridF);
|
||||||
|
GridRedBlackCartesian *FrbGridF = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGridF);
|
||||||
|
|
||||||
|
std::vector<int> seeds4({1,2,3,5});
|
||||||
|
std::vector<int> seeds5({5,6,7,8});
|
||||||
|
GridParallelRNG RNG5(FGridD); RNG5.SeedFixedIntegers(seeds5);
|
||||||
|
GridParallelRNG RNG4(UGridD); RNG4.SeedFixedIntegers(seeds4);
|
||||||
|
|
||||||
|
int threads = GridThread::GetThreads();
|
||||||
|
std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl;
|
||||||
|
|
||||||
|
LatticeGaugeFieldD Ud(UGridD);
|
||||||
|
SU<Nc>::HotConfiguration(RNG4,Ud);
|
||||||
|
|
||||||
|
LatticeGaugeFieldF Uf(UGridF);
|
||||||
|
precisionChange(Uf, Ud);
|
||||||
|
|
||||||
|
RealD b = 2.5;
|
||||||
|
RealD c = 1.5;
|
||||||
|
RealD mf = 0.01;
|
||||||
|
RealD mb = 1.0;
|
||||||
|
RealD M5 = 1.8;
|
||||||
|
FermionActionD::ImplParams params;
|
||||||
|
params.twists[0] = 1; //GPBC in X
|
||||||
|
params.twists[Nd-1] = 1; //APRD in T
|
||||||
|
|
||||||
|
std::vector<int> gtwists(4,0);
|
||||||
|
gtwists[0] = 1;
|
||||||
|
|
||||||
|
ConjugateGimplD::setDirections(gtwists);
|
||||||
|
|
||||||
|
FermionActionD LopD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, mf, mf, mb, 0.0, -1, M5, b, c, params);
|
||||||
|
FermionActionD RopD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, mb, mf, mb, -1.0, 1, M5, b, c, params);
|
||||||
|
|
||||||
|
FermionActionF LopF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, mf, mf, mb, 0.0, -1, M5, b, c, params);
|
||||||
|
FermionActionF RopF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, mb, mf, mb, -1.0, 1, M5, b, c, params);
|
||||||
|
|
||||||
|
|
||||||
|
OneFlavourRationalParams OFRp(0.95, 100.0, 5000, 1.0e-12, 12);
|
||||||
|
ConjugateGradient<FermionFieldD> CG(1.0e-10, 10000);
|
||||||
|
|
||||||
|
|
||||||
|
typedef SchurDiagMooeeOperator<FermionActionD,FermionFieldD> EOFAschuropD;
|
||||||
|
typedef SchurDiagMooeeOperator<FermionActionF,FermionFieldF> EOFAschuropF;
|
||||||
|
|
||||||
|
EOFAschuropD linopL_D(LopD);
|
||||||
|
EOFAschuropD linopR_D(RopD);
|
||||||
|
|
||||||
|
EOFAschuropF linopL_F(LopF);
|
||||||
|
EOFAschuropF linopR_F(RopF);
|
||||||
|
|
||||||
|
typedef MixedPrecisionConjugateGradientOperatorFunction<FermionActionD, FermionActionF, EOFAschuropD, EOFAschuropF> EOFA_mxCG;
|
||||||
|
|
||||||
|
EOFA_mxCG MCG_L(1e-10, 10000, 1000, UGridF, FrbGridF, LopF, LopD, linopL_F, linopL_D);
|
||||||
|
MCG_L.InnerTolerance = 1e-5;
|
||||||
|
|
||||||
|
EOFA_mxCG MCG_R(1e-10, 10000, 1000, UGridF, FrbGridF, RopF, RopD, linopR_F, linopR_D);
|
||||||
|
MCG_R.InnerTolerance = 1e-5;
|
||||||
|
|
||||||
|
ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicyD> MeofaD(LopD, RopD, CG, CG, CG, CG, CG, OFRp, true);
|
||||||
|
ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction<FermionImplPolicyD, FermionImplPolicyF> MeofaMx(LopF, RopF, LopD, RopD, MCG_L, MCG_R, MCG_L, MCG_R, MCG_L, MCG_R, OFRp, true);
|
||||||
|
|
||||||
|
FermionFieldD eta(FGridD);
|
||||||
|
gaussian(RNG5, eta);
|
||||||
|
|
||||||
|
MeofaD.refresh(Ud, eta);
|
||||||
|
MeofaMx.refresh(Ud, eta);
|
||||||
|
|
||||||
|
FermionFieldD diff_phi(FGridD);
|
||||||
|
diff_phi = MeofaD.getPhi() - MeofaMx.getPhi();
|
||||||
|
|
||||||
|
RealD n = norm2(diff_phi);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Phi(double)=" << norm2(MeofaD.getPhi()) << " Phi(mixed)=" << norm2(MeofaMx.getPhi()) << " diff=" << n << std::endl;
|
||||||
|
|
||||||
|
assert(n < 1e-8);
|
||||||
|
|
||||||
|
RealD Sd = MeofaD.S(Ud);
|
||||||
|
RealD Smx = MeofaMx.S(Ud);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Initial action double=" << Sd << " mixed=" << Smx << " diff=" << Sd-Smx << std::endl;
|
||||||
|
|
||||||
|
assert(fabs(Sd-Smx) < 1e-6);
|
||||||
|
|
||||||
|
SU<Nc>::HotConfiguration(RNG4,Ud);
|
||||||
|
precisionChange(Uf, Ud);
|
||||||
|
|
||||||
|
Sd = MeofaD.S(Ud);
|
||||||
|
Smx = MeofaMx.S(Ud);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "After randomizing U, action double=" << Sd << " mixed=" << Smx << " diff=" << Sd-Smx << std::endl;
|
||||||
|
|
||||||
|
assert(fabs(Sd-Smx) < 1e-6);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Done" << std::endl;
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
257
tests/hmc/Test_action_dwf_gparity2fvs1f.cc
Normal file
257
tests/hmc/Test_action_dwf_gparity2fvs1f.cc
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: tests/hmc/Test_action_dwf_gparity2fvs1f.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Christopher Kelly <ckelly@bnl.gov>
|
||||||
|
Author: paboyle <paboyle@ph.ed.ac.uk>
|
||||||
|
|
||||||
|
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 <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename FermionField2f, typename FermionField1f>
|
||||||
|
void copy2fTo1fFermionField(FermionField1f &out, const FermionField2f &in, int gpdir){
|
||||||
|
auto f0_halfgrid = PeekIndex<GparityFlavourIndex>(in,0); //on 2f Grid
|
||||||
|
FermionField1f f0_fullgrid_dbl(out.Grid());
|
||||||
|
Replicate(f0_halfgrid, f0_fullgrid_dbl); //double it up to live on the 1f Grid
|
||||||
|
|
||||||
|
auto f1_halfgrid = PeekIndex<GparityFlavourIndex>(in,1);
|
||||||
|
FermionField1f f1_fullgrid_dbl(out.Grid());
|
||||||
|
Replicate(f1_halfgrid, f1_fullgrid_dbl);
|
||||||
|
|
||||||
|
const Coordinate &dim_2f = in.Grid()->GlobalDimensions();
|
||||||
|
const Coordinate &dim_1f = out.Grid()->GlobalDimensions();
|
||||||
|
|
||||||
|
//We have to be careful for 5d fields; the s-direction is placed before the x,y,z,t and so we need to shift gpdir by 1
|
||||||
|
std::cout << "gpdir " << gpdir << std::endl;
|
||||||
|
|
||||||
|
gpdir+=1;
|
||||||
|
std::cout << "gpdir for 5D fields " << gpdir << std::endl;
|
||||||
|
|
||||||
|
std::cout << "dim_2f " << dim_2f << std::endl;
|
||||||
|
std::cout << "dim_1f " << dim_1f << std::endl;
|
||||||
|
|
||||||
|
assert(dim_1f[gpdir] == 2*dim_2f[gpdir]);
|
||||||
|
|
||||||
|
LatticeInteger xcoor_1f(out.Grid()); //5d lattice integer
|
||||||
|
LatticeCoordinate(xcoor_1f,gpdir);
|
||||||
|
|
||||||
|
int L = dim_2f[gpdir];
|
||||||
|
|
||||||
|
out = where(xcoor_1f < L, f0_fullgrid_dbl, f1_fullgrid_dbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Both have the same field type
|
||||||
|
void copy2fTo1fGaugeField(LatticeGaugeField &out, const LatticeGaugeField &in, int gpdir){
|
||||||
|
LatticeGaugeField U_dbl(out.Grid());
|
||||||
|
Replicate(in, U_dbl);
|
||||||
|
|
||||||
|
LatticeGaugeField Uconj_dbl = conjugate( U_dbl );
|
||||||
|
|
||||||
|
const Coordinate &dim_2f = in.Grid()->GlobalDimensions();
|
||||||
|
|
||||||
|
LatticeInteger xcoor_1f(out.Grid());
|
||||||
|
LatticeCoordinate(xcoor_1f,gpdir);
|
||||||
|
|
||||||
|
int L = dim_2f[gpdir];
|
||||||
|
|
||||||
|
out = where(xcoor_1f < L, U_dbl, Uconj_dbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream &os, const Coordinate &x){
|
||||||
|
os << "(";
|
||||||
|
for(int i=0;i<x.size();i++) os << x[i] << (i<x.size()-1 ? " " : "");
|
||||||
|
os << ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
using namespace Grid;
|
||||||
|
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
int threads = GridThread::GetThreads();
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl;
|
||||||
|
|
||||||
|
int Ls = 16;
|
||||||
|
|
||||||
|
Coordinate latt_2f = GridDefaultLatt();
|
||||||
|
Coordinate simd_layout = GridDefaultSimd(Nd, vComplexD::Nsimd());
|
||||||
|
Coordinate mpi_layout = GridDefaultMpi();
|
||||||
|
|
||||||
|
int mu = 0; //Gparity direction
|
||||||
|
|
||||||
|
Coordinate latt_1f = latt_2f;
|
||||||
|
latt_1f[mu] *= 2;
|
||||||
|
|
||||||
|
GridCartesian * UGrid_1f = SpaceTimeGrid::makeFourDimGrid(latt_1f, simd_layout, mpi_layout);
|
||||||
|
GridRedBlackCartesian * UrbGrid_1f = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid_1f);
|
||||||
|
GridCartesian * FGrid_1f = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid_1f);
|
||||||
|
GridRedBlackCartesian * FrbGrid_1f = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid_1f);
|
||||||
|
|
||||||
|
|
||||||
|
GridCartesian * UGrid_2f = SpaceTimeGrid::makeFourDimGrid(latt_2f, simd_layout, mpi_layout);
|
||||||
|
GridRedBlackCartesian * UrbGrid_2f = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid_2f);
|
||||||
|
GridCartesian * FGrid_2f = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid_2f);
|
||||||
|
GridRedBlackCartesian * FrbGrid_2f = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid_2f);
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "SIMD layout " << simd_layout << std::endl;
|
||||||
|
std::cout << "MPI layout " << mpi_layout << std::endl;
|
||||||
|
std::cout << "2f dimensions " << latt_2f << std::endl;
|
||||||
|
std::cout << "1f dimensions " << latt_1f << std::endl;
|
||||||
|
|
||||||
|
std::vector<int> seeds4({1,2,3,4});
|
||||||
|
std::vector<int> seeds5({5,6,7,8});
|
||||||
|
GridParallelRNG RNG5_2f(FGrid_2f); RNG5_2f.SeedFixedIntegers(seeds5);
|
||||||
|
GridParallelRNG RNG4_2f(UGrid_2f); RNG4_2f.SeedFixedIntegers(seeds4);
|
||||||
|
|
||||||
|
std::cout << "Generating hot 2f gauge configuration" << std::endl;
|
||||||
|
LatticeGaugeField Umu_2f(UGrid_2f);
|
||||||
|
SU<Nc>::HotConfiguration(RNG4_2f,Umu_2f);
|
||||||
|
|
||||||
|
std::cout << "Copying 2f->1f gauge field" << std::endl;
|
||||||
|
LatticeGaugeField Umu_1f(UGrid_1f);
|
||||||
|
copy2fTo1fGaugeField(Umu_1f, Umu_2f, mu);
|
||||||
|
|
||||||
|
typedef GparityWilsonImplR FermionImplPolicy2f;
|
||||||
|
typedef GparityDomainWallFermionR FermionAction2f;
|
||||||
|
typedef typename FermionAction2f::FermionField FermionField2f;
|
||||||
|
|
||||||
|
typedef WilsonImplR FermionImplPolicy1f;
|
||||||
|
typedef DomainWallFermionR FermionAction1f;
|
||||||
|
typedef typename FermionAction1f::FermionField FermionField1f;
|
||||||
|
|
||||||
|
std::cout << "Generating eta 2f" << std::endl;
|
||||||
|
FermionField2f eta_2f(FGrid_2f);
|
||||||
|
gaussian(RNG5_2f, eta_2f);
|
||||||
|
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
eta_2f=eta_2f*scale;
|
||||||
|
|
||||||
|
std::cout << "Copying 2f->1f eta" << std::endl;
|
||||||
|
FermionField1f eta_1f(FGrid_1f);
|
||||||
|
copy2fTo1fFermionField(eta_1f, eta_2f, mu);
|
||||||
|
|
||||||
|
Real beta = 2.13;
|
||||||
|
Real light_mass = 0.01;
|
||||||
|
Real strange_mass = 0.032;
|
||||||
|
Real pv_mass = 1.0;
|
||||||
|
RealD M5 = 1.8;
|
||||||
|
|
||||||
|
//Setup the Dirac operators
|
||||||
|
std::cout << "Initializing Dirac operators" << std::endl;
|
||||||
|
|
||||||
|
FermionAction2f::ImplParams Params_2f;
|
||||||
|
Params_2f.twists[mu] = 1;
|
||||||
|
Params_2f.twists[Nd-1] = 1; //APBC in time direction
|
||||||
|
|
||||||
|
//note 'Num' and 'Den' here refer to the determinant ratio, not the operator ratio in the pseudofermion action where the two are inverted
|
||||||
|
//to my mind the Pauli Villars and 'denominator' are synonymous but the Grid convention has this as the 'Numerator' operator in the RHMC implementation
|
||||||
|
FermionAction2f NumOp_2f(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f, *UrbGrid_2f, light_mass,M5,Params_2f);
|
||||||
|
FermionAction2f DenOp_2f(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f, *UrbGrid_2f, pv_mass, M5,Params_2f);
|
||||||
|
|
||||||
|
FermionAction1f::ImplParams Params_1f;
|
||||||
|
Params_1f.boundary_phases[mu] = -1; //antiperiodic in doubled lattice in GP direction
|
||||||
|
Params_1f.boundary_phases[Nd-1] = -1;
|
||||||
|
|
||||||
|
FermionAction1f NumOp_1f(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f, *UrbGrid_1f, light_mass,M5,Params_1f);
|
||||||
|
FermionAction1f DenOp_1f(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f, *UrbGrid_1f, pv_mass, M5,Params_1f);
|
||||||
|
|
||||||
|
//Test the replication routines by running a CG on eta
|
||||||
|
double StoppingCondition = 1e-10;
|
||||||
|
double MaxCGIterations = 30000;
|
||||||
|
ConjugateGradient<FermionField2f> CG_2f(StoppingCondition,MaxCGIterations);
|
||||||
|
ConjugateGradient<FermionField1f> CG_1f(StoppingCondition,MaxCGIterations);
|
||||||
|
|
||||||
|
NumOp_1f.ImportGauge(Umu_1f);
|
||||||
|
NumOp_2f.ImportGauge(Umu_2f);
|
||||||
|
|
||||||
|
FermionField1f test_1f(FGrid_1f);
|
||||||
|
FermionField2f test_2f(FGrid_2f);
|
||||||
|
|
||||||
|
MdagMLinearOperator<FermionAction1f, FermionField1f> Linop_1f(NumOp_1f);
|
||||||
|
MdagMLinearOperator<FermionAction2f, FermionField2f> Linop_2f(NumOp_2f);
|
||||||
|
|
||||||
|
CG_1f(Linop_1f, eta_1f, test_1f);
|
||||||
|
CG_2f(Linop_2f, eta_2f, test_2f);
|
||||||
|
RealD test_1f_norm = norm2(test_1f);
|
||||||
|
RealD test_2f_norm = norm2(test_2f);
|
||||||
|
|
||||||
|
std::cout << "Verification of replication routines: " << test_1f_norm << " " << test_2f_norm << " " << test_1f_norm - test_2f_norm << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicy2f> Action2f;
|
||||||
|
typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicy1f> Action1f;
|
||||||
|
|
||||||
|
RationalActionParams rational_params;
|
||||||
|
rational_params.inv_pow = 2;
|
||||||
|
rational_params.lo = 1e-5;
|
||||||
|
rational_params.hi = 32;
|
||||||
|
rational_params.md_degree = 16;
|
||||||
|
rational_params.action_degree = 16;
|
||||||
|
|
||||||
|
Action2f action_2f(DenOp_2f, NumOp_2f, rational_params);
|
||||||
|
Action1f action_1f(DenOp_1f, NumOp_1f, rational_params);
|
||||||
|
#else
|
||||||
|
typedef TwoFlavourEvenOddRatioPseudoFermionAction<FermionImplPolicy2f> Action2f;
|
||||||
|
typedef TwoFlavourEvenOddRatioPseudoFermionAction<FermionImplPolicy1f> Action1f;
|
||||||
|
|
||||||
|
Action2f action_2f(DenOp_2f, NumOp_2f, CG_2f, CG_2f);
|
||||||
|
Action1f action_1f(DenOp_1f, NumOp_1f, CG_1f, CG_1f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "Action refresh" << std::endl;
|
||||||
|
action_2f.refresh(Umu_2f, eta_2f);
|
||||||
|
action_1f.refresh(Umu_1f, eta_1f);
|
||||||
|
|
||||||
|
std::cout << "Action compute post heatbath" << std::endl;
|
||||||
|
RealD S_2f = action_2f.S(Umu_2f);
|
||||||
|
RealD S_1f = action_1f.S(Umu_1f);
|
||||||
|
|
||||||
|
std::cout << "Action comparison post heatbath" << std::endl;
|
||||||
|
std::cout << S_2f << " " << S_1f << " " << S_2f-S_1f << std::endl;
|
||||||
|
|
||||||
|
//Change the gauge field between refresh and action eval else the matrix and inverse matrices all cancel and we just get |eta|^2
|
||||||
|
SU<Nc>::HotConfiguration(RNG4_2f,Umu_2f);
|
||||||
|
copy2fTo1fGaugeField(Umu_1f, Umu_2f, mu);
|
||||||
|
|
||||||
|
//Now compute the action with the new gauge field
|
||||||
|
std::cout << "Action compute post gauge field update" << std::endl;
|
||||||
|
S_2f = action_2f.S(Umu_2f);
|
||||||
|
S_1f = action_1f.S(Umu_1f);
|
||||||
|
|
||||||
|
std::cout << "Action comparison post gauge field update" << std::endl;
|
||||||
|
std::cout << S_2f << " " << S_1f << " " << S_2f-S_1f << std::endl;
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
} // main
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ int main(int argc, char **argv) {
|
|||||||
CheckpointerParameters CPparams;
|
CheckpointerParameters CPparams;
|
||||||
CPparams.config_prefix = "ckpoint_EODWF_lat";
|
CPparams.config_prefix = "ckpoint_EODWF_lat";
|
||||||
CPparams.rng_prefix = "ckpoint_EODWF_rng";
|
CPparams.rng_prefix = "ckpoint_EODWF_rng";
|
||||||
CPparams.saveInterval = 5;
|
CPparams.saveInterval = 1;
|
||||||
CPparams.format = "IEEE64BIG";
|
CPparams.format = "IEEE64BIG";
|
||||||
|
|
||||||
TheHMC.Resources.LoadNerscCheckpointer(CPparams);
|
TheHMC.Resources.LoadNerscCheckpointer(CPparams);
|
||||||
@ -79,7 +79,7 @@ int main(int argc, char **argv) {
|
|||||||
// that have a complex construction
|
// that have a complex construction
|
||||||
// standard
|
// standard
|
||||||
RealD beta = 2.6 ;
|
RealD beta = 2.6 ;
|
||||||
const int nu = 3;
|
const int nu = 1;
|
||||||
std::vector<int> twists(Nd,0);
|
std::vector<int> twists(Nd,0);
|
||||||
twists[nu] = 1;
|
twists[nu] = 1;
|
||||||
ConjugateGimplD::setDirections(twists);
|
ConjugateGimplD::setDirections(twists);
|
||||||
|
125
tests/solver/Test_eofa_inv.cc
Normal file
125
tests/solver/Test_eofa_inv.cc
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_eofa_inv.cc
|
||||||
|
|
||||||
|
Copyright (C) 2017
|
||||||
|
|
||||||
|
Author: Christopher Kelly <ckelly@bnl.gov>
|
||||||
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
Author: David Murphy <dmurphy@phys.columbia.edu>
|
||||||
|
|
||||||
|
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 <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
;
|
||||||
|
|
||||||
|
int main (int argc, char** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
|
||||||
|
Coordinate latt_size = GridDefaultLatt();
|
||||||
|
Coordinate simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
Coordinate mpi_layout = GridDefaultMpi();
|
||||||
|
|
||||||
|
const int Ls = 8;
|
||||||
|
|
||||||
|
GridCartesian *UGrid = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid);
|
||||||
|
GridCartesian *FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid);
|
||||||
|
GridRedBlackCartesian *FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid);
|
||||||
|
|
||||||
|
// Want a different conf at every run
|
||||||
|
// First create an instance of an engine.
|
||||||
|
std::random_device rnd_device;
|
||||||
|
// Specify the engine and distribution.
|
||||||
|
std::mt19937 mersenne_engine(rnd_device());
|
||||||
|
std::uniform_int_distribution<int> dist(1, 100);
|
||||||
|
|
||||||
|
auto gen = std::bind(dist, mersenne_engine);
|
||||||
|
std::vector<int> seeds4(4);
|
||||||
|
generate(begin(seeds4), end(seeds4), gen);
|
||||||
|
|
||||||
|
//std::vector<int> seeds4({1,2,3,5});
|
||||||
|
std::vector<int> seeds5({5,6,7,8});
|
||||||
|
GridParallelRNG RNG5(FGrid); RNG5.SeedFixedIntegers(seeds5);
|
||||||
|
GridParallelRNG RNG4(UGrid); RNG4.SeedFixedIntegers(seeds4);
|
||||||
|
|
||||||
|
int threads = GridThread::GetThreads();
|
||||||
|
std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl;
|
||||||
|
|
||||||
|
LatticeFermion phi (FGrid); gaussian(RNG5, phi);
|
||||||
|
LatticeFermion Mphi (FGrid);
|
||||||
|
LatticeFermion MphiPrime (FGrid);
|
||||||
|
|
||||||
|
LatticeGaugeField U(UGrid);
|
||||||
|
SU<Nc>::HotConfiguration(RNG4,U);
|
||||||
|
|
||||||
|
////////////////////////////////////
|
||||||
|
// Unmodified matrix element
|
||||||
|
////////////////////////////////////
|
||||||
|
RealD b = 2.5;
|
||||||
|
RealD c = 1.5;
|
||||||
|
RealD mf = 0.01;
|
||||||
|
RealD mb = 1.0;
|
||||||
|
RealD M5 = 1.8;
|
||||||
|
MobiusEOFAFermionR Lop(U, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, mf, mb, 0.0, -1, M5, b, c);
|
||||||
|
MobiusEOFAFermionR Rop(U, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, mf, mb, -1.0, 1, M5, b, c);
|
||||||
|
OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-10, 12);
|
||||||
|
ConjugateGradient<LatticeFermion> CG(1.0e-10, 5000);
|
||||||
|
ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, CG, CG, CG, CG, Params, false);
|
||||||
|
|
||||||
|
GridSerialRNG sRNG; sRNG.SeedFixedIntegers(seeds4);
|
||||||
|
|
||||||
|
|
||||||
|
//Random field
|
||||||
|
LatticeFermion eta(FGrid);
|
||||||
|
gaussian(RNG5,eta);
|
||||||
|
|
||||||
|
//Check left inverse
|
||||||
|
LatticeFermion Meta(FGrid);
|
||||||
|
Meofa.Meofa(U, eta, Meta);
|
||||||
|
|
||||||
|
LatticeFermion MinvMeta(FGrid);
|
||||||
|
Meofa.MeofaInv(U, Meta, MinvMeta);
|
||||||
|
|
||||||
|
LatticeFermion diff = MinvMeta - eta;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "eta: " << norm2(eta) << " M*eta: " << norm2(Meta) << " M^{-1}*M*eta: " << norm2(MinvMeta) << " M^{-1}*M*eta - eta: " << norm2(diff) << " (expect 0)" << std::endl;
|
||||||
|
assert(norm2(diff) < 1e-8);
|
||||||
|
|
||||||
|
//Check right inverse
|
||||||
|
LatticeFermion MinvEta(FGrid);
|
||||||
|
Meofa.MeofaInv(U, eta, MinvEta);
|
||||||
|
|
||||||
|
LatticeFermion MMinvEta(FGrid);
|
||||||
|
Meofa.Meofa(U, MinvEta, MMinvEta);
|
||||||
|
|
||||||
|
diff = MMinvEta - eta;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "eta: " << norm2(eta) << " M^{-1}*eta: " << norm2(MinvEta) << " M*M^{-1}*eta: " << norm2(MMinvEta) << " M*M^{-1}*eta - eta: " << norm2(diff) << " (expect 0)" << std::endl;
|
||||||
|
assert(norm2(diff) < 1e-8);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Done" << std::endl;
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user