mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-10-31 03:54:33 +00:00 
			
		
		
		
	Compare commits
	
		
			84 Commits
		
	
	
		
			e5bc679fef
			...
			feature/gp
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 4fefae1745 | ||
|  | 758e2edcad | ||
|  | 1538b15f3b | ||
|  | deac621c2c | ||
|  | ba974960e6 | ||
|  | 6755dc57f8 | ||
|  | aa620ca52c | ||
|  | 2c46c942cc | ||
|  | adeba8059a | ||
|  | c4ac528126 | ||
|  | 551b93ba8e | ||
|  | ddf7540510 | ||
|  | de68d12c3d | ||
|  | 6d26a2a1ad | ||
|  | a1211cdcce | ||
|  | e78acf77ff | ||
|  | f7e9621492 | ||
|  | f14be15f8b | ||
|  | 6a3aaa52ef | ||
|  | 9ba47b4696 | ||
|  | e85af80c39 | ||
|  | 0b91e90dd4 | ||
|  | d184b8c921 | ||
|  | c92e390b08 | ||
|  | 5b36a8af54 | ||
|  | 75a1f85162 | ||
|  | ac4f2d9798 | ||
|  | c3b99de33f | ||
|  | e1a02bb80a | ||
|  | 86f08c6b9a | ||
|  | 9f0271039f | ||
|  | 24df770f74 | ||
|  | 45b6c7effc | ||
|  | 1c70d8c4d9 | ||
|  | f0e9a5299f | ||
|  | f1b8ba45e7 | ||
|  | fe998ab578 | ||
|  | c2ee2b5fd1 | ||
|  | 3b734ee397 | ||
|  | 8637a9512a | ||
|  | 7f6e2ee03e | ||
|  | 7b02acb2bd | ||
|  | 86948c6ea0 | ||
|  | 53d226924a | ||
|  | 80176b1b39 | ||
|  | 29ddafd0fc | ||
|  | 0f08364e4f | ||
|  | a198d59381 | ||
|  | 3a4f5f2324 | ||
|  | 824d84473f | ||
|  | 38964a4076 | ||
|  | 0d9aa87228 | ||
|  | 0e959d9b94 | ||
|  | 752f70cd48 | ||
|  | e0e42873c1 | ||
|  | 0ff3bf6dc5 | ||
|  | 351eab02ae | ||
|  | feee5ccde2 | ||
|  | e0f6a146d8 | ||
|  | daa095c519 | ||
|  | c2676853ca | ||
|  | 6a824033f8 | ||
|  | cee6a37639 | ||
|  | 6cc3ad110c | ||
|  | e6c6f82c52 | ||
|  | d10d0c4e7f | ||
|  | 9c106d625a | ||
|  | 6795bbca31 | ||
|  | d161c2dc35 | ||
|  | 7a06826cf1 | ||
|  | c3712b8e06 | ||
|  | 901ee77b84 | ||
|  | 1b84f59273 | ||
|  | 1fb41a4300 | ||
|  | 287bac946f | ||
|  | 80c14be65e | ||
|  | d7a2a4852d | ||
|  | d185f2eaa7 | ||
|  | 813d4cd900 | ||
|  | 75c6c6b173 | ||
|  | 220ad5e3ee | ||
|  | ba5dc670a5 | ||
|  | a0ca362690 | ||
|  | 249b6e61ec | 
| @@ -34,6 +34,9 @@ directory | |||||||
|  |  | ||||||
| #if defined __GNUC__ && __GNUC__>=6 | #if defined __GNUC__ && __GNUC__>=6 | ||||||
| #pragma GCC diagnostic ignored "-Wignored-attributes" | #pragma GCC diagnostic ignored "-Wignored-attributes" | ||||||
|  | #endif | ||||||
|  | #if defined __GNUC__  | ||||||
|  | #pragma GCC diagnostic ignored "-Wpsabi" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  //disables and intel compiler specific warning (in json.hpp) |  //disables and intel compiler specific warning (in json.hpp) | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/GridCore.h> | #include <Grid/GridCore.h> | ||||||
| #include <Grid/qcd/QCD.h> | #include <Grid/qcd/QCD.h> | ||||||
| #include <Grid/qcd/spin/Spin.h> | #include <Grid/qcd/spin/Spin.h> | ||||||
|  | #include <Grid/qcd/gparity/Gparity.h> | ||||||
| #include <Grid/qcd/utils/Utils.h> | #include <Grid/qcd/utils/Utils.h> | ||||||
| #include <Grid/qcd/representations/Representations.h> | #include <Grid/qcd/representations/Representations.h> | ||||||
| NAMESPACE_CHECK(GridQCDCore); | NAMESPACE_CHECK(GridQCDCore); | ||||||
|   | |||||||
| @@ -54,6 +54,7 @@ NAMESPACE_CHECK(BiCGSTAB); | |||||||
| #include <Grid/algorithms/iterative/SchurRedBlack.h> | #include <Grid/algorithms/iterative/SchurRedBlack.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateGradientMultiShift.h> | #include <Grid/algorithms/iterative/ConjugateGradientMultiShift.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h> | #include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h> | ||||||
|  | #include <Grid/algorithms/iterative/ConjugateGradientMultiShiftMixedPrec.h> | ||||||
| #include <Grid/algorithms/iterative/BiCGSTABMixedPrec.h> | #include <Grid/algorithms/iterative/BiCGSTABMixedPrec.h> | ||||||
| #include <Grid/algorithms/iterative/BlockConjugateGradient.h> | #include <Grid/algorithms/iterative/BlockConjugateGradient.h> | ||||||
| #include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h> | #include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h> | ||||||
|   | |||||||
| @@ -292,6 +292,7 @@ public: | |||||||
| template<class Field> | template<class Field> | ||||||
| class ChebyshevLanczos : public Chebyshev<Field> { | class ChebyshevLanczos : public Chebyshev<Field> { | ||||||
| private: | private: | ||||||
|  |  | ||||||
|   std::vector<RealD> Coeffs; |   std::vector<RealD> Coeffs; | ||||||
|   int order; |   int order; | ||||||
|   RealD alpha; |   RealD alpha; | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
|     Integer TotalInnerIterations; //Number of inner CG iterations |     Integer TotalInnerIterations; //Number of inner CG iterations | ||||||
|     Integer TotalOuterIterations; //Number of restarts |     Integer TotalOuterIterations; //Number of restarts | ||||||
|     Integer TotalFinalStepIterations; //Number of CG iterations in final patch-up step |     Integer TotalFinalStepIterations; //Number of CG iterations in final patch-up step | ||||||
|  |     RealD TrueResidual; | ||||||
|  |  | ||||||
|     //Option to speed up *inner single precision* solves using a LinearFunction that produces a guess |     //Option to speed up *inner single precision* solves using a LinearFunction that produces a guess | ||||||
|     LinearFunction<FieldF> *guesser; |     LinearFunction<FieldF> *guesser; | ||||||
| @@ -68,6 +69,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
|     } |     } | ||||||
|    |    | ||||||
|   void operator() (const FieldD &src_d_in, FieldD &sol_d){ |   void operator() (const FieldD &src_d_in, FieldD &sol_d){ | ||||||
|  |     std::cout << GridLogMessage << "MixedPrecisionConjugateGradient: Starting mixed precision CG with outer tolerance " << Tolerance << " and inner tolerance " << InnerTolerance << std::endl; | ||||||
|     TotalInnerIterations = 0; |     TotalInnerIterations = 0; | ||||||
| 	 | 	 | ||||||
|     GridStopWatch TotalTimer; |     GridStopWatch TotalTimer; | ||||||
| @@ -80,6 +82,11 @@ NAMESPACE_BEGIN(Grid); | |||||||
|     RealD stop = src_norm * Tolerance*Tolerance; |     RealD stop = src_norm * Tolerance*Tolerance; | ||||||
|  |  | ||||||
|     GridBase* DoublePrecGrid = src_d_in.Grid(); |     GridBase* DoublePrecGrid = src_d_in.Grid(); | ||||||
|  |  | ||||||
|  |     //Generate precision change workspaces | ||||||
|  |     precisionChangeWorkspace wk_dp_from_sp(DoublePrecGrid, SinglePrecGrid); | ||||||
|  |     precisionChangeWorkspace wk_sp_from_dp(SinglePrecGrid, DoublePrecGrid); | ||||||
|  |  | ||||||
|     FieldD tmp_d(DoublePrecGrid); |     FieldD tmp_d(DoublePrecGrid); | ||||||
|     tmp_d.Checkerboard() = cb; |     tmp_d.Checkerboard() = cb; | ||||||
|      |      | ||||||
| @@ -97,6 +104,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
|     FieldF sol_f(SinglePrecGrid); |     FieldF sol_f(SinglePrecGrid); | ||||||
|     sol_f.Checkerboard() = cb; |     sol_f.Checkerboard() = cb; | ||||||
|      |      | ||||||
|  |     std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Starting initial inner CG with tolerance " << inner_tol << std::endl; | ||||||
|     ConjugateGradient<FieldF> CG_f(inner_tol, MaxInnerIterations); |     ConjugateGradient<FieldF> CG_f(inner_tol, MaxInnerIterations); | ||||||
|     CG_f.ErrorOnNoConverge = false; |     CG_f.ErrorOnNoConverge = false; | ||||||
|  |  | ||||||
| @@ -120,7 +128,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
|       while(norm * inner_tol * inner_tol < stop) inner_tol *= 2;  // inner_tol = sqrt(stop/norm) ?? |       while(norm * inner_tol * inner_tol < stop) inner_tol *= 2;  // inner_tol = sqrt(stop/norm) ?? | ||||||
|  |  | ||||||
|       PrecChangeTimer.Start(); |       PrecChangeTimer.Start(); | ||||||
|       precisionChange(src_f, src_d); |       precisionChange(src_f, src_d, wk_sp_from_dp); | ||||||
|       PrecChangeTimer.Stop(); |       PrecChangeTimer.Stop(); | ||||||
|        |        | ||||||
|       sol_f = Zero(); |       sol_f = Zero(); | ||||||
| @@ -130,6 +138,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
| 	(*guesser)(src_f, sol_f); | 	(*guesser)(src_f, sol_f); | ||||||
|  |  | ||||||
|       //Inner CG |       //Inner CG | ||||||
|  |       std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Outer iteration " << outer_iter << " starting inner CG with tolerance " << inner_tol << std::endl; | ||||||
|       CG_f.Tolerance = inner_tol; |       CG_f.Tolerance = inner_tol; | ||||||
|       InnerCGtimer.Start(); |       InnerCGtimer.Start(); | ||||||
|       CG_f(Linop_f, src_f, sol_f); |       CG_f(Linop_f, src_f, sol_f); | ||||||
| @@ -138,7 +147,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
|        |        | ||||||
|       //Convert sol back to double and add to double prec solution |       //Convert sol back to double and add to double prec solution | ||||||
|       PrecChangeTimer.Start(); |       PrecChangeTimer.Start(); | ||||||
|       precisionChange(tmp_d, sol_f); |       precisionChange(tmp_d, sol_f, wk_dp_from_sp); | ||||||
|       PrecChangeTimer.Stop(); |       PrecChangeTimer.Stop(); | ||||||
|        |        | ||||||
|       axpy(sol_d, 1.0, tmp_d, sol_d); |       axpy(sol_d, 1.0, tmp_d, sol_d); | ||||||
| @@ -150,6 +159,7 @@ NAMESPACE_BEGIN(Grid); | |||||||
|     ConjugateGradient<FieldD> CG_d(Tolerance, MaxInnerIterations); |     ConjugateGradient<FieldD> CG_d(Tolerance, MaxInnerIterations); | ||||||
|     CG_d(Linop_d, src_d_in, sol_d); |     CG_d(Linop_d, src_d_in, sol_d); | ||||||
|     TotalFinalStepIterations = CG_d.IterationsToComplete; |     TotalFinalStepIterations = CG_d.IterationsToComplete; | ||||||
|  |     TrueResidual = CG_d.TrueResidual; | ||||||
|  |  | ||||||
|     TotalTimer.Stop(); |     TotalTimer.Stop(); | ||||||
|     std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Inner CG iterations " << TotalInnerIterations << " Restarts " << TotalOuterIterations << " Final CG iterations " << TotalFinalStepIterations << std::endl; |     std::cout<<GridLogMessage<<"MixedPrecisionConjugateGradient: Inner CG iterations " << TotalInnerIterations << " Restarts " << TotalOuterIterations << " Final CG iterations " << TotalFinalStepIterations << std::endl; | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ public: | |||||||
|   MultiShiftFunction shifts; |   MultiShiftFunction shifts; | ||||||
|   std::vector<RealD> TrueResidualShift; |   std::vector<RealD> TrueResidualShift; | ||||||
|  |  | ||||||
|   ConjugateGradientMultiShift(Integer maxit,MultiShiftFunction &_shifts) :  |   ConjugateGradientMultiShift(Integer maxit, const MultiShiftFunction &_shifts) :  | ||||||
|     MaxIterations(maxit), |     MaxIterations(maxit), | ||||||
|     shifts(_shifts) |     shifts(_shifts) | ||||||
|   {  |   {  | ||||||
| @@ -183,6 +183,9 @@ public: | |||||||
|       axpby(psi[s],0.,-bs[s]*alpha[s],src,src); |       axpby(psi[s],0.,-bs[s]*alpha[s],src,src); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     std::cout << GridLogIterative << "ConjugateGradientMultiShift: initial rn (|src|^2) =" << rn << " qq (|MdagM src|^2) =" << qq << " d ( dot(src, [MdagM + m_0]src) ) =" << d << " c=" << c << std::endl; | ||||||
|  |      | ||||||
|  |    | ||||||
|   /////////////////////////////////////// |   /////////////////////////////////////// | ||||||
|   // Timers |   // Timers | ||||||
|   /////////////////////////////////////// |   /////////////////////////////////////// | ||||||
|   | |||||||
							
								
								
									
										411
									
								
								Grid/algorithms/iterative/ConjugateGradientMultiShiftMixedPrec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										411
									
								
								Grid/algorithms/iterative/ConjugateGradientMultiShiftMixedPrec.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,411 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/algorithms/iterative/ConjugateGradientMultiShift.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk> | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  |  | ||||||
|  |     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 GRID_CONJUGATE_GRADIENT_MULTI_SHIFT_MIXEDPREC_H | ||||||
|  | #define GRID_CONJUGATE_GRADIENT_MULTI_SHIFT_MIXEDPREC_H | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | //CK 2020: A variant of the multi-shift conjugate gradient with the matrix multiplication in single precision.  | ||||||
|  | //The residual is stored in single precision, but the search directions and solution are stored in double precision.  | ||||||
|  | //Every update_freq iterations the residual is corrected in double precision.  | ||||||
|  |      | ||||||
|  | //For safety the a final regular CG is applied to clean up if necessary | ||||||
|  |  | ||||||
|  | //Linop to add shift to input linop, used in cleanup CG | ||||||
|  | namespace ConjugateGradientMultiShiftMixedPrecSupport{ | ||||||
|  | template<typename Field> | ||||||
|  | class ShiftedLinop: public LinearOperatorBase<Field>{ | ||||||
|  | public: | ||||||
|  |   LinearOperatorBase<Field> &linop_base; | ||||||
|  |   RealD shift; | ||||||
|  |  | ||||||
|  |   ShiftedLinop(LinearOperatorBase<Field> &_linop_base, RealD _shift): linop_base(_linop_base), shift(_shift){} | ||||||
|  |  | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); } | ||||||
|  |    | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |  | ||||||
|  |   void HermOp(const Field &in, Field &out){ | ||||||
|  |     linop_base.HermOp(in, out); | ||||||
|  |     axpy(out, shift, in, out); | ||||||
|  |   }     | ||||||
|  |  | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||||
|  |     HermOp(in,out); | ||||||
|  |     ComplexD dot = innerProduct(in,out); | ||||||
|  |     n1=real(dot); | ||||||
|  |     n2=norm2(out); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class FieldD, class FieldF, | ||||||
|  | 	 typename std::enable_if< getPrecision<FieldD>::value == 2, int>::type = 0, | ||||||
|  | 	 typename std::enable_if< getPrecision<FieldF>::value == 1, int>::type = 0>  | ||||||
|  | class ConjugateGradientMultiShiftMixedPrec : public OperatorMultiFunction<FieldD>, | ||||||
|  | 					     public OperatorFunction<FieldD> | ||||||
|  | { | ||||||
|  | public:                                                 | ||||||
|  |  | ||||||
|  |   using OperatorFunction<FieldD>::operator(); | ||||||
|  |  | ||||||
|  |   RealD   Tolerance; | ||||||
|  |   Integer MaxIterations; | ||||||
|  |   Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion | ||||||
|  |   std::vector<int> IterationsToCompleteShift;  // Iterations for this shift | ||||||
|  |   int verbose; | ||||||
|  |   MultiShiftFunction shifts; | ||||||
|  |   std::vector<RealD> TrueResidualShift; | ||||||
|  |  | ||||||
|  |   int ReliableUpdateFreq; //number of iterations between reliable updates | ||||||
|  |  | ||||||
|  |   GridBase* SinglePrecGrid; //Grid for single-precision fields | ||||||
|  |   LinearOperatorBase<FieldF> &Linop_f; //single precision | ||||||
|  |  | ||||||
|  |   ConjugateGradientMultiShiftMixedPrec(Integer maxit, const MultiShiftFunction &_shifts, | ||||||
|  | 				       GridBase* _SinglePrecGrid, LinearOperatorBase<FieldF> &_Linop_f, | ||||||
|  | 				       int _ReliableUpdateFreq | ||||||
|  | 				       ) :  | ||||||
|  |     MaxIterations(maxit),  shifts(_shifts), SinglePrecGrid(_SinglePrecGrid), Linop_f(_Linop_f), ReliableUpdateFreq(_ReliableUpdateFreq) | ||||||
|  |   {  | ||||||
|  |     verbose=1; | ||||||
|  |     IterationsToCompleteShift.resize(_shifts.order); | ||||||
|  |     TrueResidualShift.resize(_shifts.order); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<FieldD> &Linop, const FieldD &src, FieldD &psi) | ||||||
|  |   { | ||||||
|  |     GridBase *grid = src.Grid(); | ||||||
|  |     int nshift = shifts.order; | ||||||
|  |     std::vector<FieldD> results(nshift,grid); | ||||||
|  |     (*this)(Linop,src,results,psi); | ||||||
|  |   } | ||||||
|  |   void operator() (LinearOperatorBase<FieldD> &Linop, const FieldD &src, std::vector<FieldD> &results, FieldD &psi) | ||||||
|  |   { | ||||||
|  |     int nshift = shifts.order; | ||||||
|  |  | ||||||
|  |     (*this)(Linop,src,results); | ||||||
|  |    | ||||||
|  |     psi = shifts.norm*src; | ||||||
|  |     for(int i=0;i<nshift;i++){ | ||||||
|  |       psi = psi + shifts.residues[i]*results[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void operator() (LinearOperatorBase<FieldD> &Linop_d, const FieldD &src_d, std::vector<FieldD> &psi_d) | ||||||
|  |   {  | ||||||
|  |     GridBase *DoublePrecGrid = src_d.Grid(); | ||||||
|  |     precisionChangeWorkspace wk_f_from_d(SinglePrecGrid, DoublePrecGrid); | ||||||
|  |     precisionChangeWorkspace wk_d_from_f(DoublePrecGrid, SinglePrecGrid); | ||||||
|  |  | ||||||
|  |     //////////////////////////////////////////////////////////////////////// | ||||||
|  |     // Convenience references to the info stored in "MultiShiftFunction" | ||||||
|  |     //////////////////////////////////////////////////////////////////////// | ||||||
|  |     int nshift = shifts.order; | ||||||
|  |  | ||||||
|  |     std::vector<RealD> &mass(shifts.poles); // Make references to array in "shifts" | ||||||
|  |     std::vector<RealD> &mresidual(shifts.tolerances); | ||||||
|  |     std::vector<RealD> alpha(nshift,1.0); | ||||||
|  |  | ||||||
|  |     //Double precision search directions | ||||||
|  |     FieldD p_d(DoublePrecGrid); | ||||||
|  |     std::vector<FieldD> ps_d(nshift, DoublePrecGrid);// Search directions (double precision) | ||||||
|  |  | ||||||
|  |     FieldD tmp_d(DoublePrecGrid); | ||||||
|  |     FieldD r_d(DoublePrecGrid); | ||||||
|  |     FieldD mmp_d(DoublePrecGrid); | ||||||
|  |  | ||||||
|  |     assert(psi_d.size()==nshift); | ||||||
|  |     assert(mass.size()==nshift); | ||||||
|  |     assert(mresidual.size()==nshift); | ||||||
|  |    | ||||||
|  |     // dynamic sized arrays on stack; 2d is a pain with vector | ||||||
|  |     RealD  bs[nshift]; | ||||||
|  |     RealD  rsq[nshift]; | ||||||
|  |     RealD  z[nshift][2]; | ||||||
|  |     int     converged[nshift]; | ||||||
|  |    | ||||||
|  |     const int       primary =0; | ||||||
|  |    | ||||||
|  |     //Primary shift fields CG iteration | ||||||
|  |     RealD a,b,c,d; | ||||||
|  |     RealD cp,bp,qq; //prev | ||||||
|  |    | ||||||
|  |     // Matrix mult fields | ||||||
|  |     FieldF r_f(SinglePrecGrid); | ||||||
|  |     FieldF p_f(SinglePrecGrid); | ||||||
|  |     FieldF tmp_f(SinglePrecGrid); | ||||||
|  |     FieldF mmp_f(SinglePrecGrid); | ||||||
|  |     FieldF src_f(SinglePrecGrid); | ||||||
|  |     precisionChange(src_f, src_d, wk_f_from_d); | ||||||
|  |  | ||||||
|  |     // Check lightest mass | ||||||
|  |     for(int s=0;s<nshift;s++){ | ||||||
|  |       assert( mass[s]>= mass[primary] ); | ||||||
|  |       converged[s]=0; | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     // Wire guess to zero | ||||||
|  |     // Residuals "r" are src | ||||||
|  |     // First search direction "p" is also src | ||||||
|  |     cp = norm2(src_d); | ||||||
|  |  | ||||||
|  |     // Handle trivial case of zero src. | ||||||
|  |     if( cp == 0. ){ | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  | 	psi_d[s] = Zero(); | ||||||
|  | 	IterationsToCompleteShift[s] = 1; | ||||||
|  | 	TrueResidualShift[s] = 0.; | ||||||
|  |       } | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(int s=0;s<nshift;s++){ | ||||||
|  |       rsq[s] = cp * mresidual[s] * mresidual[s]; | ||||||
|  |       std::cout<<GridLogMessage<<"ConjugateGradientMultiShiftMixedPrec: shift "<< s <<" target resid "<<rsq[s]<<std::endl; | ||||||
|  |       ps_d[s] = src_d; | ||||||
|  |     } | ||||||
|  |     // r and p for primary | ||||||
|  |     r_f=src_f; //residual maintained in single | ||||||
|  |     p_f=src_f; | ||||||
|  |     p_d = src_d; //primary copy --- make this a reference to ps_d to save axpys | ||||||
|  |    | ||||||
|  |     //MdagM+m[0] | ||||||
|  |     Linop_f.HermOpAndNorm(p_f,mmp_f,d,qq); // mmp = MdagM p        d=real(dot(p, mmp)),  qq=norm2(mmp) | ||||||
|  |     axpy(mmp_f,mass[0],p_f,mmp_f); | ||||||
|  |     RealD rn = norm2(p_f); | ||||||
|  |     d += rn*mass[0]; | ||||||
|  |  | ||||||
|  |     b = -cp /d; | ||||||
|  |    | ||||||
|  |     // Set up the various shift variables | ||||||
|  |     int       iz=0; | ||||||
|  |     z[0][1-iz] = 1.0; | ||||||
|  |     z[0][iz]   = 1.0; | ||||||
|  |     bs[0]      = b; | ||||||
|  |     for(int s=1;s<nshift;s++){ | ||||||
|  |       z[s][1-iz] = 1.0; | ||||||
|  |       z[s][iz]   = 1.0/( 1.0 - b*(mass[s]-mass[0])); | ||||||
|  |       bs[s]      = b*z[s][iz];  | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     // r += b[0] A.p[0] | ||||||
|  |     // c= norm(r) | ||||||
|  |     c=axpy_norm(r_f,b,mmp_f,r_f); | ||||||
|  |    | ||||||
|  |     for(int s=0;s<nshift;s++) { | ||||||
|  |       axpby(psi_d[s],0.,-bs[s]*alpha[s],src_d,src_d); | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     /////////////////////////////////////// | ||||||
|  |     // Timers | ||||||
|  |     /////////////////////////////////////// | ||||||
|  |     GridStopWatch AXPYTimer, ShiftTimer, QRTimer, MatrixTimer, SolverTimer, PrecChangeTimer, CleanupTimer; | ||||||
|  |  | ||||||
|  |     SolverTimer.Start(); | ||||||
|  |    | ||||||
|  |     // Iteration loop | ||||||
|  |     int k; | ||||||
|  |    | ||||||
|  |     for (k=1;k<=MaxIterations;k++){     | ||||||
|  |       a = c /cp; | ||||||
|  |  | ||||||
|  |       //Update double precision search direction by residual | ||||||
|  |       PrecChangeTimer.Start(); | ||||||
|  |       precisionChange(r_d, r_f, wk_d_from_f); | ||||||
|  |       PrecChangeTimer.Stop(); | ||||||
|  |  | ||||||
|  |       AXPYTimer.Start(); | ||||||
|  |       axpy(p_d,a,p_d,r_d);  | ||||||
|  |  | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  | 	if ( ! converged[s] ) {  | ||||||
|  | 	  if (s==0){ | ||||||
|  | 	    axpy(ps_d[s],a,ps_d[s],r_d); | ||||||
|  | 	  } else{ | ||||||
|  | 	    RealD as =a *z[s][iz]*bs[s] /(z[s][1-iz]*b); | ||||||
|  | 	    axpby(ps_d[s],z[s][iz],as,r_d,ps_d[s]); | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |       AXPYTimer.Stop(); | ||||||
|  |  | ||||||
|  |       PrecChangeTimer.Start(); | ||||||
|  |       precisionChange(p_f, p_d, wk_f_from_d); //get back single prec search direction for linop | ||||||
|  |       PrecChangeTimer.Stop(); | ||||||
|  |  | ||||||
|  |       cp=c; | ||||||
|  |       MatrixTimer.Start();   | ||||||
|  |       Linop_f.HermOp(p_f,mmp_f);  | ||||||
|  |       d=real(innerProduct(p_f,mmp_f));     | ||||||
|  |       MatrixTimer.Stop();   | ||||||
|  |  | ||||||
|  |       AXPYTimer.Start(); | ||||||
|  |       axpy(mmp_f,mass[0],p_f,mmp_f); | ||||||
|  |       AXPYTimer.Stop(); | ||||||
|  |       RealD rn = norm2(p_f); | ||||||
|  |       d += rn*mass[0]; | ||||||
|  |      | ||||||
|  |       bp=b; | ||||||
|  |       b=-cp/d; | ||||||
|  |      | ||||||
|  |       // Toggle the recurrence history | ||||||
|  |       bs[0] = b; | ||||||
|  |       iz = 1-iz; | ||||||
|  |       ShiftTimer.Start(); | ||||||
|  |       for(int s=1;s<nshift;s++){ | ||||||
|  | 	if((!converged[s])){ | ||||||
|  | 	  RealD z0 = z[s][1-iz]; | ||||||
|  | 	  RealD z1 = z[s][iz]; | ||||||
|  | 	  z[s][iz] = z0*z1*bp | ||||||
|  | 	    / (b*a*(z1-z0) + z1*bp*(1- (mass[s]-mass[0])*b));  | ||||||
|  | 	  bs[s] = b*z[s][iz]/z0; // NB sign  rel to Mike | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |       ShiftTimer.Stop(); | ||||||
|  |  | ||||||
|  |       //Update double precision solutions | ||||||
|  |       AXPYTimer.Start(); | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  | 	int ss = s; | ||||||
|  | 	if( (!converged[s]) ) {  | ||||||
|  | 	  axpy(psi_d[ss],-bs[s]*alpha[s],ps_d[s],psi_d[ss]); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       //Perform reliable update if necessary; otherwise update residual from single-prec mmp | ||||||
|  |       RealD c_f = axpy_norm(r_f,b,mmp_f,r_f); | ||||||
|  |       AXPYTimer.Stop(); | ||||||
|  |  | ||||||
|  |       c = c_f; | ||||||
|  |  | ||||||
|  |       if(k % ReliableUpdateFreq == 0){ | ||||||
|  | 	//Replace r with true residual | ||||||
|  | 	MatrixTimer.Start();   | ||||||
|  | 	Linop_d.HermOp(psi_d[0],mmp_d);  | ||||||
|  | 	MatrixTimer.Stop();   | ||||||
|  |  | ||||||
|  | 	AXPYTimer.Start(); | ||||||
|  | 	axpy(mmp_d,mass[0],psi_d[0],mmp_d); | ||||||
|  |  | ||||||
|  | 	RealD c_d = axpy_norm(r_d, -1.0, mmp_d, src_d); | ||||||
|  | 	AXPYTimer.Stop(); | ||||||
|  |  | ||||||
|  | 	std::cout<<GridLogMessage<<"ConjugateGradientMultiShiftMixedPrec k="<<k<< ", replaced |r|^2 = "<<c_f <<" with |r|^2 = "<<c_d<<std::endl; | ||||||
|  | 	 | ||||||
|  | 	PrecChangeTimer.Start(); | ||||||
|  | 	precisionChange(r_f, r_d, wk_f_from_d); | ||||||
|  | 	PrecChangeTimer.Stop(); | ||||||
|  | 	c = c_d; | ||||||
|  |       } | ||||||
|  |      | ||||||
|  |       // Convergence checks | ||||||
|  |       int all_converged = 1; | ||||||
|  |       for(int s=0;s<nshift;s++){ | ||||||
|  |        | ||||||
|  | 	if ( (!converged[s]) ){ | ||||||
|  | 	  IterationsToCompleteShift[s] = k; | ||||||
|  | 	 | ||||||
|  | 	  RealD css  = c * z[s][iz]* z[s][iz]; | ||||||
|  | 	 | ||||||
|  | 	  if(css<rsq[s]){ | ||||||
|  | 	    if ( ! converged[s] ) | ||||||
|  | 	      std::cout<<GridLogMessage<<"ConjugateGradientMultiShiftMixedPrec k="<<k<<" Shift "<<s<<" has converged"<<std::endl; | ||||||
|  | 	    converged[s]=1; | ||||||
|  | 	  } else { | ||||||
|  | 	    all_converged=0; | ||||||
|  | 	  } | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if ( all_converged ){ | ||||||
|  |  | ||||||
|  | 	SolverTimer.Stop(); | ||||||
|  | 	std::cout<<GridLogMessage<< "ConjugateGradientMultiShiftMixedPrec: All shifts have converged iteration "<<k<<std::endl; | ||||||
|  | 	std::cout<<GridLogMessage<< "ConjugateGradientMultiShiftMixedPrec: Checking solutions"<<std::endl; | ||||||
|  |        | ||||||
|  | 	// Check answers  | ||||||
|  | 	for(int s=0; s < nshift; s++) {  | ||||||
|  | 	  Linop_d.HermOpAndNorm(psi_d[s],mmp_d,d,qq); | ||||||
|  | 	  axpy(tmp_d,mass[s],psi_d[s],mmp_d); | ||||||
|  | 	  axpy(r_d,-alpha[s],src_d,tmp_d); | ||||||
|  | 	  RealD rn = norm2(r_d); | ||||||
|  | 	  RealD cn = norm2(src_d); | ||||||
|  | 	  TrueResidualShift[s] = std::sqrt(rn/cn); | ||||||
|  | 	  std::cout<<GridLogMessage<<"ConjugateGradientMultiShiftMixedPrec: shift["<<s<<"] true residual "<< TrueResidualShift[s] << " target " << mresidual[s] << std::endl; | ||||||
|  |  | ||||||
|  | 	  //If we have not reached the desired tolerance, do a (mixed precision) CG cleanup | ||||||
|  | 	  if(rn >= rsq[s]){ | ||||||
|  | 	    CleanupTimer.Start(); | ||||||
|  | 	    std::cout<<GridLogMessage<<"ConjugateGradientMultiShiftMixedPrec: performing cleanup step for shift " << s << std::endl; | ||||||
|  |  | ||||||
|  | 	    //Setup linear operators for final cleanup | ||||||
|  | 	    ConjugateGradientMultiShiftMixedPrecSupport::ShiftedLinop<FieldD> Linop_shift_d(Linop_d, mass[s]); | ||||||
|  | 	    ConjugateGradientMultiShiftMixedPrecSupport::ShiftedLinop<FieldF> Linop_shift_f(Linop_f, mass[s]); | ||||||
|  | 					        | ||||||
|  | 	    MixedPrecisionConjugateGradient<FieldD,FieldF> cg(mresidual[s], MaxIterations, MaxIterations, SinglePrecGrid, Linop_shift_f, Linop_shift_d);  | ||||||
|  | 	    cg(src_d, psi_d[s]); | ||||||
|  | 	     | ||||||
|  | 	    TrueResidualShift[s] = cg.TrueResidual; | ||||||
|  | 	    CleanupTimer.Stop(); | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	std::cout << GridLogMessage << "ConjugateGradientMultiShiftMixedPrec: Time Breakdown for body"<<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\tSolver    " << SolverTimer.Elapsed()     <<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\t\tAXPY    " << AXPYTimer.Elapsed()     <<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\t\tMatrix    " << MatrixTimer.Elapsed()     <<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\t\tShift    " << ShiftTimer.Elapsed()     <<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\t\tPrecision Change " << PrecChangeTimer.Elapsed()     <<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\tFinal Cleanup " << CleanupTimer.Elapsed()     <<std::endl; | ||||||
|  | 	std::cout << GridLogMessage << "\tSolver+Cleanup " << SolverTimer.Elapsed() + CleanupTimer.Elapsed() << std::endl; | ||||||
|  |  | ||||||
|  | 	IterationsToComplete = k;	 | ||||||
|  |  | ||||||
|  | 	return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     | ||||||
|  |     } | ||||||
|  |     // ugly hack | ||||||
|  |     std::cout<<GridLogMessage<<"CG multi shift did not converge"<<std::endl; | ||||||
|  |     //  assert(0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  | #endif | ||||||
| @@ -44,6 +44,7 @@ public: | |||||||
| 				  int, MinRes);    // Must restart | 				  int, MinRes);    // Must restart | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | //This class is the input parameter class for some testing programs | ||||||
| struct LocalCoherenceLanczosParams : Serializable { | struct LocalCoherenceLanczosParams : Serializable { | ||||||
| public: | public: | ||||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(LocalCoherenceLanczosParams, |   GRID_SERIALIZABLE_CLASS_MEMBERS(LocalCoherenceLanczosParams, | ||||||
| @@ -155,6 +156,7 @@ public: | |||||||
|       _coarse_relax_tol(coarse_relax_tol)   |       _coarse_relax_tol(coarse_relax_tol)   | ||||||
|   {    }; |   {    }; | ||||||
|  |  | ||||||
|  |   //evalMaxApprox: approximation of largest eval of the fine Chebyshev operator (suitably wrapped by block projection) | ||||||
|   int TestConvergence(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) |   int TestConvergence(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) | ||||||
|   { |   { | ||||||
|     CoarseField v(B); |     CoarseField v(B); | ||||||
| @@ -181,8 +183,16 @@ public: | |||||||
|     if( (vv<eresid*eresid) ) conv = 1; |     if( (vv<eresid*eresid) ) conv = 1; | ||||||
|     return conv; |     return conv; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //This function is called at the end of the coarse grid Lanczos. It promotes the coarse eigenvector 'B' to the fine grid, | ||||||
|  |   //applies a smoother to the result then computes the computes the *fine grid* eigenvalue (output as 'eval'). | ||||||
|  |  | ||||||
|  |   //evalMaxApprox should be the approximation of the largest eval of the fine Hermop. However when this function is called by IRL it actually passes the largest eval of the *Chebyshev* operator (as this is the max approx used for the TestConvergence above) | ||||||
|  |   //As the largest eval of the Chebyshev is typically several orders of magnitude larger this makes the convergence test pass even when it should not. | ||||||
|  |   //We therefore ignore evalMaxApprox here and use a value of 1.0 (note this value is already used by TestCoarse) | ||||||
|   int ReconstructEval(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox)   |   int ReconstructEval(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox)   | ||||||
|   { |   { | ||||||
|  |     evalMaxApprox = 1.0; //cf above | ||||||
|     GridBase *FineGrid = _subspace[0].Grid();     |     GridBase *FineGrid = _subspace[0].Grid();     | ||||||
|     int checkerboard   = _subspace[0].Checkerboard(); |     int checkerboard   = _subspace[0].Checkerboard(); | ||||||
|     FineField fB(FineGrid);fB.Checkerboard() =checkerboard; |     FineField fB(FineGrid);fB.Checkerboard() =checkerboard; | ||||||
| @@ -201,13 +211,13 @@ public: | |||||||
|     eval   = vnum/vden; |     eval   = vnum/vden; | ||||||
|     fv -= eval*fB; |     fv -= eval*fB; | ||||||
|     RealD vv = norm2(fv) / ::pow(evalMaxApprox,2.0); |     RealD vv = norm2(fv) / ::pow(evalMaxApprox,2.0); | ||||||
|  |     if ( j > nbasis ) eresid = eresid*_coarse_relax_tol; | ||||||
|      |      | ||||||
|     std::cout.precision(13); |     std::cout.precision(13); | ||||||
|     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " |     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||||
| 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||||
| 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv << " target " << eresid*eresid | ||||||
| 	     <<std::endl; | 	     <<std::endl; | ||||||
|     if ( j > nbasis ) eresid = eresid*_coarse_relax_tol; |  | ||||||
|     if( (vv<eresid*eresid) ) return 1; |     if( (vv<eresid*eresid) ) return 1; | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
| @@ -285,6 +295,10 @@ public: | |||||||
|     evals_coarse.resize(0); |     evals_coarse.resize(0); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   //The block inner product is the inner product on the fine grid locally summed over the blocks | ||||||
|  |   //to give a Lattice<Scalar> on the coarse grid. This function orthnormalizes the fine-grid subspace | ||||||
|  |   //vectors under the block inner product. This step must be performed after computing the fine grid | ||||||
|  |   //eigenvectors and before computing the coarse grid eigenvectors.     | ||||||
|   void Orthogonalise(void ) { |   void Orthogonalise(void ) { | ||||||
|     CoarseScalar InnerProd(_CoarseGrid); |     CoarseScalar InnerProd(_CoarseGrid); | ||||||
|     std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl; |     std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl; | ||||||
| @@ -328,6 +342,8 @@ public: | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //While this method serves to check the coarse eigenvectors, it also recomputes the eigenvalues from the smoothed reconstructed eigenvectors | ||||||
|  |   //hence the smoother can be tuned after running the coarse Lanczos by using a different smoother here | ||||||
|   void testCoarse(RealD resid,ChebyParams cheby_smooth,RealD relax)  |   void testCoarse(RealD resid,ChebyParams cheby_smooth,RealD relax)  | ||||||
|   { |   { | ||||||
|     assert(evals_fine.size() == nbasis); |     assert(evals_fine.size() == nbasis); | ||||||
| @@ -376,18 +392,23 @@ public: | |||||||
|     evals_fine.resize(nbasis); |     evals_fine.resize(nbasis); | ||||||
|     subspace.resize(nbasis,_FineGrid); |     subspace.resize(nbasis,_FineGrid); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //cheby_op: Parameters of the fine grid Chebyshev polynomial used for the Lanczos acceleration | ||||||
|  |   //cheby_smooth: Parameters of a separate Chebyshev polynomial used after the Lanczos has completed to smooth out high frequency noise in the reconstructed fine grid eigenvectors prior to computing the eigenvalue | ||||||
|  |   //relax: Reconstructed eigenvectors (post smoothing) are naturally not as precise as true eigenvectors. This factor acts as a multiplier on the stopping condition when determining whether the results satisfy the user provided stopping condition | ||||||
|   void calcCoarse(ChebyParams cheby_op,ChebyParams cheby_smooth,RealD relax, |   void calcCoarse(ChebyParams cheby_op,ChebyParams cheby_smooth,RealD relax, | ||||||
| 		  int Nstop, int Nk, int Nm,RealD resid,  | 		  int Nstop, int Nk, int Nm,RealD resid,  | ||||||
| 		  RealD MaxIt, RealD betastp, int MinRes) | 		  RealD MaxIt, RealD betastp, int MinRes) | ||||||
|   { |   { | ||||||
|     Chebyshev<FineField>                          Cheby(cheby_op); |     Chebyshev<FineField>                          Cheby(cheby_op); //Chebyshev of fine operator on fine grid | ||||||
|     ProjectedHermOp<Fobj,CComplex,nbasis>         Op(_FineOp,subspace); |     ProjectedHermOp<Fobj,CComplex,nbasis>         Op(_FineOp,subspace); //Fine operator on coarse grid with intermediate fine grid conversion | ||||||
|     ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (Cheby,_FineOp,subspace); |     ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (Cheby,_FineOp,subspace); //Chebyshev of fine operator on coarse grid with intermediate fine grid conversion | ||||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////// |     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|     // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL |     // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL | ||||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////// |     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|     Chebyshev<FineField>                                           ChebySmooth(cheby_smooth); |     Chebyshev<FineField>                                           ChebySmooth(cheby_smooth); //lower order Chebyshev of fine operator on fine grid used to smooth regenerated eigenvectors | ||||||
|     ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax);  |     ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax);  | ||||||
|  |  | ||||||
|     evals_coarse.resize(Nm); |     evals_coarse.resize(Nm); | ||||||
| @@ -395,6 +416,7 @@ public: | |||||||
|  |  | ||||||
|     CoarseField src(_CoarseGrid);     src=1.0;  |     CoarseField src(_CoarseGrid);     src=1.0;  | ||||||
|  |  | ||||||
|  |     //Note the "tester" here is also responsible for generating the fine grid eigenvalues which are output into the "evals_coarse" array | ||||||
|     ImplicitlyRestartedLanczos<CoarseField> IRL(ChebyOp,ChebyOp,ChebySmoothTester,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); |     ImplicitlyRestartedLanczos<CoarseField> IRL(ChebyOp,ChebyOp,ChebySmoothTester,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); | ||||||
|     int Nconv=0; |     int Nconv=0; | ||||||
|     IRL.calc(evals_coarse,evec_coarse,src,Nconv,false); |     IRL.calc(evals_coarse,evec_coarse,src,Nconv,false); | ||||||
| @@ -405,6 +427,14 @@ public: | |||||||
|       std::cout << i << " Coarse eval = " << evals_coarse[i]  << std::endl; |       std::cout << i << " Coarse eval = " << evals_coarse[i]  << std::endl; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Get the fine eigenvector 'i' by reconstruction | ||||||
|  |   void getFineEvecEval(FineField &evec, RealD &eval, const int i) const{ | ||||||
|  |     blockPromote(evec_coarse[i],evec,subspace);   | ||||||
|  |     eval = evals_coarse[i]; | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |      | ||||||
| }; | }; | ||||||
|  |  | ||||||
| NAMESPACE_END(Grid); | NAMESPACE_END(Grid); | ||||||
|   | |||||||
| @@ -30,6 +30,8 @@ template<class Field> class PowerMethod | |||||||
|       RealD vden = norm2(src_n);  |       RealD vden = norm2(src_n);  | ||||||
|       RealD na = vnum/vden;  |       RealD na = vnum/vden;  | ||||||
|  |  | ||||||
|  |       std::cout << GridLogIterative << "PowerMethod: Current approximation of largest eigenvalue " << na << std::endl; | ||||||
|  |        | ||||||
|       if ( (fabs(evalMaxApprox/na - 1.0) < 0.001) || (i==_MAX_ITER_EST_-1) ) {  |       if ( (fabs(evalMaxApprox/na - 1.0) < 0.001) || (i==_MAX_ITER_EST_-1) ) {  | ||||||
|  	evalMaxApprox = na;  |  	evalMaxApprox = na;  | ||||||
| 	std::cout << GridLogMessage << " Approximation of largest eigenvalue: " << evalMaxApprox << std::endl; | 	std::cout << GridLogMessage << " Approximation of largest eigenvalue: " << evalMaxApprox << std::endl; | ||||||
|   | |||||||
| @@ -46,3 +46,4 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/lattice/Lattice_unary.h> | #include <Grid/lattice/Lattice_unary.h> | ||||||
| #include <Grid/lattice/Lattice_transfer.h> | #include <Grid/lattice/Lattice_transfer.h> | ||||||
| #include <Grid/lattice/Lattice_basis.h> | #include <Grid/lattice/Lattice_basis.h> | ||||||
|  | #include <Grid/lattice/Lattice_crc.h> | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								Grid/lattice/Lattice_crc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								Grid/lattice/Lattice_crc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./lib/lattice/Lattice_crc.h | ||||||
|  |  | ||||||
|  |     Copyright (C) 2021 | ||||||
|  |  | ||||||
|  | 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 */ | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | template<class vobj> uint32_t crc(Lattice<vobj> & buf) | ||||||
|  | { | ||||||
|  |   autoView( buf_v , buf, CpuRead); | ||||||
|  |   return ::crc32(0L,(unsigned char *)&buf_v[0],(size_t)sizeof(vobj)*buf.oSites()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #define CRC(U) std::cout << "FingerPrint "<<__FILE__ <<" "<< __LINE__ <<" "<< #U <<" "<<crc(U)<<std::endl; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -32,8 +32,9 @@ | |||||||
| #include <random> | #include <random> | ||||||
|  |  | ||||||
| #ifdef RNG_SITMO | #ifdef RNG_SITMO | ||||||
| #include <Grid/sitmo_rng/sitmo_prng_engine.hpp> | #include <Grid/random/sitmo_prng_engine.hpp> | ||||||
| #endif  | #endif  | ||||||
|  | #include <Grid/random/gaussian.h> | ||||||
|  |  | ||||||
| #if defined(RNG_SITMO) | #if defined(RNG_SITMO) | ||||||
| #define RNG_FAST_DISCARD | #define RNG_FAST_DISCARD | ||||||
| @@ -142,8 +143,8 @@ public: | |||||||
|  |  | ||||||
|   std::vector<RngEngine>                             _generators; |   std::vector<RngEngine>                             _generators; | ||||||
|   std::vector<std::uniform_real_distribution<RealD> > _uniform; |   std::vector<std::uniform_real_distribution<RealD> > _uniform; | ||||||
|   std::vector<std::normal_distribution<RealD> >       _gaussian; |   std::vector<Grid::gaussian_distribution<RealD> >       _gaussian; | ||||||
|   std::vector<std::discrete_distribution<int32_t> >   _bernoulli; |   //  std::vector<std::discrete_distribution<int32_t> >   _bernoulli; | ||||||
|   std::vector<std::uniform_int_distribution<uint32_t> > _uid; |   std::vector<std::uniform_int_distribution<uint32_t> > _uid; | ||||||
|  |  | ||||||
|   /////////////////////// |   /////////////////////// | ||||||
| @@ -243,8 +244,8 @@ public: | |||||||
|   GridSerialRNG() : GridRNGbase() { |   GridSerialRNG() : GridRNGbase() { | ||||||
|     _generators.resize(1); |     _generators.resize(1); | ||||||
|     _uniform.resize(1,std::uniform_real_distribution<RealD>{0,1}); |     _uniform.resize(1,std::uniform_real_distribution<RealD>{0,1}); | ||||||
|     _gaussian.resize(1,std::normal_distribution<RealD>(0.0,1.0) ); |     _gaussian.resize(1,gaussian_distribution<RealD>(0.0,1.0) ); | ||||||
|     _bernoulli.resize(1,std::discrete_distribution<int32_t>{1,1}); |     //    _bernoulli.resize(1,std::discrete_distribution<int32_t>{1,1}); | ||||||
|     _uid.resize(1,std::uniform_int_distribution<uint32_t>() ); |     _uid.resize(1,std::uniform_int_distribution<uint32_t>() ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -357,8 +358,8 @@ public: | |||||||
|  |  | ||||||
|     _generators.resize(_vol); |     _generators.resize(_vol); | ||||||
|     _uniform.resize(_vol,std::uniform_real_distribution<RealD>{0,1}); |     _uniform.resize(_vol,std::uniform_real_distribution<RealD>{0,1}); | ||||||
|     _gaussian.resize(_vol,std::normal_distribution<RealD>(0.0,1.0) ); |     _gaussian.resize(_vol,gaussian_distribution<RealD>(0.0,1.0) ); | ||||||
|     _bernoulli.resize(_vol,std::discrete_distribution<int32_t>{1,1}); |     //    _bernoulli.resize(_vol,std::discrete_distribution<int32_t>{1,1}); | ||||||
|     _uid.resize(_vol,std::uniform_int_distribution<uint32_t>() ); |     _uid.resize(_vol,std::uniform_int_distribution<uint32_t>() ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -515,11 +516,11 @@ public: | |||||||
|  |  | ||||||
| template <class vobj> inline void random(GridParallelRNG &rng,Lattice<vobj> &l)   { rng.fill(l,rng._uniform);  } | template <class vobj> inline void random(GridParallelRNG &rng,Lattice<vobj> &l)   { rng.fill(l,rng._uniform);  } | ||||||
| template <class vobj> inline void gaussian(GridParallelRNG &rng,Lattice<vobj> &l) { rng.fill(l,rng._gaussian); } | template <class vobj> inline void gaussian(GridParallelRNG &rng,Lattice<vobj> &l) { rng.fill(l,rng._gaussian); } | ||||||
| template <class vobj> inline void bernoulli(GridParallelRNG &rng,Lattice<vobj> &l){ rng.fill(l,rng._bernoulli);} | //template <class vobj> inline void bernoulli(GridParallelRNG &rng,Lattice<vobj> &l){ rng.fill(l,rng._bernoulli);} | ||||||
|  |  | ||||||
| template <class sobj> inline void random(GridSerialRNG &rng,sobj &l)   { rng.fill(l,rng._uniform  ); } | template <class sobj> inline void random(GridSerialRNG &rng,sobj &l)   { rng.fill(l,rng._uniform  ); } | ||||||
| template <class sobj> inline void gaussian(GridSerialRNG &rng,sobj &l) { rng.fill(l,rng._gaussian ); } | template <class sobj> inline void gaussian(GridSerialRNG &rng,sobj &l) { rng.fill(l,rng._gaussian ); } | ||||||
| template <class sobj> inline void bernoulli(GridSerialRNG &rng,sobj &l){ rng.fill(l,rng._bernoulli); } | //template <class sobj> inline void bernoulli(GridSerialRNG &rng,sobj &l){ rng.fill(l,rng._bernoulli); } | ||||||
|  |  | ||||||
| NAMESPACE_END(Grid); | NAMESPACE_END(Grid); | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -855,7 +855,7 @@ void ExtractSliceLocal(Lattice<vobj> &lowDim,const Lattice<vobj> & higherDim,int | |||||||
|  |  | ||||||
|  |  | ||||||
| template<class vobj> | template<class vobj> | ||||||
| void Replicate(Lattice<vobj> &coarse,Lattice<vobj> & fine) | void Replicate(const Lattice<vobj> &coarse,Lattice<vobj> & fine) | ||||||
| { | { | ||||||
|   typedef typename vobj::scalar_object sobj; |   typedef typename vobj::scalar_object sobj; | ||||||
|  |  | ||||||
| @@ -1080,54 +1080,96 @@ vectorizeFromRevLexOrdArray( std::vector<sobj> &in, Lattice<vobj> &out) | |||||||
|   }); |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
| //Convert a Lattice from one precision to another | //The workspace for a precision change operation allowing for the reuse of the mapping to save time on subsequent calls | ||||||
| template<class VobjOut, class VobjIn> | class precisionChangeWorkspace{ | ||||||
| void precisionChange(Lattice<VobjOut> &out, const Lattice<VobjIn> &in) |   std::pair<Integer,Integer>* fmap_device; //device pointer | ||||||
| { | public: | ||||||
|   assert(out.Grid()->Nd() == in.Grid()->Nd()); |   precisionChangeWorkspace(GridBase *out_grid, GridBase *in_grid){ | ||||||
|   for(int d=0;d<out.Grid()->Nd();d++){ |     //Build a map between the sites and lanes of the output field and the input field as we cannot use the Grids on the device | ||||||
|     assert(out.Grid()->FullDimensions()[d] == in.Grid()->FullDimensions()[d]); |     assert(out_grid->Nd() == in_grid->Nd()); | ||||||
|   } |     for(int d=0;d<out_grid->Nd();d++){ | ||||||
|   out.Checkerboard() = in.Checkerboard(); |       assert(out_grid->FullDimensions()[d] == in_grid->FullDimensions()[d]); | ||||||
|   GridBase *in_grid=in.Grid(); |  | ||||||
|   GridBase *out_grid = out.Grid(); |  | ||||||
|  |  | ||||||
|   typedef typename VobjOut::scalar_object SobjOut; |  | ||||||
|   typedef typename VobjIn::scalar_object SobjIn; |  | ||||||
|  |  | ||||||
|   int ndim = out.Grid()->Nd(); |  | ||||||
|   int out_nsimd = out_grid->Nsimd(); |  | ||||||
|      |  | ||||||
|   std::vector<Coordinate > out_icoor(out_nsimd); |  | ||||||
|        |  | ||||||
|   for(int lane=0; lane < out_nsimd; lane++){ |  | ||||||
|     out_icoor[lane].resize(ndim); |  | ||||||
|     out_grid->iCoorFromIindex(out_icoor[lane], lane); |  | ||||||
|   } |  | ||||||
|          |  | ||||||
|   std::vector<SobjOut> in_slex_conv(in_grid->lSites()); |  | ||||||
|   unvectorizeToLexOrdArray(in_slex_conv, in); |  | ||||||
|      |  | ||||||
|   autoView( out_v , out, CpuWrite); |  | ||||||
|   thread_for(out_oidx,out_grid->oSites(),{ |  | ||||||
|     Coordinate out_ocoor(ndim); |  | ||||||
|     out_grid->oCoorFromOindex(out_ocoor, out_oidx); |  | ||||||
|  |  | ||||||
|     ExtractPointerArray<SobjOut> ptrs(out_nsimd);       |  | ||||||
|  |  | ||||||
|     Coordinate lcoor(out_grid->Nd()); |  | ||||||
|        |  | ||||||
|     for(int lane=0; lane < out_nsimd; lane++){ |  | ||||||
|       for(int mu=0;mu<ndim;mu++) |  | ||||||
| 	lcoor[mu] = out_ocoor[mu] + out_grid->_rdimensions[mu]*out_icoor[lane][mu]; |  | ||||||
| 	 |  | ||||||
|       int llex; Lexicographic::IndexFromCoor(lcoor, llex, out_grid->_ldimensions); |  | ||||||
|       ptrs[lane] = &in_slex_conv[llex]; |  | ||||||
|     } |     } | ||||||
|     merge(out_v[out_oidx], ptrs, 0); |     int Nsimd_out = out_grid->Nsimd(); | ||||||
|   }); |  | ||||||
|  |     std::vector<Coordinate> out_icorrs(out_grid->Nsimd()); //reuse these | ||||||
|  |     for(int lane=0; lane < out_grid->Nsimd(); lane++) | ||||||
|  |       out_grid->iCoorFromIindex(out_icorrs[lane], lane); | ||||||
|  |    | ||||||
|  |     std::vector<std::pair<Integer,Integer> > fmap_host(out_grid->lSites()); //lsites = osites*Nsimd | ||||||
|  |     thread_for(out_oidx,out_grid->oSites(),{ | ||||||
|  | 	Coordinate out_ocorr;  | ||||||
|  | 	out_grid->oCoorFromOindex(out_ocorr, out_oidx); | ||||||
|  |        | ||||||
|  | 	Coordinate lcorr; //the local coordinate (common to both in and out as full coordinate) | ||||||
|  | 	for(int out_lane=0; out_lane < Nsimd_out; out_lane++){ | ||||||
|  | 	  out_grid->InOutCoorToLocalCoor(out_ocorr, out_icorrs[out_lane], lcorr); | ||||||
|  | 	 | ||||||
|  | 	  //int in_oidx = in_grid->oIndex(lcorr), in_lane = in_grid->iIndex(lcorr); | ||||||
|  | 	  //Note oIndex and OcorrFromOindex (and same for iIndex) are not inverse for checkerboarded lattice, the former coordinates being defined on the full lattice and the latter on the reduced lattice | ||||||
|  | 	  //Until this is fixed we need to circumvent the problem locally. Here I will use the coordinates defined on the reduced lattice for simplicity | ||||||
|  | 	  int in_oidx = 0, in_lane = 0; | ||||||
|  | 	  for(int d=0;d<in_grid->_ndimension;d++){ | ||||||
|  | 	    in_oidx += in_grid->_ostride[d] * ( lcorr[d] % in_grid->_rdimensions[d] ); | ||||||
|  | 	    in_lane += in_grid->_istride[d] * ( lcorr[d] / in_grid->_rdimensions[d] ); | ||||||
|  | 	  } | ||||||
|  | 	  fmap_host[out_lane + Nsimd_out*out_oidx] = std::pair<Integer,Integer>( in_oidx, in_lane ); | ||||||
|  | 	} | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |     //Copy the map to the device (if we had a way to tell if an accelerator is in use we could avoid this copy for CPU-only machines) | ||||||
|  |     size_t fmap_bytes = out_grid->lSites() * sizeof(std::pair<Integer,Integer>); | ||||||
|  |     fmap_device = (std::pair<Integer,Integer>*)acceleratorAllocDevice(fmap_bytes); | ||||||
|  |     acceleratorCopyToDevice(fmap_host.data(), fmap_device, fmap_bytes);  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Prevent moving or copying | ||||||
|  |   precisionChangeWorkspace(const precisionChangeWorkspace &r) = delete; | ||||||
|  |   precisionChangeWorkspace(precisionChangeWorkspace &&r) = delete; | ||||||
|  |   precisionChangeWorkspace &operator=(const precisionChangeWorkspace &r) = delete; | ||||||
|  |   precisionChangeWorkspace &operator=(precisionChangeWorkspace &&r) = delete; | ||||||
|  |    | ||||||
|  |   std::pair<Integer,Integer> const* getMap() const{ return fmap_device; } | ||||||
|  |  | ||||||
|  |   ~precisionChangeWorkspace(){ | ||||||
|  |     acceleratorFreeDevice(fmap_device); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Convert a lattice of one precision to another. The input workspace contains the mapping data. | ||||||
|  | template<class VobjOut, class VobjIn> | ||||||
|  | void precisionChange(Lattice<VobjOut> &out, const Lattice<VobjIn> &in, const precisionChangeWorkspace &workspace){ | ||||||
|  |   static_assert( std::is_same<typename VobjOut::DoublePrecision, typename VobjIn::DoublePrecision>::value == 1, "copyLane: tensor types must be the same" ); //if tensor types are same the DoublePrecision type must be the same | ||||||
|  |  | ||||||
|  |   out.Checkerboard() = in.Checkerboard(); | ||||||
|  |   constexpr int Nsimd_out = VobjOut::Nsimd(); | ||||||
|  |  | ||||||
|  |   std::pair<Integer,Integer> const* fmap_device = workspace.getMap(); | ||||||
|  |  | ||||||
|  |   //Do the copy/precision change | ||||||
|  |   autoView( out_v , out, AcceleratorWrite); | ||||||
|  |   autoView( in_v , in, AcceleratorRead); | ||||||
|  |  | ||||||
|  |   accelerator_for(out_oidx, out.Grid()->oSites(), 1,{ | ||||||
|  |       std::pair<Integer,Integer> const* fmap_osite = fmap_device + out_oidx*Nsimd_out; | ||||||
|  |       for(int out_lane=0; out_lane < Nsimd_out; out_lane++){       | ||||||
|  | 	int in_oidx = fmap_osite[out_lane].first; | ||||||
|  | 	int in_lane = fmap_osite[out_lane].second; | ||||||
|  | 	copyLane(out_v[out_oidx], out_lane, in_v[in_oidx], in_lane); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //Convert a Lattice from one precision to another | ||||||
|  | //Generate the workspace in place; if multiple calls with the same mapping are performed, consider pregenerating the workspace and reusing | ||||||
|  | template<class VobjOut, class VobjIn> | ||||||
|  | void precisionChange(Lattice<VobjOut> &out, const Lattice<VobjIn> &in){ | ||||||
|  |   precisionChangeWorkspace workspace(out.Grid(), in.Grid()); | ||||||
|  |   precisionChange(out, in, workspace); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||||
| // Communicate between grids | // Communicate between grids | ||||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||||
|   | |||||||
| @@ -69,6 +69,7 @@ GridLogger GridLogDebug  (1, "Debug", GridLogColours, "PURPLE"); | |||||||
| GridLogger GridLogPerformance(1, "Performance", GridLogColours, "GREEN"); | GridLogger GridLogPerformance(1, "Performance", GridLogColours, "GREEN"); | ||||||
| GridLogger GridLogIterative  (1, "Iterative", GridLogColours, "BLUE"); | GridLogger GridLogIterative  (1, "Iterative", GridLogColours, "BLUE"); | ||||||
| GridLogger GridLogIntegrator (1, "Integrator", GridLogColours, "BLUE"); | GridLogger GridLogIntegrator (1, "Integrator", GridLogColours, "BLUE"); | ||||||
|  | GridLogger GridLogHMC (1, "HMC", GridLogColours, "BLUE"); | ||||||
|  |  | ||||||
| void GridLogConfigure(std::vector<std::string> &logstreams) { | void GridLogConfigure(std::vector<std::string> &logstreams) { | ||||||
|   GridLogError.Active(0); |   GridLogError.Active(0); | ||||||
| @@ -79,6 +80,7 @@ void GridLogConfigure(std::vector<std::string> &logstreams) { | |||||||
|   GridLogPerformance.Active(0); |   GridLogPerformance.Active(0); | ||||||
|   GridLogIntegrator.Active(1); |   GridLogIntegrator.Active(1); | ||||||
|   GridLogColours.Active(0); |   GridLogColours.Active(0); | ||||||
|  |   GridLogHMC.Active(1); | ||||||
|  |  | ||||||
|   for (int i = 0; i < logstreams.size(); i++) { |   for (int i = 0; i < logstreams.size(); i++) { | ||||||
|     if (logstreams[i] == std::string("Error"))       GridLogError.Active(1); |     if (logstreams[i] == std::string("Error"))       GridLogError.Active(1); | ||||||
| @@ -87,7 +89,8 @@ void GridLogConfigure(std::vector<std::string> &logstreams) { | |||||||
|     if (logstreams[i] == std::string("Iterative"))   GridLogIterative.Active(1); |     if (logstreams[i] == std::string("Iterative"))   GridLogIterative.Active(1); | ||||||
|     if (logstreams[i] == std::string("Debug"))       GridLogDebug.Active(1); |     if (logstreams[i] == std::string("Debug"))       GridLogDebug.Active(1); | ||||||
|     if (logstreams[i] == std::string("Performance")) GridLogPerformance.Active(1); |     if (logstreams[i] == std::string("Performance")) GridLogPerformance.Active(1); | ||||||
|     if (logstreams[i] == std::string("Integrator"))  GridLogIntegrator.Active(1); |     if (logstreams[i] == std::string("NoIntegrator"))  GridLogIntegrator.Active(0); | ||||||
|  |     if (logstreams[i] == std::string("NoHMC"))         GridLogHMC.Active(0); | ||||||
|     if (logstreams[i] == std::string("Colours"))     GridLogColours.Active(1); |     if (logstreams[i] == std::string("Colours"))     GridLogColours.Active(1); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -182,6 +182,7 @@ extern GridLogger GridLogDebug  ; | |||||||
| extern GridLogger GridLogPerformance; | extern GridLogger GridLogPerformance; | ||||||
| extern GridLogger GridLogIterative  ; | extern GridLogger GridLogIterative  ; | ||||||
| extern GridLogger GridLogIntegrator  ; | extern GridLogger GridLogIntegrator  ; | ||||||
|  | extern GridLogger GridLogHMC; | ||||||
| extern Colours    GridLogColours; | extern Colours    GridLogColours; | ||||||
|  |  | ||||||
| std::string demangle(const char* name) ; | std::string demangle(const char* name) ; | ||||||
|   | |||||||
| @@ -39,9 +39,11 @@ using namespace Grid; | |||||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||||
| class NerscIO : public BinaryIO {  | class NerscIO : public BinaryIO {  | ||||||
| public: | public: | ||||||
|  |  | ||||||
|   typedef Lattice<vLorentzColourMatrixD> GaugeField; |   typedef Lattice<vLorentzColourMatrixD> GaugeField; | ||||||
|  |  | ||||||
|  |   // Enable/disable exiting if the plaquette in the header does not match the value computed (default true) | ||||||
|  |   static bool & exitOnReadPlaquetteMismatch(){ static bool v=true; return v; } | ||||||
|  |  | ||||||
|   static inline void truncate(std::string file){ |   static inline void truncate(std::string file){ | ||||||
|     std::ofstream fout(file,std::ios::out); |     std::ofstream fout(file,std::ios::out); | ||||||
|   } |   } | ||||||
| @@ -198,7 +200,7 @@ public: | |||||||
|       std::cerr << " nersc_csum  " <<std::hex<< nersc_csum << " " << header.checksum<< std::dec<< std::endl; |       std::cerr << " nersc_csum  " <<std::hex<< nersc_csum << " " << header.checksum<< std::dec<< std::endl; | ||||||
|       exit(0); |       exit(0); | ||||||
|     } |     } | ||||||
|     assert(fabs(clone.plaquette -header.plaquette ) < 1.0e-5 ); |     if(exitOnReadPlaquetteMismatch()) assert(fabs(clone.plaquette -header.plaquette ) < 1.0e-5 ); | ||||||
|     assert(fabs(clone.link_trace-header.link_trace) < 1.0e-6 ); |     assert(fabs(clone.link_trace-header.link_trace) < 1.0e-6 ); | ||||||
|     assert(nersc_csum == header.checksum ); |     assert(nersc_csum == header.checksum ); | ||||||
|        |        | ||||||
|   | |||||||
| @@ -63,6 +63,7 @@ static constexpr int Ngp=2; // gparity index range | |||||||
| #define ColourIndex  (2) | #define ColourIndex  (2) | ||||||
| #define SpinIndex    (1) | #define SpinIndex    (1) | ||||||
| #define LorentzIndex (0) | #define LorentzIndex (0) | ||||||
|  | #define GparityFlavourIndex (0) | ||||||
|  |  | ||||||
| // Also should make these a named enum type | // Also should make these a named enum type | ||||||
| static constexpr int DaggerNo=0; | static constexpr int DaggerNo=0; | ||||||
| @@ -87,6 +88,8 @@ template<typename T> struct isCoarsened { | |||||||
| template <typename T> using IfCoarsened    = Invoke<std::enable_if< isCoarsened<T>::value,int> > ; | template <typename T> using IfCoarsened    = Invoke<std::enable_if< isCoarsened<T>::value,int> > ; | ||||||
| template <typename T> using IfNotCoarsened = Invoke<std::enable_if<!isCoarsened<T>::value,int> > ; | template <typename T> using IfNotCoarsened = Invoke<std::enable_if<!isCoarsened<T>::value,int> > ; | ||||||
|  |  | ||||||
|  | const int GparityFlavourTensorIndex = 3; //TensorLevel counts from the bottom! | ||||||
|  |  | ||||||
| // ChrisK very keen to add extra space for Gparity doubling. | // ChrisK very keen to add extra space for Gparity doubling. | ||||||
| // | // | ||||||
| // Also add domain wall index, in a way where Wilson operator  | // Also add domain wall index, in a way where Wilson operator  | ||||||
| @@ -110,8 +113,10 @@ template<typename vtype> using iHalfSpinColourVector      = iScalar<iVector<iVec | |||||||
|     template<typename vtype> using iSpinColourSpinColourMatrix  = iScalar<iMatrix<iMatrix<iMatrix<iMatrix<vtype, Nc>, Ns>, Nc>, Ns> >; |     template<typename vtype> using iSpinColourSpinColourMatrix  = iScalar<iMatrix<iMatrix<iMatrix<iMatrix<vtype, Nc>, Ns>, Nc>, Ns> >; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename vtype> using iGparityFlavourVector                = iVector<iScalar<iScalar<vtype> >, Ngp>; | ||||||
| template<typename vtype> using iGparitySpinColourVector       = iVector<iVector<iVector<vtype, Nc>, Ns>, Ngp >; | template<typename vtype> using iGparitySpinColourVector       = iVector<iVector<iVector<vtype, Nc>, Ns>, Ngp >; | ||||||
| template<typename vtype> using iGparityHalfSpinColourVector   = iVector<iVector<iVector<vtype, Nc>, Nhs>, Ngp >; | template<typename vtype> using iGparityHalfSpinColourVector   = iVector<iVector<iVector<vtype, Nc>, Nhs>, Ngp >; | ||||||
|  | template<typename vtype> using iGparityFlavourMatrix = iMatrix<iScalar<iScalar<vtype> >, Ngp>; | ||||||
|  |  | ||||||
| // Spin matrix | // Spin matrix | ||||||
| typedef iSpinMatrix<Complex  >          SpinMatrix; | typedef iSpinMatrix<Complex  >          SpinMatrix; | ||||||
| @@ -176,6 +181,16 @@ typedef iDoubleStoredColourMatrix<vComplex > vDoubleStoredColourMatrix; | |||||||
| typedef iDoubleStoredColourMatrix<vComplexF> vDoubleStoredColourMatrixF; | typedef iDoubleStoredColourMatrix<vComplexF> vDoubleStoredColourMatrixF; | ||||||
| typedef iDoubleStoredColourMatrix<vComplexD> vDoubleStoredColourMatrixD; | typedef iDoubleStoredColourMatrix<vComplexD> vDoubleStoredColourMatrixD; | ||||||
|  |  | ||||||
|  | //G-parity flavour matrix | ||||||
|  | typedef iGparityFlavourMatrix<Complex> GparityFlavourMatrix; | ||||||
|  | typedef iGparityFlavourMatrix<ComplexF> GparityFlavourMatrixF; | ||||||
|  | typedef iGparityFlavourMatrix<ComplexD> GparityFlavourMatrixD; | ||||||
|  |  | ||||||
|  | typedef iGparityFlavourMatrix<vComplex> vGparityFlavourMatrix; | ||||||
|  | typedef iGparityFlavourMatrix<vComplexF> vGparityFlavourMatrixF; | ||||||
|  | typedef iGparityFlavourMatrix<vComplexD> vGparityFlavourMatrixD; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Spin vector | // Spin vector | ||||||
| typedef iSpinVector<Complex >           SpinVector; | typedef iSpinVector<Complex >           SpinVector; | ||||||
| typedef iSpinVector<ComplexF>           SpinVectorF; | typedef iSpinVector<ComplexF>           SpinVectorF; | ||||||
| @@ -221,6 +236,16 @@ typedef iHalfSpinColourVector<vComplex > vHalfSpinColourVector; | |||||||
| typedef iHalfSpinColourVector<vComplexF> vHalfSpinColourVectorF; | typedef iHalfSpinColourVector<vComplexF> vHalfSpinColourVectorF; | ||||||
| typedef iHalfSpinColourVector<vComplexD> vHalfSpinColourVectorD; | typedef iHalfSpinColourVector<vComplexD> vHalfSpinColourVectorD; | ||||||
|  |  | ||||||
|  | //G-parity flavour vector | ||||||
|  | typedef iGparityFlavourVector<Complex >         GparityFlavourVector; | ||||||
|  | typedef iGparityFlavourVector<ComplexF>         GparityFlavourVectorF; | ||||||
|  | typedef iGparityFlavourVector<ComplexD>         GparityFlavourVectorD; | ||||||
|  |  | ||||||
|  | typedef iGparityFlavourVector<vComplex >         vGparityFlavourVector; | ||||||
|  | typedef iGparityFlavourVector<vComplexF>         vGparityFlavourVectorF; | ||||||
|  | typedef iGparityFlavourVector<vComplexD>         vGparityFlavourVectorD; | ||||||
|  |  | ||||||
|  |      | ||||||
| // singlets | // singlets | ||||||
| typedef iSinglet<Complex >         TComplex;     // FIXME This is painful. Tensor singlet complex type. | typedef iSinglet<Complex >         TComplex;     // FIXME This is painful. Tensor singlet complex type. | ||||||
| typedef iSinglet<ComplexF>         TComplexF;    // FIXME This is painful. Tensor singlet complex type. | typedef iSinglet<ComplexF>         TComplexF;    // FIXME This is painful. Tensor singlet complex type. | ||||||
|   | |||||||
| @@ -36,7 +36,8 @@ 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; //Here the first Nd-1 directions are treated as "spatial", and a twist value of 1 indicates G-parity BCs in that direction.  | ||||||
|  |                      //mu=Nd-1 is assumed to be the time direction and a twist value of 1 indicates antiperiodic BCs | ||||||
|   GparityWilsonImplParams() : twists(Nd, 0) {}; |   GparityWilsonImplParams() : twists(Nd, 0) {}; | ||||||
| }; | }; | ||||||
|    |    | ||||||
| @@ -65,7 +66,8 @@ struct StaggeredImplParams { | |||||||
| 				    RealD, tolerance,  | 				    RealD, tolerance,  | ||||||
| 				    int,   degree,  | 				    int,   degree,  | ||||||
| 				    int,   precision, | 				    int,   precision, | ||||||
| 				    int,   BoundsCheckFreq); | 				    int,   BoundsCheckFreq, | ||||||
|  | 				    RealD, BoundsCheckTol); | ||||||
|      |      | ||||||
|   // MaxIter and tolerance, vectors?? |   // MaxIter and tolerance, vectors?? | ||||||
|      |      | ||||||
| @@ -76,16 +78,62 @@ struct StaggeredImplParams { | |||||||
| 				RealD tol      = 1.0e-8,  | 				RealD tol      = 1.0e-8,  | ||||||
|                            	int _degree    = 10, |                            	int _degree    = 10, | ||||||
| 				int _precision = 64, | 				int _precision = 64, | ||||||
| 				int _BoundsCheckFreq=20) | 				int _BoundsCheckFreq=20, | ||||||
|  | 				double _BoundsCheckTol=1e-6) | ||||||
|       : lo(_lo), |       : lo(_lo), | ||||||
| 	hi(_hi), | 	hi(_hi), | ||||||
| 	MaxIter(_maxit), | 	MaxIter(_maxit), | ||||||
| 	tolerance(tol), | 	tolerance(tol), | ||||||
| 	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 | ||||||
|   | |||||||
| @@ -30,6 +30,18 @@ directory | |||||||
|  |  | ||||||
| NAMESPACE_BEGIN(Grid); | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |   Policy implementation for G-parity boundary conditions | ||||||
|  |  | ||||||
|  |   Rather than treating the gauge field as a flavored field, the Grid implementation of G-parity treats the gauge field as a regular | ||||||
|  |   field with complex conjugate boundary conditions. In order to ensure the second flavor interacts with the conjugate links and the first | ||||||
|  |   with the regular links we overload the functionality of doubleStore, whose purpose is to store the gauge field and the barrel-shifted gauge field | ||||||
|  |   to avoid communicating links when applying the Dirac operator, such that the double-stored field contains also a flavor index which maps to | ||||||
|  |   either the link or the conjugate link. This flavored field is then used by multLink to apply the correct link to a spinor. | ||||||
|  |  | ||||||
|  |   Here the first Nd-1 directions are treated as "spatial", and a twist value of 1 indicates G-parity BCs in that direction.  | ||||||
|  |   mu=Nd-1 is assumed to be the time direction and a twist value of 1 indicates antiperiodic BCs | ||||||
|  |  */ | ||||||
| template <class S, class Representation = FundamentalRepresentation, class Options=CoeffReal> | template <class S, class Representation = FundamentalRepresentation, class Options=CoeffReal> | ||||||
| class GparityWilsonImpl : public ConjugateGaugeImpl<GaugeImplTypes<S, Representation::Dimension> > { | class GparityWilsonImpl : public ConjugateGaugeImpl<GaugeImplTypes<S, Representation::Dimension> > { | ||||||
| public: | public: | ||||||
| @@ -113,7 +125,7 @@ public: | |||||||
|     || ((distance== 1)&&(icoor[direction]==1)) |     || ((distance== 1)&&(icoor[direction]==1)) | ||||||
|     || ((distance==-1)&&(icoor[direction]==0)); |     || ((distance==-1)&&(icoor[direction]==0)); | ||||||
|  |  | ||||||
|     permute_lane = permute_lane && SE->_around_the_world && St.parameters.twists[mmu]; //only if we are going around the world |     permute_lane = permute_lane && SE->_around_the_world && St.parameters.twists[mmu] && mmu < Nd-1; //only if we are going around the world in a spatial direction | ||||||
|  |  | ||||||
|     //Apply the links |     //Apply the links | ||||||
|     int f_upper = permute_lane ? 1 : 0; |     int f_upper = permute_lane ? 1 : 0; | ||||||
| @@ -139,10 +151,10 @@ public: | |||||||
|     assert((distance == 1) || (distance == -1));  // nearest neighbour stencil hard code |     assert((distance == 1) || (distance == -1));  // nearest neighbour stencil hard code | ||||||
|     assert((sl == 1) || (sl == 2)); |     assert((sl == 1) || (sl == 2)); | ||||||
|  |  | ||||||
|     if ( SE->_around_the_world && St.parameters.twists[mmu] ) { |     //If this site is an global boundary site, perform the G-parity flavor twist | ||||||
|  |     if ( mmu < Nd-1 && SE->_around_the_world && St.parameters.twists[mmu] ) { | ||||||
|       if ( sl == 2 ) { |       if ( sl == 2 ) { | ||||||
|         | 	//Only do the twist for lanes on the edge of the physical node | ||||||
| 	ExtractBuffer<sobj> vals(Nsimd); | 	ExtractBuffer<sobj> vals(Nsimd); | ||||||
|  |  | ||||||
| 	extract(chi,vals); | 	extract(chi,vals); | ||||||
| @@ -197,6 +209,19 @@ public: | |||||||
|     reg = memory; |     reg = memory; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Poke 'poke_f0' onto flavor 0 and 'poke_f1' onto flavor 1 in direction mu of the doubled gauge field Uds | ||||||
|  |   inline void pokeGparityDoubledGaugeField(DoubledGaugeField &Uds, const GaugeLinkField &poke_f0, const GaugeLinkField &poke_f1, const int mu){ | ||||||
|  |     autoView(poke_f0_v, poke_f0, CpuRead); | ||||||
|  |     autoView(poke_f1_v, poke_f1, CpuRead); | ||||||
|  |     autoView(Uds_v, Uds, CpuWrite); | ||||||
|  |     thread_foreach(ss,poke_f0_v,{ | ||||||
|  | 	Uds_v[ss](0)(mu) = poke_f0_v[ss](); | ||||||
|  | 	Uds_v[ss](1)(mu) = poke_f1_v[ss](); | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |  | ||||||
|   inline void DoubleStore(GridBase *GaugeGrid,DoubledGaugeField &Uds,const GaugeField &Umu) |   inline void DoubleStore(GridBase *GaugeGrid,DoubledGaugeField &Uds,const GaugeField &Umu) | ||||||
|   { |   { | ||||||
|     conformable(Uds.Grid(),GaugeGrid); |     conformable(Uds.Grid(),GaugeGrid); | ||||||
| @@ -208,13 +233,18 @@ public: | |||||||
|     |     | ||||||
|     Lattice<iScalar<vInteger> > coor(GaugeGrid); |     Lattice<iScalar<vInteger> > coor(GaugeGrid); | ||||||
|  |  | ||||||
|     for(int mu=0;mu<Nd;mu++){ |     //Here the first Nd-1 directions are treated as "spatial", and a twist value of 1 indicates G-parity BCs in that direction.  | ||||||
|  |     //mu=Nd-1 is assumed to be the time direction and a twist value of 1 indicates antiperiodic BCs         | ||||||
|  |     for(int mu=0;mu<Nd-1;mu++){ | ||||||
|  |  | ||||||
|       LatticeCoordinate(coor,mu); |       if( Params.twists[mu] ){ | ||||||
|  | 	LatticeCoordinate(coor,mu); | ||||||
|  |       } | ||||||
|            |            | ||||||
|       U     = PeekIndex<LorentzIndex>(Umu,mu); |       U     = PeekIndex<LorentzIndex>(Umu,mu); | ||||||
|       Uconj = conjugate(U); |       Uconj = conjugate(U); | ||||||
|       |       | ||||||
|  |       // Implement the isospin rotation sign on the boundary between f=1 and f=0 | ||||||
|       // This phase could come from a simple bc 1,1,-1,1 .. |       // This phase could come from a simple bc 1,1,-1,1 .. | ||||||
|       int neglink = GaugeGrid->GlobalDimensions()[mu]-1; |       int neglink = GaugeGrid->GlobalDimensions()[mu]-1; | ||||||
|       if ( Params.twists[mu] ) {  |       if ( Params.twists[mu] ) {  | ||||||
| @@ -229,7 +259,7 @@ public: | |||||||
| 	thread_foreach(ss,U_v,{ | 	thread_foreach(ss,U_v,{ | ||||||
| 	    Uds_v[ss](0)(mu) = U_v[ss](); | 	    Uds_v[ss](0)(mu) = U_v[ss](); | ||||||
| 	    Uds_v[ss](1)(mu) = Uconj_v[ss](); | 	    Uds_v[ss](1)(mu) = Uconj_v[ss](); | ||||||
| 	  }); | 	}); | ||||||
|       } |       } | ||||||
|            |            | ||||||
|       U     = adj(Cshift(U    ,mu,-1));      // correct except for spanning the boundary |       U     = adj(Cshift(U    ,mu,-1));      // correct except for spanning the boundary | ||||||
| @@ -260,6 +290,38 @@ public: | |||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     { //periodic / antiperiodic temporal BCs | ||||||
|  |       int mu = Nd-1; | ||||||
|  |       int L   = GaugeGrid->GlobalDimensions()[mu]; | ||||||
|  |       int Lmu = L - 1; | ||||||
|  |  | ||||||
|  |       LatticeCoordinate(coor, mu); | ||||||
|  |  | ||||||
|  |       U = PeekIndex<LorentzIndex>(Umu, mu); //Get t-directed links | ||||||
|  |        | ||||||
|  |       GaugeLinkField *Upoke = &U; | ||||||
|  |  | ||||||
|  |       if(Params.twists[mu]){ //antiperiodic | ||||||
|  | 	Utmp =  where(coor == Lmu, -U, U); | ||||||
|  | 	Upoke = &Utmp; | ||||||
|  |       } | ||||||
|  |      | ||||||
|  |       Uconj = conjugate(*Upoke); //second flavor interacts with conjugate links       | ||||||
|  |       pokeGparityDoubledGaugeField(Uds, *Upoke, Uconj, mu); | ||||||
|  |  | ||||||
|  |       //Get the barrel-shifted field | ||||||
|  |       Utmp = adj(Cshift(U, mu, -1)); //is a forward shift! | ||||||
|  |       Upoke = &Utmp; | ||||||
|  |  | ||||||
|  |       if(Params.twists[mu]){ | ||||||
|  | 	U = where(coor == 0, -Utmp, Utmp);  //boundary phase | ||||||
|  | 	Upoke = &U; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       Uconj = conjugate(*Upoke); | ||||||
|  |       pokeGparityDoubledGaugeField(Uds, *Upoke, Uconj, mu + 4); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|        |        | ||||||
|   inline void InsertForce4D(GaugeField &mat, FermionField &Btilde, FermionField &A, int mu) { |   inline void InsertForce4D(GaugeField &mat, FermionField &Btilde, FermionField &A, int mu) { | ||||||
| @@ -300,27 +362,47 @@ public: | |||||||
|   } |   } | ||||||
|   |   | ||||||
|   inline void InsertForce5D(GaugeField &mat, FermionField &Btilde, FermionField Ã, int mu) { |   inline void InsertForce5D(GaugeField &mat, FermionField &Btilde, FermionField Ã, int mu) { | ||||||
|  |     int Ls=Btilde.Grid()->_fdimensions[0]; | ||||||
|      |      | ||||||
|     int Ls = Btilde.Grid()->_fdimensions[0]; |  | ||||||
|          |  | ||||||
|     GaugeLinkField tmp(mat.Grid()); |  | ||||||
|     tmp = Zero(); |  | ||||||
|     { |     { | ||||||
|       autoView( tmp_v , tmp, CpuWrite); |       GridBase *GaugeGrid = mat.Grid(); | ||||||
|       autoView( Atilde_v , Atilde, CpuRead); |       Lattice<iScalar<vInteger> > coor(GaugeGrid); | ||||||
|       autoView( Btilde_v , Btilde, CpuRead); |  | ||||||
|       thread_for(ss,tmp.Grid()->oSites(),{ |       if( Params.twists[mu] ){ | ||||||
| 	  for (int s = 0; s < Ls; s++) { | 	LatticeCoordinate(coor,mu); | ||||||
| 	    int sF = s + Ls * ss; |       } | ||||||
| 	    auto ttmp = traceIndex<SpinIndex>(outerProduct(Btilde_v[sF], Atilde_v[sF])); |  | ||||||
| 	    tmp_v[ss]() = tmp_v[ss]() + ttmp(0, 0) + conjugate(ttmp(1, 1)); |       autoView( mat_v , mat, AcceleratorWrite); | ||||||
| 	  } |       autoView( Btilde_v , Btilde, AcceleratorRead); | ||||||
| 	}); |       autoView( Atilde_v , Atilde, AcceleratorRead); | ||||||
|  |       accelerator_for(sss,mat.Grid()->oSites(), FermionField::vector_type::Nsimd(),{	   | ||||||
|  |   	  int sU=sss; | ||||||
|  |   	  typedef decltype(coalescedRead(mat_v[sU](mu)() )) ColorMatrixType; | ||||||
|  |   	  ColorMatrixType sum; | ||||||
|  |   	  zeroit(sum); | ||||||
|  |   	  for(int s=0;s<Ls;s++){ | ||||||
|  |   	    int sF = s+Ls*sU; | ||||||
|  |   	    for(int spn=0;spn<Ns;spn++){ //sum over spin | ||||||
|  | 	      //Flavor 0 | ||||||
|  |   	      auto bb = coalescedRead(Btilde_v[sF](0)(spn) ); //color vector | ||||||
|  |   	      auto aa = coalescedRead(Atilde_v[sF](0)(spn) ); | ||||||
|  |   	      sum = sum + outerProduct(bb,aa); | ||||||
|  |  | ||||||
|  |   	      //Flavor 1 | ||||||
|  |   	      bb = coalescedRead(Btilde_v[sF](1)(spn) ); | ||||||
|  |   	      aa = coalescedRead(Atilde_v[sF](1)(spn) ); | ||||||
|  |   	      sum = sum + conjugate(outerProduct(bb,aa)); | ||||||
|  |   	    } | ||||||
|  |   	  }	     | ||||||
|  |   	  coalescedWrite(mat_v[sU](mu)(), sum); | ||||||
|  |   	}); | ||||||
|     } |     } | ||||||
|     PokeIndex<LorentzIndex>(mat, tmp, mu); |  | ||||||
|     return; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    | ||||||
|  |  | ||||||
|  |    | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef GparityWilsonImpl<vComplex , FundamentalRepresentation,CoeffReal> GparityWilsonImplR;  // Real.. whichever prec | typedef GparityWilsonImpl<vComplex , FundamentalRepresentation,CoeffReal> GparityWilsonImplR;  // Real.. whichever prec | ||||||
|   | |||||||
| @@ -69,6 +69,11 @@ public: | |||||||
|     return PeriodicBC::ShiftStaple(Link,mu); |     return PeriodicBC::ShiftStaple(Link,mu); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Same as Cshift for periodic BCs | ||||||
|  |   static inline GaugeLinkField CshiftLink(const GaugeLinkField &Link, int mu, int shift){ | ||||||
|  |     return PeriodicBC::CshiftLink(Link,mu,shift); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   static inline bool isPeriodicGaugeField(void) { return true; } |   static inline bool isPeriodicGaugeField(void) { return true; } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -110,6 +115,11 @@ public: | |||||||
|       return PeriodicBC::CovShiftBackward(Link, mu, field); |       return PeriodicBC::CovShiftBackward(Link, mu, field); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //If mu is a conjugate BC direction | ||||||
|  |   //Out(x) = U^dag_\mu(x-mu)  | x_\mu != 0 | ||||||
|  |   //       = U^T_\mu(L-1)  | x_\mu == 0 | ||||||
|  |   //else | ||||||
|  |   //Out(x) = U^dag_\mu(x-mu mod L) | ||||||
|   static inline GaugeLinkField |   static inline GaugeLinkField | ||||||
|   CovShiftIdentityBackward(const GaugeLinkField &Link, int mu) |   CovShiftIdentityBackward(const GaugeLinkField &Link, int mu) | ||||||
|   { |   { | ||||||
| @@ -129,6 +139,13 @@ public: | |||||||
|       return PeriodicBC::CovShiftIdentityForward(Link,mu); |       return PeriodicBC::CovShiftIdentityForward(Link,mu); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //If mu is a conjugate BC direction | ||||||
|  |   //Out(x) = S_\mu(x+mu)  | x_\mu != L-1 | ||||||
|  |   //       = S*_\mu(x+mu)  | x_\mu == L-1 | ||||||
|  |   //else | ||||||
|  |   //Out(x) = S_\mu(x+mu mod L) | ||||||
|  |   //Note: While this is used for Staples it is also applicable for shifting gauge links or gauge transformation matrices | ||||||
|   static inline GaugeLinkField ShiftStaple(const GaugeLinkField &Link, int mu) |   static inline GaugeLinkField ShiftStaple(const GaugeLinkField &Link, int mu) | ||||||
|   { |   { | ||||||
|     assert(_conjDirs.size() == Nd); |     assert(_conjDirs.size() == Nd); | ||||||
| @@ -138,6 +155,27 @@ public: | |||||||
|       return PeriodicBC::ShiftStaple(Link,mu); |       return PeriodicBC::ShiftStaple(Link,mu); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Boundary-aware C-shift of gauge links / gauge transformation matrices | ||||||
|  |   //For conjugate BC direction | ||||||
|  |   //shift = 1 | ||||||
|  |   //Out(x) = U_\mu(x+\hat\mu)  | x_\mu != L-1 | ||||||
|  |   //       = U*_\mu(0)  | x_\mu == L-1 | ||||||
|  |   //shift = -1 | ||||||
|  |   //Out(x) = U_\mu(x-mu)  | x_\mu != 0 | ||||||
|  |   //       = U*_\mu(L-1)  | x_\mu == 0 | ||||||
|  |   //else | ||||||
|  |   //shift = 1 | ||||||
|  |   //Out(x) = U_\mu(x+\hat\mu mod L) | ||||||
|  |   //shift = -1 | ||||||
|  |   //Out(x) = U_\mu(x-\hat\mu mod L) | ||||||
|  |   static inline GaugeLinkField CshiftLink(const GaugeLinkField &Link, int mu, int shift){ | ||||||
|  |     assert(_conjDirs.size() == Nd); | ||||||
|  |     if(_conjDirs[mu])  | ||||||
|  |       return ConjugateBC::CshiftLink(Link,mu,shift); | ||||||
|  |     else      | ||||||
|  |       return PeriodicBC::CshiftLink(Link,mu,shift); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   static inline void       setDirections(std::vector<int> &conjDirs) { _conjDirs=conjDirs; } |   static inline void       setDirections(std::vector<int> &conjDirs) { _conjDirs=conjDirs; } | ||||||
|   static inline std::vector<int> getDirections(void) { return _conjDirs; } |   static inline std::vector<int> getDirections(void) { return _conjDirs; } | ||||||
|   static inline bool isPeriodicGaugeField(void) { return false; } |   static inline bool isPeriodicGaugeField(void) { return false; } | ||||||
|   | |||||||
| @@ -40,13 +40,66 @@ 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>& ActionCGL, OperatorFunction<FermionField>& ActionCGR,  | ||||||
| 					      OperatorFunction<FermionField>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,  | 					      OperatorFunction<FermionField>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,  | ||||||
| 					      Params& p,  | 					      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>& DerivCGL , OperatorFunction<FermionField>& DerivCGR,  | ||||||
|  | 					      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,16 @@ 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); | ||||||
|  | 	  //Lop.RefreshShiftCoefficients(-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 +223,16 @@ 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]); | ||||||
|  |           //Rop.RefreshShiftCoefficients(-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 +242,119 @@ 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); |         //Lop.RefreshShiftCoefficients(0.0); | ||||||
|         Rop.RefreshShiftCoefficients(-1.0); |         //Rop.RefreshShiftCoefficients(-1.0); | ||||||
|  | 	heatbathRefreshShiftCoefficients(0, 0.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 +378,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 +388,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 +456,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,249 +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; |  | ||||||
|  |  | ||||||
|     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; | ||||||
|  | 	out.MaxIter = in.MaxIter; | ||||||
|     public: | 	out.action_tolerance = out.md_tolerance = in.tolerance; | ||||||
|  | 	out.action_degree = out.md_degree = in.degree; | ||||||
|       OneFlavourEvenOddRatioRationalPseudoFermionAction(FermionOperator<Impl>  &_NumOp,  | 	out.precision = in.precision; | ||||||
| 					    FermionOperator<Impl>  &_DenOp,  | 	out.BoundsCheckFreq = in.BoundsCheckFreq; | ||||||
| 					    Params & p | 	return out; | ||||||
| 					    ) :  |  | ||||||
|       NumOp(_NumOp),  |  | ||||||
|       DenOp(_DenOp),  |  | ||||||
|       PhiOdd (_NumOp.FermionRedBlackGrid()), |  | ||||||
|       PhiEven(_NumOp.FermionRedBlackGrid()), |  | ||||||
|       param(p)  |  | ||||||
|       { |  | ||||||
| 	AlgRemez remez(param.lo,param.hi,param.precision); |  | ||||||
|  |  | ||||||
| 	// MdagM^(+- 1/2) |  | ||||||
| 	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); |  | ||||||
|  |  | ||||||
| 	// 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); |  | ||||||
| 	PowerNegQuarter.Init(remez,param.tolerance,true); |  | ||||||
|       }; |  | ||||||
|  |  | ||||||
|       virtual std::string action_name(){return "OneFlavourEvenOddRatioRationalPseudoFermionAction";} |  | ||||||
|  |  | ||||||
|       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(); |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |     public: | ||||||
|  |       OneFlavourEvenOddRatioRationalPseudoFermionAction(FermionOperator<Impl>  &_NumOp,  | ||||||
|  | 							FermionOperator<Impl>  &_DenOp,  | ||||||
|  | 							const Params & p | ||||||
|  | 							) :  | ||||||
|  | 	GeneralEvenOddRatioRationalPseudoFermionAction<Impl>(_NumOp, _DenOp, transcribe(p)){} | ||||||
|  |  | ||||||
|       virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) { |       virtual std::string action_name(){return "OneFlavourEvenOddRatioRationalPseudoFermionAction";}       | ||||||
|  |  | ||||||
| 	// 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); |  | ||||||
|  |  | ||||||
| 	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 = PhiOdd; |  | ||||||
| 	  HighBoundCheck(MdagM,gauss,param.hi); |  | ||||||
| 	  InverseSqrtBoundsCheck(param.MaxIter,param.tolerance*100,MdagM,gauss,PowerNegHalf); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	//  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  = PowerNegHalf.poles.size(); |  | ||||||
| 	const int n_pv = PowerQuarter.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,PowerQuarter); |  | ||||||
| 	ConjugateGradientMultiShift<FermionField> msCG_M(param.MaxIter,PowerNegHalf); |  | ||||||
|  |  | ||||||
| 	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 = PowerNegHalf.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 = PowerQuarter.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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -83,16 +83,10 @@ NAMESPACE_BEGIN(Grid); | |||||||
| 	return sstream.str(); | 	return sstream.str(); | ||||||
|       }  |       }  | ||||||
|  |  | ||||||
|  |       //Access the fermion field | ||||||
|  |       const FermionField &getPhiOdd() const{ return PhiOdd; } | ||||||
|  |  | ||||||
|       virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) { |       virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) { | ||||||
|  |  | ||||||
|         // P(phi) = e^{- phi^dag Vpc (MpcdagMpc)^-1 Vpcdag phi} |  | ||||||
|         // |  | ||||||
|         // 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. | ||||||
| @@ -100,12 +94,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 | ||||||
|  |         // | ||||||
|  |         // Take phi_o = Vpcdag^{-1} Mpcdag eta_o  ; eta_o = Mpcdag^{-1} Vpcdag Phi | ||||||
|         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); | ||||||
|  |  | ||||||
| @@ -125,8 +129,8 @@ NAMESPACE_BEGIN(Grid); | |||||||
|         DenOp.MooeeDag(etaEven,tmp); |         DenOp.MooeeDag(etaEven,tmp); | ||||||
|         NumOp.MooeeInvDag(tmp,PhiEven); |         NumOp.MooeeInvDag(tmp,PhiEven); | ||||||
|  |  | ||||||
|         PhiOdd =PhiOdd*scale; |         //PhiOdd =PhiOdd*scale; | ||||||
|         PhiEven=PhiEven*scale; |         //PhiEven=PhiEven*scale; | ||||||
|          |          | ||||||
|       }; |       }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								Grid/qcd/gparity/Gparity.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Grid/qcd/gparity/Gparity.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | #ifndef GRID_GPARITY_H_ | ||||||
|  | #define GRID_GPARITY_H_ | ||||||
|  |  | ||||||
|  | #include<Grid/qcd/gparity/GparityFlavour.h> | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										34
									
								
								Grid/qcd/gparity/GparityFlavour.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Grid/qcd/gparity/GparityFlavour.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | #include <Grid/Grid.h> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | const std::array<const GparityFlavour, 3> GparityFlavour::sigma_mu = {{ | ||||||
|  |     GparityFlavour(GparityFlavour::Algebra::SigmaX), | ||||||
|  |     GparityFlavour(GparityFlavour::Algebra::SigmaY), | ||||||
|  |     GparityFlavour(GparityFlavour::Algebra::SigmaZ) | ||||||
|  |     }}; | ||||||
|  |  | ||||||
|  | const std::array<const GparityFlavour, 6> GparityFlavour::sigma_all = {{ | ||||||
|  |   GparityFlavour(GparityFlavour::Algebra::Identity), | ||||||
|  |   GparityFlavour(GparityFlavour::Algebra::SigmaX), | ||||||
|  |   GparityFlavour(GparityFlavour::Algebra::SigmaY), | ||||||
|  |   GparityFlavour(GparityFlavour::Algebra::SigmaZ), | ||||||
|  |   GparityFlavour(GparityFlavour::Algebra::ProjPlus), | ||||||
|  |   GparityFlavour(GparityFlavour::Algebra::ProjMinus) | ||||||
|  | }}; | ||||||
|  |  | ||||||
|  | const std::array<const char *, GparityFlavour::nSigma> GparityFlavour::name = {{ | ||||||
|  |     "SigmaX", | ||||||
|  |     "MinusSigmaX", | ||||||
|  |     "SigmaY", | ||||||
|  |     "MinusSigmaY", | ||||||
|  |     "SigmaZ", | ||||||
|  |     "MinusSigmaZ", | ||||||
|  |     "Identity", | ||||||
|  |     "MinusIdentity", | ||||||
|  |     "ProjPlus", | ||||||
|  |     "MinusProjPlus", | ||||||
|  |     "ProjMinus", | ||||||
|  |     "MinusProjMinus"}}; | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
							
								
								
									
										475
									
								
								Grid/qcd/gparity/GparityFlavour.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								Grid/qcd/gparity/GparityFlavour.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,475 @@ | |||||||
|  | #ifndef GRID_QCD_GPARITY_FLAVOUR_H | ||||||
|  | #define GRID_QCD_GPARITY_FLAVOUR_H | ||||||
|  |  | ||||||
|  | //Support for flavour-matrix operations acting on the G-parity flavour index | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  |  | ||||||
|  | NAMESPACE_BEGIN(Grid); | ||||||
|  |  | ||||||
|  | class GparityFlavour { | ||||||
|  |   public: | ||||||
|  |     GRID_SERIALIZABLE_ENUM(Algebra, undef, | ||||||
|  |                            SigmaX, 0, | ||||||
|  | 			   MinusSigmaX, 1, | ||||||
|  |                            SigmaY, 2, | ||||||
|  | 			   MinusSigmaY, 3, | ||||||
|  |                            SigmaZ, 4, | ||||||
|  | 			   MinusSigmaZ, 5, | ||||||
|  | 			   Identity, 6, | ||||||
|  | 			   MinusIdentity, 7, | ||||||
|  | 			   ProjPlus, 8, | ||||||
|  | 			   MinusProjPlus, 9, | ||||||
|  | 			   ProjMinus, 10, | ||||||
|  | 			   MinusProjMinus, 11 | ||||||
|  | 			   ); | ||||||
|  |     static constexpr unsigned int nSigma = 12; | ||||||
|  |     static const std::array<const char *, nSigma>                name; | ||||||
|  |     static const std::array<const GparityFlavour, 3>             sigma_mu; | ||||||
|  |     static const std::array<const GparityFlavour, 6>            sigma_all; | ||||||
|  |     Algebra                                                      g; | ||||||
|  |   public: | ||||||
|  |   accelerator GparityFlavour(Algebra initg): g(initg) {}   | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // 0 1  x   vector | ||||||
|  | // 1 0 | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourSigmaX(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = rhs(1); | ||||||
|  |   ret(1) = rhs(0); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourSigmaX(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = rhs(1,0); | ||||||
|  |   ret(0,1) = rhs(1,1); | ||||||
|  |   ret(1,0) = rhs(0,0); | ||||||
|  |   ret(1,1) = rhs(0,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourSigmaX(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = rhs(0,1); | ||||||
|  |   ret(0,1) = rhs(0,0); | ||||||
|  |   ret(1,0) = rhs(1,1); | ||||||
|  |   ret(1,1) = rhs(1,0); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourMinusSigmaX(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = -rhs(1); | ||||||
|  |   ret(1) = -rhs(0); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourMinusSigmaX(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -rhs(1,0); | ||||||
|  |   ret(0,1) = -rhs(1,1); | ||||||
|  |   ret(1,0) = -rhs(0,0); | ||||||
|  |   ret(1,1) = -rhs(0,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourMinusSigmaX(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -rhs(0,1); | ||||||
|  |   ret(0,1) = -rhs(0,0); | ||||||
|  |   ret(1,0) = -rhs(1,1); | ||||||
|  |   ret(1,1) = -rhs(1,0); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // 0 -i  x   vector | ||||||
|  | // i 0 | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourSigmaY(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = timesMinusI(rhs(1)); | ||||||
|  |   ret(1) = timesI(rhs(0)); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourSigmaY(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = timesMinusI(rhs(1,0)); | ||||||
|  |   ret(0,1) = timesMinusI(rhs(1,1)); | ||||||
|  |   ret(1,0) = timesI(rhs(0,0)); | ||||||
|  |   ret(1,1) = timesI(rhs(0,1)); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourSigmaY(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = timesI(rhs(0,1)); | ||||||
|  |   ret(0,1) = timesMinusI(rhs(0,0)); | ||||||
|  |   ret(1,0) = timesI(rhs(1,1)); | ||||||
|  |   ret(1,1) = timesMinusI(rhs(1,0)); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourMinusSigmaY(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = timesI(rhs(1)); | ||||||
|  |   ret(1) = timesMinusI(rhs(0)); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourMinusSigmaY(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = timesI(rhs(1,0)); | ||||||
|  |   ret(0,1) = timesI(rhs(1,1)); | ||||||
|  |   ret(1,0) = timesMinusI(rhs(0,0)); | ||||||
|  |   ret(1,1) = timesMinusI(rhs(0,1)); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourMinusSigmaY(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = timesMinusI(rhs(0,1)); | ||||||
|  |   ret(0,1) = timesI(rhs(0,0)); | ||||||
|  |   ret(1,0) = timesMinusI(rhs(1,1)); | ||||||
|  |   ret(1,1) = timesI(rhs(1,0)); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // 1 0  x   vector | ||||||
|  | // 0 -1 | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourSigmaZ(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = rhs(0); | ||||||
|  |   ret(1) = -rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourSigmaZ(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = rhs(0,0); | ||||||
|  |   ret(0,1) = rhs(0,1); | ||||||
|  |   ret(1,0) = -rhs(1,0); | ||||||
|  |   ret(1,1) = -rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourSigmaZ(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = rhs(0,0); | ||||||
|  |   ret(0,1) = -rhs(0,1); | ||||||
|  |   ret(1,0) = rhs(1,0); | ||||||
|  |   ret(1,1) = -rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourMinusSigmaZ(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = -rhs(0); | ||||||
|  |   ret(1) = rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourMinusSigmaZ(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -rhs(0,0); | ||||||
|  |   ret(0,1) = -rhs(0,1); | ||||||
|  |   ret(1,0) = rhs(1,0); | ||||||
|  |   ret(1,1) = rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourMinusSigmaZ(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -rhs(0,0); | ||||||
|  |   ret(0,1) = rhs(0,1); | ||||||
|  |   ret(1,0) = -rhs(1,0); | ||||||
|  |   ret(1,1) = rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourIdentity(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = rhs(0); | ||||||
|  |   ret(1) = rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourIdentity(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = rhs(0,0); | ||||||
|  |   ret(0,1) = rhs(0,1); | ||||||
|  |   ret(1,0) = rhs(1,0); | ||||||
|  |   ret(1,1) = rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourIdentity(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = rhs(0,0); | ||||||
|  |   ret(0,1) = rhs(0,1); | ||||||
|  |   ret(1,0) = rhs(1,0); | ||||||
|  |   ret(1,1) = rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourMinusIdentity(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = -rhs(0); | ||||||
|  |   ret(1) = -rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourMinusIdentity(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -rhs(0,0); | ||||||
|  |   ret(0,1) = -rhs(0,1); | ||||||
|  |   ret(1,0) = -rhs(1,0); | ||||||
|  |   ret(1,1) = -rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourMinusIdentity(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -rhs(0,0); | ||||||
|  |   ret(0,1) = -rhs(0,1); | ||||||
|  |   ret(1,0) = -rhs(1,0); | ||||||
|  |   ret(1,1) = -rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //G-parity flavour projection 1/2(1+\sigma_2) | ||||||
|  | //1 -i | ||||||
|  | //i  1 | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourProjPlus(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = 0.5*rhs(0) + 0.5*timesMinusI(rhs(1)); | ||||||
|  |   ret(1) = 0.5*timesI(rhs(0)) + 0.5*rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourProjPlus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = 0.5*rhs(0,0) + 0.5*timesMinusI(rhs(1,0)); | ||||||
|  |   ret(0,1) = 0.5*rhs(0,1) + 0.5*timesMinusI(rhs(1,1)); | ||||||
|  |   ret(1,0) = 0.5*timesI(rhs(0,0)) + 0.5*rhs(1,0); | ||||||
|  |   ret(1,1) = 0.5*timesI(rhs(0,1)) + 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourProjPlus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = 0.5*rhs(0,0) + 0.5*timesI(rhs(0,1)); | ||||||
|  |   ret(0,1) = 0.5*timesMinusI(rhs(0,0)) + 0.5*rhs(0,1); | ||||||
|  |   ret(1,0) = 0.5*rhs(1,0) + 0.5*timesI(rhs(1,1)); | ||||||
|  |   ret(1,1) = 0.5*timesMinusI(rhs(1,0)) + 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourMinusProjPlus(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = -0.5*rhs(0) + 0.5*timesI(rhs(1)); | ||||||
|  |   ret(1) = 0.5*timesMinusI(rhs(0)) - 0.5*rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourMinusProjPlus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -0.5*rhs(0,0) + 0.5*timesI(rhs(1,0)); | ||||||
|  |   ret(0,1) = -0.5*rhs(0,1) + 0.5*timesI(rhs(1,1)); | ||||||
|  |   ret(1,0) = 0.5*timesMinusI(rhs(0,0)) - 0.5*rhs(1,0); | ||||||
|  |   ret(1,1) = 0.5*timesMinusI(rhs(0,1)) - 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourMinusProjPlus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -0.5*rhs(0,0) + 0.5*timesMinusI(rhs(0,1)); | ||||||
|  |   ret(0,1) = 0.5*timesI(rhs(0,0)) - 0.5*rhs(0,1); | ||||||
|  |   ret(1,0) = -0.5*rhs(1,0) + 0.5*timesMinusI(rhs(1,1)); | ||||||
|  |   ret(1,1) = 0.5*timesI(rhs(1,0)) - 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //G-parity flavour projection 1/2(1-\sigma_2) | ||||||
|  | //1 i | ||||||
|  | //-i  1 | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourProjMinus(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = 0.5*rhs(0) + 0.5*timesI(rhs(1)); | ||||||
|  |   ret(1) = 0.5*timesMinusI(rhs(0)) + 0.5*rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourProjMinus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = 0.5*rhs(0,0) + 0.5*timesI(rhs(1,0)); | ||||||
|  |   ret(0,1) = 0.5*rhs(0,1) + 0.5*timesI(rhs(1,1)); | ||||||
|  |   ret(1,0) = 0.5*timesMinusI(rhs(0,0)) + 0.5*rhs(1,0); | ||||||
|  |   ret(1,1) = 0.5*timesMinusI(rhs(0,1)) + 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourProjMinus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = 0.5*rhs(0,0) + 0.5*timesMinusI(rhs(0,1)); | ||||||
|  |   ret(0,1) = 0.5*timesI(rhs(0,0)) + 0.5*rhs(0,1); | ||||||
|  |   ret(1,0) = 0.5*rhs(1,0) + 0.5*timesMinusI(rhs(1,1)); | ||||||
|  |   ret(1,1) = 0.5*timesI(rhs(1,0)) + 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void multFlavourMinusProjMinus(iVector<vtype, Ngp> &ret, const iVector<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0) = -0.5*rhs(0) + 0.5*timesMinusI(rhs(1)); | ||||||
|  |   ret(1) = 0.5*timesI(rhs(0)) - 0.5*rhs(1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void lmultFlavourMinusProjMinus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -0.5*rhs(0,0) + 0.5*timesMinusI(rhs(1,0)); | ||||||
|  |   ret(0,1) = -0.5*rhs(0,1) + 0.5*timesMinusI(rhs(1,1)); | ||||||
|  |   ret(1,0) = 0.5*timesI(rhs(0,0)) - 0.5*rhs(1,0); | ||||||
|  |   ret(1,1) = 0.5*timesI(rhs(0,1)) - 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  | template<class vtype> | ||||||
|  | accelerator_inline void rmultFlavourMinusProjMinus(iMatrix<vtype, Ngp> &ret, const iMatrix<vtype, Ngp> &rhs) | ||||||
|  | { | ||||||
|  |   ret(0,0) = -0.5*rhs(0,0) + 0.5*timesI(rhs(0,1)); | ||||||
|  |   ret(0,1) = 0.5*timesMinusI(rhs(0,0)) - 0.5*rhs(0,1); | ||||||
|  |   ret(1,0) = -0.5*rhs(1,0) + 0.5*timesI(rhs(1,1)); | ||||||
|  |   ret(1,1) = 0.5*timesMinusI(rhs(1,0)) - 0.5*rhs(1,1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class vtype>  | ||||||
|  | accelerator_inline auto operator*(const GparityFlavour &G, const iVector<vtype, Ngp> &arg) | ||||||
|  | ->typename std::enable_if<matchGridTensorIndex<iVector<vtype, Ngp>, GparityFlavourTensorIndex>::value, iVector<vtype, Ngp>>::type | ||||||
|  | { | ||||||
|  |   iVector<vtype, Ngp> ret; | ||||||
|  |  | ||||||
|  |   switch (G.g)  | ||||||
|  |   { | ||||||
|  |   case GparityFlavour::Algebra::SigmaX: | ||||||
|  |     multFlavourSigmaX(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaX: | ||||||
|  |     multFlavourMinusSigmaX(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::SigmaY: | ||||||
|  |     multFlavourSigmaY(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaY: | ||||||
|  |     multFlavourMinusSigmaY(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::SigmaZ: | ||||||
|  |     multFlavourSigmaZ(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaZ: | ||||||
|  |     multFlavourMinusSigmaZ(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::Identity: | ||||||
|  |     multFlavourIdentity(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusIdentity: | ||||||
|  |     multFlavourMinusIdentity(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::ProjPlus: | ||||||
|  |     multFlavourProjPlus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusProjPlus: | ||||||
|  |     multFlavourMinusProjPlus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::ProjMinus: | ||||||
|  |     multFlavourProjMinus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusProjMinus: | ||||||
|  |     multFlavourMinusProjMinus(ret, arg); break; | ||||||
|  |   default: assert(0); | ||||||
|  |   } | ||||||
|  |   | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class vtype>  | ||||||
|  | accelerator_inline auto operator*(const GparityFlavour &G, const iMatrix<vtype, Ngp> &arg) | ||||||
|  | ->typename std::enable_if<matchGridTensorIndex<iMatrix<vtype, Ngp>, GparityFlavourTensorIndex>::value, iMatrix<vtype, Ngp>>::type | ||||||
|  | { | ||||||
|  |   iMatrix<vtype, Ngp> ret; | ||||||
|  |  | ||||||
|  |   switch (G.g)  | ||||||
|  |   { | ||||||
|  |   case GparityFlavour::Algebra::SigmaX: | ||||||
|  |     lmultFlavourSigmaX(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaX: | ||||||
|  |     lmultFlavourMinusSigmaX(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::SigmaY: | ||||||
|  |     lmultFlavourSigmaY(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaY: | ||||||
|  |     lmultFlavourMinusSigmaY(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::SigmaZ: | ||||||
|  |     lmultFlavourSigmaZ(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaZ: | ||||||
|  |     lmultFlavourMinusSigmaZ(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::Identity: | ||||||
|  |     lmultFlavourIdentity(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusIdentity: | ||||||
|  |     lmultFlavourMinusIdentity(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::ProjPlus: | ||||||
|  |     lmultFlavourProjPlus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusProjPlus: | ||||||
|  |     lmultFlavourMinusProjPlus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::ProjMinus: | ||||||
|  |     lmultFlavourProjMinus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusProjMinus: | ||||||
|  |     lmultFlavourMinusProjMinus(ret, arg); break;   | ||||||
|  |   default: assert(0); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class vtype>  | ||||||
|  | accelerator_inline auto operator*(const iMatrix<vtype, Ngp> &arg, const GparityFlavour &G) | ||||||
|  | ->typename std::enable_if<matchGridTensorIndex<iMatrix<vtype, Ngp>, GparityFlavourTensorIndex>::value, iMatrix<vtype, Ngp>>::type | ||||||
|  | { | ||||||
|  |   iMatrix<vtype, Ngp> ret; | ||||||
|  |  | ||||||
|  |   switch (G.g)  | ||||||
|  |   { | ||||||
|  |   case GparityFlavour::Algebra::SigmaX: | ||||||
|  |     rmultFlavourSigmaX(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaX: | ||||||
|  |     rmultFlavourMinusSigmaX(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::SigmaY: | ||||||
|  |     rmultFlavourSigmaY(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaY: | ||||||
|  |     rmultFlavourMinusSigmaY(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::SigmaZ: | ||||||
|  |     rmultFlavourSigmaZ(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusSigmaZ: | ||||||
|  |     rmultFlavourMinusSigmaZ(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::Identity: | ||||||
|  |     rmultFlavourIdentity(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusIdentity: | ||||||
|  |     rmultFlavourMinusIdentity(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::ProjPlus: | ||||||
|  |     rmultFlavourProjPlus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusProjPlus: | ||||||
|  |     rmultFlavourMinusProjPlus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::ProjMinus: | ||||||
|  |     rmultFlavourProjMinus(ret, arg); break; | ||||||
|  |   case GparityFlavour::Algebra::MinusProjMinus: | ||||||
|  |     rmultFlavourMinusProjMinus(ret, arg); break; | ||||||
|  |   default: assert(0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  | #endif // include guard | ||||||
| @@ -129,18 +129,10 @@ public: | |||||||
|     Runner(S); |     Runner(S); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ////////////////////////////////////////////////////////////////// |   //Use the checkpointer to initialize the RNGs and the gauge field, writing the resulting gauge field into U. | ||||||
|  |   //This is called automatically by Run but may be useful elsewhere, e.g. for integrator tuning experiments | ||||||
| private: |   void initializeGaugeFieldAndRNGs(Field &U){ | ||||||
|   template <class SmearingPolicy> |     if(!Resources.haveRNGs()) Resources.AddRNGs(); | ||||||
|   void Runner(SmearingPolicy &Smearing) { |  | ||||||
|     auto UGrid = Resources.GetCartesian(); |  | ||||||
|     Resources.AddRNGs(); |  | ||||||
|     Field U(UGrid); |  | ||||||
|  |  | ||||||
|     // Can move this outside? |  | ||||||
|     typedef IntegratorType<SmearingPolicy> TheIntegrator; |  | ||||||
|     TheIntegrator MDynamics(UGrid, Parameters.MD, TheAction, Smearing); |  | ||||||
|  |  | ||||||
|     if (Parameters.StartingType == "HotStart") { |     if (Parameters.StartingType == "HotStart") { | ||||||
|       // Hot start |       // Hot start | ||||||
| @@ -159,14 +151,40 @@ private: | |||||||
|       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); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |   template <class SmearingPolicy> | ||||||
|  |   void Runner(SmearingPolicy &Smearing) { | ||||||
|  |     auto UGrid = Resources.GetCartesian(); | ||||||
|  |     Field U(UGrid); | ||||||
|  |  | ||||||
|  |     initializeGaugeFieldAndRNGs(U); | ||||||
|  |  | ||||||
|  |     typedef IntegratorType<SmearingPolicy> TheIntegrator; | ||||||
|  |     TheIntegrator MDynamics(UGrid, Parameters.MD, TheAction, Smearing); | ||||||
|  |  | ||||||
|     Smearing.set_Field(U); |     Smearing.set_Field(U); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,21 +115,21 @@ private: | |||||||
|  |  | ||||||
|     random(sRNG, rn_test); |     random(sRNG, rn_test); | ||||||
|  |  | ||||||
|     std::cout << GridLogMessage |     std::cout << GridLogHMC | ||||||
|               << "--------------------------------------------------\n"; |               << "--------------------------------------------------\n"; | ||||||
|     std::cout << GridLogMessage << "exp(-dH) = " << prob |     std::cout << GridLogHMC << "exp(-dH) = " << prob | ||||||
|               << "  Random = " << rn_test << "\n"; |               << "  Random = " << rn_test << "\n"; | ||||||
|     std::cout << GridLogMessage |     std::cout << GridLogHMC | ||||||
|               << "Acc. Probability = " << ((prob < 1.0) ? prob : 1.0) << "\n"; |               << "Acc. Probability = " << ((prob < 1.0) ? prob : 1.0) << "\n"; | ||||||
|  |  | ||||||
|     if ((prob > 1.0) || (rn_test <= prob)) {  // accepted |     if ((prob > 1.0) || (rn_test <= prob)) {  // accepted | ||||||
|       std::cout << GridLogMessage << "Metropolis_test -- ACCEPTED\n"; |       std::cout << GridLogHMC << "Metropolis_test -- ACCEPTED\n"; | ||||||
|       std::cout << GridLogMessage |       std::cout << GridLogHMC | ||||||
|                 << "--------------------------------------------------\n"; |                 << "--------------------------------------------------\n"; | ||||||
|       return true; |       return true; | ||||||
|     } else {  // rejected |     } else {  // rejected | ||||||
|       std::cout << GridLogMessage << "Metropolis_test -- REJECTED\n"; |       std::cout << GridLogHMC << "Metropolis_test -- REJECTED\n"; | ||||||
|       std::cout << GridLogMessage |       std::cout << GridLogHMC | ||||||
|                 << "--------------------------------------------------\n"; |                 << "--------------------------------------------------\n"; | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| @@ -145,7 +145,7 @@ private: | |||||||
|  |  | ||||||
|     std::streamsize current_precision = std::cout.precision(); |     std::streamsize current_precision = std::cout.precision(); | ||||||
|     std::cout.precision(15); |     std::cout.precision(15); | ||||||
|     std::cout << GridLogMessage << "Total H before trajectory = " << H0 << "\n"; |     std::cout << GridLogHMC << "Total H before trajectory = " << H0 << "\n"; | ||||||
|     std::cout.precision(current_precision); |     std::cout.precision(current_precision); | ||||||
|  |  | ||||||
|     TheIntegrator.integrate(U); |     TheIntegrator.integrate(U); | ||||||
| @@ -165,7 +165,7 @@ private: | |||||||
|  |  | ||||||
|  |  | ||||||
|     std::cout.precision(15); |     std::cout.precision(15); | ||||||
|     std::cout << GridLogMessage << "Total H after trajectory  = " << H1 |     std::cout << GridLogHMC << "Total H after trajectory  = " << H1 | ||||||
| 	      << "  dH = " << H1 - H0 << "\n"; | 	      << "  dH = " << H1 - H0 << "\n"; | ||||||
|     std::cout.precision(current_precision); |     std::cout.precision(current_precision); | ||||||
|      |      | ||||||
| @@ -196,9 +196,9 @@ public: | |||||||
|     // Actual updates (evolve a copy Ucopy then copy back eventually) |     // Actual updates (evolve a copy Ucopy then copy back eventually) | ||||||
|     unsigned int FinalTrajectory = Params.Trajectories + Params.NoMetropolisUntil + Params.StartTrajectory; |     unsigned int FinalTrajectory = Params.Trajectories + Params.NoMetropolisUntil + Params.StartTrajectory; | ||||||
|     for (int traj = Params.StartTrajectory; traj < FinalTrajectory; ++traj) { |     for (int traj = Params.StartTrajectory; traj < FinalTrajectory; ++traj) { | ||||||
|       std::cout << GridLogMessage << "-- # Trajectory = " << traj << "\n"; |       std::cout << GridLogHMC << "-- # Trajectory = " << traj << "\n"; | ||||||
|       if (traj < Params.StartTrajectory + Params.NoMetropolisUntil) { |       if (traj < Params.StartTrajectory + Params.NoMetropolisUntil) { | ||||||
|       	std::cout << GridLogMessage << "-- Thermalization" << std::endl; |       	std::cout << GridLogHMC << "-- Thermalization" << std::endl; | ||||||
|       } |       } | ||||||
|        |        | ||||||
|       double t0=usecond(); |       double t0=usecond(); | ||||||
| @@ -207,10 +207,10 @@ public: | |||||||
|       DeltaH = evolve_hmc_step(Ucopy); |       DeltaH = evolve_hmc_step(Ucopy); | ||||||
|       // Metropolis-Hastings test |       // Metropolis-Hastings test | ||||||
|       bool accept = true; |       bool accept = true; | ||||||
|       if (traj >= Params.StartTrajectory + Params.NoMetropolisUntil) { |       if (Params.MetropolisTest && traj >= Params.StartTrajectory + Params.NoMetropolisUntil) { | ||||||
|         accept = metropolis_test(DeltaH); |         accept = metropolis_test(DeltaH); | ||||||
|       } else { |       } else { | ||||||
|       	std::cout << GridLogMessage << "Skipping Metropolis test" << std::endl; |       	std::cout << GridLogHMC << "Skipping Metropolis test" << std::endl; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (accept) |       if (accept) | ||||||
| @@ -219,7 +219,7 @@ public: | |||||||
|       |       | ||||||
|        |        | ||||||
|       double t1=usecond(); |       double t1=usecond(); | ||||||
|       std::cout << GridLogMessage << "Total time for trajectory (s): " << (t1-t0)/1e6 << std::endl; |       std::cout << GridLogHMC << "Total time for trajectory (s): " << (t1-t0)/1e6 << std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|       for (int obs = 0; obs < Observables.size(); obs++) { |       for (int obs = 0; obs < Observables.size(); obs++) { | ||||||
| @@ -228,7 +228,7 @@ public: | |||||||
|       	std::cout << GridLogDebug << "Observables pointer " << Observables[obs] << std::endl; |       	std::cout << GridLogDebug << "Observables pointer " << Observables[obs] << std::endl; | ||||||
|         Observables[obs]->TrajectoryComplete(traj + 1, Ucur, sRNG, pRNG); |         Observables[obs]->TrajectoryComplete(traj + 1, Ucur, sRNG, pRNG); | ||||||
|       } |       } | ||||||
|       std::cout << GridLogMessage << ":::::::::::::::::::::::::::::::::::::::::::" << std::endl; |       std::cout << GridLogHMC << ":::::::::::::::::::::::::::::::::::::::::::" << std::endl; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -227,6 +227,9 @@ public: | |||||||
|   // Random number generators |   // Random number generators | ||||||
|   ////////////////////////////////////////////////////// |   ////////////////////////////////////////////////////// | ||||||
|    |    | ||||||
|  |   //Return true if the RNG objects have been instantiated | ||||||
|  |   bool haveRNGs() const{ return have_RNG; } | ||||||
|  |  | ||||||
|   void AddRNGs(std::string s = "") { |   void AddRNGs(std::string s = "") { | ||||||
|     // Couple the RNGs to the GridModule tagged by s |     // Couple the RNGs to the GridModule tagged by s | ||||||
|     // the default is the first grid registered |     // the default is the first grid registered | ||||||
|   | |||||||
| @@ -136,8 +136,14 @@ protected: | |||||||
|       if (as[level].actions.at(a)->is_smeared) Smearer.smeared_force(force); |       if (as[level].actions.at(a)->is_smeared) Smearer.smeared_force(force); | ||||||
|       force = FieldImplementation::projectForce(force); // Ta for gauge fields |       force = FieldImplementation::projectForce(force); // Ta for gauge fields | ||||||
|       double end_force = usecond(); |       double end_force = usecond(); | ||||||
|       Real force_abs = std::sqrt(norm2(force)/U.Grid()->gSites()); |  | ||||||
|       std::cout << GridLogIntegrator << "["<<level<<"]["<<a<<"] Force average: " << force_abs << std::endl; |       Real force_abs = std::sqrt(norm2(force)/U.Grid()->gSites()); //average per-site norm.  nb. norm2(latt) = \sum_x norm2(latt[x])  | ||||||
|  |       Real impulse_abs = force_abs * ep * HMC_MOMENTUM_DENOMINATOR;     | ||||||
|  |  | ||||||
|  |       Real max_force_abs = std::sqrt(maxLocalNorm2(force)); | ||||||
|  |       Real max_impulse_abs = max_force_abs * ep * HMC_MOMENTUM_DENOMINATOR;     | ||||||
|  |  | ||||||
|  |       std::cout << GridLogIntegrator << "["<<level<<"]["<<a<<"] Force average: " << force_abs << " Max force: " << max_force_abs << " Time step: " << ep << " Impulse average: " << impulse_abs << " Max impulse: " << max_impulse_abs << std::endl; | ||||||
|       Mom -= force * ep* HMC_MOMENTUM_DENOMINATOR;;  |       Mom -= force * ep* HMC_MOMENTUM_DENOMINATOR;;  | ||||||
|       double end_full = usecond(); |       double end_full = usecond(); | ||||||
|       double time_full  = (end_full - start_full) / 1e3; |       double time_full  = (end_full - start_full) / 1e3; | ||||||
| @@ -249,15 +255,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 | ||||||
| @@ -267,6 +277,7 @@ public: | |||||||
|       for (int actionID = 0; actionID < as[level].actions.size(); ++actionID) { |       for (int actionID = 0; actionID < as[level].actions.size(); ++actionID) { | ||||||
|         // get gauge field from the SmearingPolicy and |         // get gauge field from the SmearingPolicy and | ||||||
|         // based on the boolean is_smeared in actionID |         // based on the boolean is_smeared in actionID | ||||||
|  | 	std::cout << GridLogIntegrator << "Refreshing integrator level " << level << " index " << actionID << std::endl; | ||||||
|         Field& Us = Smearer.get_U(as[level].actions.at(actionID)->is_smeared); |         Field& Us = Smearer.get_U(as[level].actions.at(actionID)->is_smeared); | ||||||
|         as[level].actions.at(actionID)->refresh(Us, sRNG, pRNG); |         as[level].actions.at(actionID)->refresh(Us, sRNG, pRNG); | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -99,7 +99,7 @@ public: | |||||||
| 	// using wilson flow by default here | 	// using wilson flow by default here | ||||||
| 	WilsonFlow<PeriodicGimplR> WF(Pars.Smearing.steps, Pars.Smearing.step_size, Pars.Smearing.meas_interval); | 	WilsonFlow<PeriodicGimplR> WF(Pars.Smearing.steps, Pars.Smearing.step_size, Pars.Smearing.meas_interval); | ||||||
| 	WF.smear_adaptive(Usmear, U, Pars.Smearing.maxTau); | 	WF.smear_adaptive(Usmear, U, Pars.Smearing.maxTau); | ||||||
| 	Real T0   = WF.energyDensityPlaquette(Usmear); | 	Real T0   = WF.energyDensityPlaquette(Pars.Smearing.maxTau, Usmear); | ||||||
| 	std::cout << GridLogMessage << std::setprecision(std::numeric_limits<Real>::digits10 + 1) | 	std::cout << GridLogMessage << std::setprecision(std::numeric_limits<Real>::digits10 + 1) | ||||||
| 		  << "T0                : [ " << traj << " ] "<< T0 << std::endl; | 		  << "T0                : [ " << traj << " ] "<< T0 << std::endl; | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ Source file: ./lib/qcd/modules/plaquette.h | |||||||
| Copyright (C) 2017 | Copyright (C) 2017 | ||||||
|  |  | ||||||
| Author: Guido Cossu <guido.cossu@ed.ac.uk> | Author: Guido Cossu <guido.cossu@ed.ac.uk> | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  |  | ||||||
| This program is free software; you can redistribute it and/or modify | 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 | it under the terms of the GNU General Public License as published by | ||||||
| @@ -33,28 +34,44 @@ NAMESPACE_BEGIN(Grid); | |||||||
|  |  | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| class WilsonFlow: public Smear<Gimpl>{ | class WilsonFlow: public Smear<Gimpl>{ | ||||||
|   unsigned int Nstep; | public: | ||||||
|   unsigned int measure_interval; |   //Store generic measurements to take during smearing process using std::function | ||||||
|   mutable RealD epsilon, taus; |   typedef std::function<void(int, RealD, const typename Gimpl::GaugeField &)> FunctionType;  //int: step,  RealD: flow time,  GaugeField : the gauge field | ||||||
|    |    | ||||||
|  | private: | ||||||
|  |   unsigned int Nstep; | ||||||
|  |   RealD epsilon; //for regular smearing this is the time step, for adaptive it is the initial time step | ||||||
|  |   | ||||||
|  |   std::vector< std::pair<int, FunctionType> > functions; //The int maps to the measurement frequency | ||||||
|  |  | ||||||
|   mutable WilsonGaugeAction<Gimpl> SG; |   mutable WilsonGaugeAction<Gimpl> SG; | ||||||
|  |  | ||||||
|   void evolve_step(typename Gimpl::GaugeField&) const; |   //Evolve the gauge field by 1 step and update tau | ||||||
|   void evolve_step_adaptive(typename Gimpl::GaugeField&, RealD); |   void evolve_step(typename Gimpl::GaugeField &U, RealD &tau) const; | ||||||
|   RealD tau(unsigned int t)const {return epsilon*(t+1.0); } |   //Evolve the gauge field by 1 step and update tau and the current time step eps | ||||||
|  |   void evolve_step_adaptive(typename Gimpl::GaugeField&U, RealD &tau, RealD &eps, RealD maxTau) const; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   INHERIT_GIMPL_TYPES(Gimpl) |   INHERIT_GIMPL_TYPES(Gimpl) | ||||||
|  |  | ||||||
|  |   void resetActions(){ functions.clear(); } | ||||||
|  |  | ||||||
|  |   void addMeasurement(int meas_interval, FunctionType meas){ functions.push_back({meas_interval, meas}); } | ||||||
|  |  | ||||||
|  |   //Set the class to perform the default measurements:  | ||||||
|  |   //the plaquette energy density every step | ||||||
|  |   //the plaquette topological charge every 'topq_meas_interval' steps | ||||||
|  |   //and output to stdout | ||||||
|  |   void setDefaultMeasurements(int topq_meas_interval = 1); | ||||||
|  |  | ||||||
|   explicit WilsonFlow(unsigned int Nstep, RealD epsilon, unsigned int interval = 1): |   explicit WilsonFlow(unsigned int Nstep, RealD epsilon, unsigned int interval = 1): | ||||||
|   Nstep(Nstep), |   Nstep(Nstep), | ||||||
|     epsilon(epsilon), |     epsilon(epsilon), | ||||||
|     measure_interval(interval), |  | ||||||
|     SG(WilsonGaugeAction<Gimpl>(3.0)) { |     SG(WilsonGaugeAction<Gimpl>(3.0)) { | ||||||
|     // WilsonGaugeAction with beta 3.0 |     // WilsonGaugeAction with beta 3.0 | ||||||
|     assert(epsilon > 0.0); |     assert(epsilon > 0.0); | ||||||
|     LogMessage(); |     LogMessage(); | ||||||
|  |     setDefaultMeasurements(interval); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void LogMessage() { |   void LogMessage() { | ||||||
| @@ -73,9 +90,29 @@ public: | |||||||
|     // undefined for WilsonFlow |     // undefined for WilsonFlow | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void smear_adaptive(GaugeField&, const GaugeField&, RealD maxTau); |   void smear_adaptive(GaugeField&, const GaugeField&, RealD maxTau) const; | ||||||
|   RealD energyDensityPlaquette(unsigned int step, const GaugeField& U) const; |  | ||||||
|   RealD energyDensityPlaquette(const GaugeField& U) const; |   //Compute t^2 <E(t)> for time t from the plaquette | ||||||
|  |   static RealD energyDensityPlaquette(const RealD t, const GaugeField& U); | ||||||
|  |  | ||||||
|  |   //Compute t^2 <E(t)> for time t from the 1x1 cloverleaf form | ||||||
|  |   //t is the Wilson flow time | ||||||
|  |   static RealD energyDensityCloverleaf(const RealD t, const GaugeField& U); | ||||||
|  |    | ||||||
|  |   //Evolve the gauge field by Nstep steps of epsilon and return the energy density computed every interval steps | ||||||
|  |   //The smeared field is output as V | ||||||
|  |   std::vector<RealD> flowMeasureEnergyDensityPlaquette(GaugeField &V, const GaugeField& U, int measure_interval = 1); | ||||||
|  |  | ||||||
|  |   //Version that does not return the smeared field | ||||||
|  |   std::vector<RealD> flowMeasureEnergyDensityPlaquette(const GaugeField& U, int measure_interval = 1); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Evolve the gauge field by Nstep steps of epsilon and return the Cloverleaf energy density computed every interval steps | ||||||
|  |   //The smeared field is output as V | ||||||
|  |   std::vector<RealD> flowMeasureEnergyDensityCloverleaf(GaugeField &V, const GaugeField& U, int measure_interval = 1); | ||||||
|  |  | ||||||
|  |   //Version that does not return the smeared field | ||||||
|  |   std::vector<RealD> flowMeasureEnergyDensityCloverleaf(const GaugeField& U, int measure_interval = 1); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -83,7 +120,7 @@ public: | |||||||
| // Implementations | // Implementations | ||||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| void WilsonFlow<Gimpl>::evolve_step(typename Gimpl::GaugeField &U) const{ | void WilsonFlow<Gimpl>::evolve_step(typename Gimpl::GaugeField &U, RealD &tau) const{ | ||||||
|   GaugeField Z(U.Grid()); |   GaugeField Z(U.Grid()); | ||||||
|   GaugeField tmp(U.Grid()); |   GaugeField tmp(U.Grid()); | ||||||
|   SG.deriv(U, Z); |   SG.deriv(U, Z); | ||||||
| @@ -99,12 +136,13 @@ void WilsonFlow<Gimpl>::evolve_step(typename Gimpl::GaugeField &U) const{ | |||||||
|   SG.deriv(U, tmp); Z += tmp;                 // 4/3*(17/36*Z0 -8/9*Z1) +Z2 |   SG.deriv(U, tmp); Z += tmp;                 // 4/3*(17/36*Z0 -8/9*Z1) +Z2 | ||||||
|   Z *= 3.0/4.0;                               // Z = 17/36*Z0 -8/9*Z1 +3/4*Z2 |   Z *= 3.0/4.0;                               // Z = 17/36*Z0 -8/9*Z1 +3/4*Z2 | ||||||
|   Gimpl::update_field(Z, U, -2.0*epsilon);    // V(t+e) = exp(ep*Z)*W2 |   Gimpl::update_field(Z, U, -2.0*epsilon);    // V(t+e) = exp(ep*Z)*W2 | ||||||
|  |   tau += epsilon; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| void WilsonFlow<Gimpl>::evolve_step_adaptive(typename Gimpl::GaugeField &U, RealD maxTau) { | void WilsonFlow<Gimpl>::evolve_step_adaptive(typename Gimpl::GaugeField &U, RealD &tau, RealD &eps, RealD maxTau) const{ | ||||||
|   if (maxTau - taus < epsilon){ |   if (maxTau - tau < eps){ | ||||||
|     epsilon = maxTau-taus; |     eps = maxTau-tau; | ||||||
|   } |   } | ||||||
|   //std::cout << GridLogMessage << "Integration epsilon : " << epsilon << std::endl; |   //std::cout << GridLogMessage << "Integration epsilon : " << epsilon << std::endl; | ||||||
|   GaugeField Z(U.Grid()); |   GaugeField Z(U.Grid()); | ||||||
| @@ -114,95 +152,151 @@ void WilsonFlow<Gimpl>::evolve_step_adaptive(typename Gimpl::GaugeField &U, Real | |||||||
|   SG.deriv(U, Z); |   SG.deriv(U, Z); | ||||||
|   Zprime = -Z; |   Zprime = -Z; | ||||||
|   Z *= 0.25;                                  // Z0 = 1/4 * F(U) |   Z *= 0.25;                                  // Z0 = 1/4 * F(U) | ||||||
|   Gimpl::update_field(Z, U, -2.0*epsilon);    // U = W1 = exp(ep*Z0)*W0 |   Gimpl::update_field(Z, U, -2.0*eps);    // U = W1 = exp(ep*Z0)*W0 | ||||||
|  |  | ||||||
|   Z *= -17.0/8.0; |   Z *= -17.0/8.0; | ||||||
|   SG.deriv(U, tmp); Z += tmp;                 // -17/32*Z0 +Z1 |   SG.deriv(U, tmp); Z += tmp;                 // -17/32*Z0 +Z1 | ||||||
|   Zprime += 2.0*tmp; |   Zprime += 2.0*tmp; | ||||||
|   Z *= 8.0/9.0;                               // Z = -17/36*Z0 +8/9*Z1 |   Z *= 8.0/9.0;                               // Z = -17/36*Z0 +8/9*Z1 | ||||||
|   Gimpl::update_field(Z, U, -2.0*epsilon);    // U_= W2 = exp(ep*Z)*W1 |   Gimpl::update_field(Z, U, -2.0*eps);    // U_= W2 = exp(ep*Z)*W1 | ||||||
|      |      | ||||||
|  |  | ||||||
|   Z *= -4.0/3.0; |   Z *= -4.0/3.0; | ||||||
|   SG.deriv(U, tmp); Z += tmp;                 // 4/3*(17/36*Z0 -8/9*Z1) +Z2 |   SG.deriv(U, tmp); Z += tmp;                 // 4/3*(17/36*Z0 -8/9*Z1) +Z2 | ||||||
|   Z *= 3.0/4.0;                               // Z = 17/36*Z0 -8/9*Z1 +3/4*Z2 |   Z *= 3.0/4.0;                               // Z = 17/36*Z0 -8/9*Z1 +3/4*Z2 | ||||||
|   Gimpl::update_field(Z, U, -2.0*epsilon);    // V(t+e) = exp(ep*Z)*W2 |   Gimpl::update_field(Z, U, -2.0*eps);    // V(t+e) = exp(ep*Z)*W2 | ||||||
|  |  | ||||||
|   // Ramos  |   // Ramos  | ||||||
|   Gimpl::update_field(Zprime, Uprime, -2.0*epsilon); // V'(t+e) = exp(ep*Z')*W0 |   Gimpl::update_field(Zprime, Uprime, -2.0*eps); // V'(t+e) = exp(ep*Z')*W0 | ||||||
|   // Compute distance as norm^2 of the difference |   // Compute distance as norm^2 of the difference | ||||||
|   GaugeField diffU = U - Uprime; |   GaugeField diffU = U - Uprime; | ||||||
|   RealD diff = norm2(diffU); |   RealD diff = norm2(diffU); | ||||||
|   // adjust integration step |   // adjust integration step | ||||||
|      |      | ||||||
|   taus += epsilon; |   tau += eps; | ||||||
|   //std::cout << GridLogMessage << "Adjusting integration step with distance: " << diff << std::endl; |   //std::cout << GridLogMessage << "Adjusting integration step with distance: " << diff << std::endl; | ||||||
|      |      | ||||||
|   epsilon = epsilon*0.95*std::pow(1e-4/diff,1./3.); |   eps = eps*0.95*std::pow(1e-4/diff,1./3.); | ||||||
|   //std::cout << GridLogMessage << "New epsilon : " << epsilon << std::endl; |   //std::cout << GridLogMessage << "New epsilon : " << epsilon << std::endl; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| RealD WilsonFlow<Gimpl>::energyDensityPlaquette(unsigned int step, const GaugeField& U) const { | RealD WilsonFlow<Gimpl>::energyDensityPlaquette(const RealD t, const GaugeField& U){ | ||||||
|   RealD td = tau(step); |   static WilsonGaugeAction<Gimpl> SG(3.0); | ||||||
|   return 2.0 * td * td * SG.S(U)/U.Grid()->gSites(); |   return 2.0 * t * t * SG.S(U)/U.Grid()->gSites(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Compute t^2 <E(t)> for time from the 1x1 cloverleaf form | ||||||
|  | template <class Gimpl> | ||||||
|  | RealD WilsonFlow<Gimpl>::energyDensityCloverleaf(const RealD t, const GaugeField& U){ | ||||||
|  |   typedef typename Gimpl::GaugeLinkField GaugeMat; | ||||||
|  |   typedef typename Gimpl::GaugeField GaugeLorentz; | ||||||
|  |  | ||||||
|  |   assert(Nd == 4); | ||||||
|  |   //E = 1/2 tr( F_munu F_munu ) | ||||||
|  |   //However as  F_numu = -F_munu, only need to sum the trace of the squares of the following 6 field strengths: | ||||||
|  |   //F_01 F_02 F_03   F_12 F_13  F_23 | ||||||
|  |   GaugeMat F(U.Grid()); | ||||||
|  |   LatticeComplexD R(U.Grid()); | ||||||
|  |   R = Zero(); | ||||||
|  |    | ||||||
|  |   for(int mu=0;mu<3;mu++){ | ||||||
|  |     for(int nu=mu+1;nu<4;nu++){ | ||||||
|  |       WilsonLoops<Gimpl>::FieldStrength(F, U, mu, nu); | ||||||
|  |       R = R + trace(F*F); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ComplexD out = sum(R); | ||||||
|  |   out = t*t*out / RealD(U.Grid()->gSites()); | ||||||
|  |   return -real(out); //minus sign necessary for +ve energy | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template <class Gimpl> | ||||||
|  | std::vector<RealD> WilsonFlow<Gimpl>::flowMeasureEnergyDensityPlaquette(GaugeField &V, const GaugeField& U, int measure_interval){ | ||||||
|  |   std::vector<RealD> out; | ||||||
|  |   resetActions(); | ||||||
|  |   addMeasurement(measure_interval, [&out](int step, RealD t, const typename Gimpl::GaugeField &U){  | ||||||
|  |       std::cout << GridLogMessage << "[WilsonFlow] Computing plaquette energy density for step " << step << std::endl; | ||||||
|  |       out.push_back( energyDensityPlaquette(t,U) ); | ||||||
|  |     });       | ||||||
|  |   smear(V,U); | ||||||
|  |   return out; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| RealD WilsonFlow<Gimpl>::energyDensityPlaquette(const GaugeField& U) const { | std::vector<RealD> WilsonFlow<Gimpl>::flowMeasureEnergyDensityPlaquette(const GaugeField& U, int measure_interval){ | ||||||
|   return 2.0 * taus * taus * SG.S(U)/U.Grid()->gSites(); |   GaugeField V(U); | ||||||
|  |   return flowMeasureEnergyDensityPlaquette(V,U, measure_interval); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | template <class Gimpl> | ||||||
|  | std::vector<RealD> WilsonFlow<Gimpl>::flowMeasureEnergyDensityCloverleaf(GaugeField &V, const GaugeField& U, int measure_interval){ | ||||||
|  |   std::vector<RealD> out; | ||||||
|  |   resetActions(); | ||||||
|  |   addMeasurement(measure_interval, [&out](int step, RealD t, const typename Gimpl::GaugeField &U){  | ||||||
|  |       std::cout << GridLogMessage << "[WilsonFlow] Computing Cloverleaf energy density for step " << step << std::endl; | ||||||
|  |       out.push_back( energyDensityCloverleaf(t,U) ); | ||||||
|  |     });       | ||||||
|  |   smear(V,U); | ||||||
|  |   return out; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class Gimpl> | ||||||
|  | std::vector<RealD> WilsonFlow<Gimpl>::flowMeasureEnergyDensityCloverleaf(const GaugeField& U, int measure_interval){ | ||||||
|  |   GaugeField V(U); | ||||||
|  |   return flowMeasureEnergyDensityCloverleaf(V,U, measure_interval); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| //#define WF_TIMING  | //#define WF_TIMING  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| void WilsonFlow<Gimpl>::smear(GaugeField& out, const GaugeField& in) const { | void WilsonFlow<Gimpl>::smear(GaugeField& out, const GaugeField& in) const{ | ||||||
|   out = in; |   out = in; | ||||||
|   for (unsigned int step = 1; step <= Nstep; step++) { |   RealD taus = 0.; | ||||||
|  |   for (unsigned int step = 1; step <= Nstep; step++) { //step indicates the number of smearing steps applied at the time of measurement | ||||||
|     auto start = std::chrono::high_resolution_clock::now(); |     auto start = std::chrono::high_resolution_clock::now(); | ||||||
|     evolve_step(out); |     evolve_step(out, taus); | ||||||
|     auto end = std::chrono::high_resolution_clock::now(); |     auto end = std::chrono::high_resolution_clock::now(); | ||||||
|     std::chrono::duration<double> diff = end - start; |     std::chrono::duration<double> diff = end - start; | ||||||
| #ifdef WF_TIMING | #ifdef WF_TIMING | ||||||
|     std::cout << "Time to evolve " << diff.count() << " s\n"; |     std::cout << "Time to evolve " << diff.count() << " s\n"; | ||||||
| #endif | #endif | ||||||
|     std::cout << GridLogMessage << "[WilsonFlow] Energy density (plaq) : " |     //Perform measurements | ||||||
| 		  << step << "  " << tau(step) << "  "  |     for(auto const &meas : functions) | ||||||
| 	      << energyDensityPlaquette(step,out) << std::endl; |       if( step % meas.first == 0 ) meas.second(step,taus,out); | ||||||
|     if( step % measure_interval == 0){ |  | ||||||
|       std::cout << GridLogMessage << "[WilsonFlow] Top. charge           : " |  | ||||||
| 		<< step << "  "  |  | ||||||
| 		<< WilsonLoops<PeriodicGimplR>::TopologicalCharge(out) << std::endl; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| template <class Gimpl> | template <class Gimpl> | ||||||
| void WilsonFlow<Gimpl>::smear_adaptive(GaugeField& out, const GaugeField& in, RealD maxTau){ | void WilsonFlow<Gimpl>::smear_adaptive(GaugeField& out, const GaugeField& in, RealD maxTau) const{ | ||||||
|   out = in; |   out = in; | ||||||
|   taus = epsilon; |   RealD taus = 0.; | ||||||
|  |   RealD eps = epsilon; | ||||||
|   unsigned int step = 0; |   unsigned int step = 0; | ||||||
|   do{ |   do{ | ||||||
|     step++; |     step++; | ||||||
|     //std::cout << GridLogMessage << "Evolution time :"<< taus << std::endl; |     //std::cout << GridLogMessage << "Evolution time :"<< taus << std::endl; | ||||||
|     evolve_step_adaptive(out, maxTau); |     evolve_step_adaptive(out, taus, eps, maxTau); | ||||||
|     std::cout << GridLogMessage << "[WilsonFlow] Energy density (plaq) : " |     //Perform measurements | ||||||
| 		  << step << "  " << taus << "  " |     for(auto const &meas : functions) | ||||||
| 	      << energyDensityPlaquette(out) << std::endl; |       if( step % meas.first == 0 ) meas.second(step,taus,out); | ||||||
|     if( step % measure_interval == 0){ |  | ||||||
|       std::cout << GridLogMessage << "[WilsonFlow] Top. charge           : " |  | ||||||
| 		<< step << "  "  |  | ||||||
| 		<< WilsonLoops<PeriodicGimplR>::TopologicalCharge(out) << std::endl; |  | ||||||
|     } |  | ||||||
|   } while (taus < maxTau); |   } while (taus < maxTau); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | template <class Gimpl> | ||||||
|  | void WilsonFlow<Gimpl>::setDefaultMeasurements(int topq_meas_interval){ | ||||||
|  |   addMeasurement(1, [](int step, RealD t, const typename Gimpl::GaugeField &U){ | ||||||
|  |       std::cout << GridLogMessage << "[WilsonFlow] Energy density (plaq) : "  << step << "  " << t << "  " << energyDensityPlaquette(t,U) << std::endl; | ||||||
|  |     }); | ||||||
|  |   addMeasurement(topq_meas_interval, [](int step, RealD t, const typename Gimpl::GaugeField &U){ | ||||||
|  |       std::cout << GridLogMessage << "[WilsonFlow] Top. charge           : "  << step << "  " << WilsonLoops<Gimpl>::TopologicalCharge(U) << std::endl; | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| NAMESPACE_END(Grid); | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -88,6 +88,12 @@ namespace PeriodicBC { | |||||||
|     return CovShiftBackward(Link,mu,arg); |     return CovShiftBackward(Link,mu,arg); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Boundary-aware C-shift of gauge links / gauge transformation matrices | ||||||
|  |   template<class gauge> Lattice<gauge> | ||||||
|  |   CshiftLink(const Lattice<gauge> &Link, int mu, int shift) | ||||||
|  |   { | ||||||
|  |     return Cshift(Link, mu, shift); | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -158,6 +164,9 @@ namespace ConjugateBC { | |||||||
|     //    std::cout<<"Gparity::CovCshiftBackward mu="<<mu<<std::endl; |     //    std::cout<<"Gparity::CovCshiftBackward mu="<<mu<<std::endl; | ||||||
|     return Cshift(tmp,mu,-1);// moves towards positive mu |     return Cshift(tmp,mu,-1);// moves towards positive mu | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Out(x) = U^dag_\mu(x-mu)  | x_\mu != 0 | ||||||
|  |   //       = U^T_\mu(L-1)  | x_\mu == 0 | ||||||
|   template<class gauge> Lattice<gauge> |   template<class gauge> Lattice<gauge> | ||||||
|   CovShiftIdentityBackward(const Lattice<gauge> &Link, int mu) { |   CovShiftIdentityBackward(const Lattice<gauge> &Link, int mu) { | ||||||
|     GridBase *grid = Link.Grid(); |     GridBase *grid = Link.Grid(); | ||||||
| @@ -176,6 +185,9 @@ namespace ConjugateBC { | |||||||
|     return Link; |     return Link; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Out(x) = S_\mu(x+\hat\mu)  | x_\mu != L-1 | ||||||
|  |   //       = S*_\mu(0)  | x_\mu == L-1 | ||||||
|  |   //Note: While this is used for Staples it is also applicable for shifting gauge links or gauge transformation matrices | ||||||
|   template<class gauge> Lattice<gauge> |   template<class gauge> Lattice<gauge> | ||||||
|   ShiftStaple(const Lattice<gauge> &Link, int mu) |   ShiftStaple(const Lattice<gauge> &Link, int mu) | ||||||
|   { |   { | ||||||
| @@ -208,6 +220,35 @@ namespace ConjugateBC { | |||||||
|     return CovShiftBackward(Link,mu,arg); |     return CovShiftBackward(Link,mu,arg); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //Boundary-aware C-shift of gauge links / gauge transformation matrices | ||||||
|  |   //shift = 1 | ||||||
|  |   //Out(x) = U_\mu(x+\hat\mu)  | x_\mu != L-1 | ||||||
|  |   //       = U*_\mu(0)  | x_\mu == L-1 | ||||||
|  |   //shift = -1 | ||||||
|  |   //Out(x) = U_\mu(x-mu)  | x_\mu != 0 | ||||||
|  |   //       = U*_\mu(L-1)  | x_\mu == 0 | ||||||
|  |   template<class gauge> Lattice<gauge> | ||||||
|  |   CshiftLink(const Lattice<gauge> &Link, int mu, int shift) | ||||||
|  |   { | ||||||
|  |     GridBase *grid = Link.Grid(); | ||||||
|  |     int Lmu = grid->GlobalDimensions()[mu] - 1; | ||||||
|  |  | ||||||
|  |     Lattice<iScalar<vInteger>> coor(grid); | ||||||
|  |     LatticeCoordinate(coor, mu); | ||||||
|  |  | ||||||
|  |     Lattice<gauge> tmp(grid); | ||||||
|  |     if(shift == 1){ | ||||||
|  |       tmp = Cshift(Link, mu, 1); | ||||||
|  |       tmp = where(coor == Lmu, conjugate(tmp), tmp); | ||||||
|  |       return tmp; | ||||||
|  |     }else if(shift == -1){ | ||||||
|  |       tmp = Link; | ||||||
|  |       tmp = where(coor == Lmu, conjugate(tmp), tmp); | ||||||
|  |       return Cshift(tmp, mu, -1); | ||||||
|  |     }else assert(0 && "Invalid shift value"); | ||||||
|  |     return tmp; //shuts up the compiler fussing about the return type | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,27 +40,46 @@ public: | |||||||
|   typedef typename Gimpl::GaugeLinkField GaugeMat; |   typedef typename Gimpl::GaugeLinkField GaugeMat; | ||||||
|   typedef typename Gimpl::GaugeField GaugeLorentz; |   typedef typename Gimpl::GaugeField GaugeLorentz; | ||||||
|  |  | ||||||
|   static void GaugeLinkToLieAlgebraField(const std::vector<GaugeMat> &U,std::vector<GaugeMat> &A) { |   //A_\mu(x) = -i Ta(U_\mu(x) )   where Ta(U) = 1/2( U - U^dag ) - 1/2N tr(U - U^dag)  is the traceless antihermitian part. This is an O(A^3) approximation to the logarithm of U | ||||||
|     for(int mu=0;mu<Nd;mu++){ |   static void GaugeLinkToLieAlgebraField(const GaugeMat &U, GaugeMat &A) { | ||||||
|       Complex cmi(0.0,-1.0); |     Complex cmi(0.0,-1.0); | ||||||
|       A[mu] = Ta(U[mu]) * cmi; |     A = Ta(U) * cmi; | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|   static void DmuAmu(const std::vector<GaugeMat> &A,GaugeMat &dmuAmu,int orthog) { |    | ||||||
|  |   //The derivative of the Lie algebra field | ||||||
|  |   static void DmuAmu(const std::vector<GaugeMat> &U, GaugeMat &dmuAmu,int orthog) { | ||||||
|  |     GridBase* grid = U[0].Grid(); | ||||||
|  |     GaugeMat Ax(grid); | ||||||
|  |     GaugeMat Axm1(grid); | ||||||
|  |     GaugeMat Utmp(grid); | ||||||
|  |  | ||||||
|     dmuAmu=Zero(); |     dmuAmu=Zero(); | ||||||
|     for(int mu=0;mu<Nd;mu++){ |     for(int mu=0;mu<Nd;mu++){ | ||||||
|       if ( mu != orthog ) { |       if ( mu != orthog ) { | ||||||
| 	dmuAmu = dmuAmu + A[mu] - Cshift(A[mu],mu,-1); | 	//Rather than define functionality to work out how the BCs apply to A_\mu we simply use the BC-aware Cshift to the gauge links and compute A_\mu(x) and A_\mu(x-1) separately | ||||||
|  | 	//Ax = A_\mu(x) | ||||||
|  | 	GaugeLinkToLieAlgebraField(U[mu], Ax); | ||||||
|  | 	 | ||||||
|  | 	//Axm1 = A_\mu(x_\mu-1) | ||||||
|  | 	Utmp = Gimpl::CshiftLink(U[mu], mu, -1); | ||||||
|  | 	GaugeLinkToLieAlgebraField(Utmp, Axm1); | ||||||
|  | 	 | ||||||
|  | 	//Derivative | ||||||
|  | 	dmuAmu = dmuAmu + Ax - Axm1; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }   |   }   | ||||||
|  |  | ||||||
|   static void SteepestDescentGaugeFix(GaugeLorentz &Umu,Real & alpha,int maxiter,Real Omega_tol, Real Phi_tol,bool Fourier=false,int orthog=-1) { |   //Fix the gauge field Umu | ||||||
|  |   //0 < alpha < 1 is related to the step size, cf https://arxiv.org/pdf/1405.5812.pdf | ||||||
|  |   static void SteepestDescentGaugeFix(GaugeLorentz &Umu, Real alpha,int maxiter,Real Omega_tol, Real Phi_tol,bool Fourier=false,int orthog=-1) { | ||||||
|     GridBase *grid = Umu.Grid(); |     GridBase *grid = Umu.Grid(); | ||||||
|     GaugeMat xform(grid); |     GaugeMat xform(grid); | ||||||
|     SteepestDescentGaugeFix(Umu,xform,alpha,maxiter,Omega_tol,Phi_tol,Fourier,orthog); |     SteepestDescentGaugeFix(Umu,xform,alpha,maxiter,Omega_tol,Phi_tol,Fourier,orthog); | ||||||
|   } |   } | ||||||
|   static void SteepestDescentGaugeFix(GaugeLorentz &Umu,GaugeMat &xform,Real & alpha,int maxiter,Real Omega_tol, Real Phi_tol,bool Fourier=false,int orthog=-1) { |  | ||||||
|  |   //Fix the gauge field Umu and also return the gauge transformation from the original gauge field, xform | ||||||
|  |   static void SteepestDescentGaugeFix(GaugeLorentz &Umu,GaugeMat &xform, Real alpha,int maxiter,Real Omega_tol, Real Phi_tol,bool Fourier=false,int orthog=-1) { | ||||||
|  |  | ||||||
|     GridBase *grid = Umu.Grid(); |     GridBase *grid = Umu.Grid(); | ||||||
|  |  | ||||||
| @@ -122,27 +141,24 @@ public: | |||||||
|  |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |     assert(0 && "Gauge fixing did not converge within the specified number of iterations"); | ||||||
|   }; |   }; | ||||||
|   static Real SteepestDescentStep(std::vector<GaugeMat> &U,GaugeMat &xform,Real & alpha, GaugeMat & dmuAmu,int orthog) { |   static Real SteepestDescentStep(std::vector<GaugeMat> &U,GaugeMat &xform, Real alpha, GaugeMat & dmuAmu,int orthog) { | ||||||
|     GridBase *grid = U[0].Grid(); |     GridBase *grid = U[0].Grid(); | ||||||
|  |  | ||||||
|     std::vector<GaugeMat> A(Nd,grid); |  | ||||||
|     GaugeMat g(grid); |     GaugeMat g(grid); | ||||||
|  |     ExpiAlphaDmuAmu(U,g,alpha,dmuAmu,orthog); | ||||||
|     GaugeLinkToLieAlgebraField(U,A); |  | ||||||
|     ExpiAlphaDmuAmu(A,g,alpha,dmuAmu,orthog); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     Real vol = grid->gSites(); |     Real vol = grid->gSites(); | ||||||
|     Real trG = TensorRemove(sum(trace(g))).real()/vol/Nc; |     Real trG = TensorRemove(sum(trace(g))).real()/vol/Nc; | ||||||
|  |  | ||||||
|     xform = g*xform ; |     xform = g*xform ; | ||||||
|     SU<Nc>::GaugeTransform(U,g); |     SU<Nc>::GaugeTransform<Gimpl>(U,g); | ||||||
|  |  | ||||||
|     return trG; |     return trG; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static Real FourierAccelSteepestDescentStep(std::vector<GaugeMat> &U,GaugeMat &xform,Real & alpha, GaugeMat & dmuAmu,int orthog) { |   static Real FourierAccelSteepestDescentStep(std::vector<GaugeMat> &U,GaugeMat &xform, Real alpha, GaugeMat & dmuAmu,int orthog) { | ||||||
|  |  | ||||||
|     GridBase *grid = U[0].Grid(); |     GridBase *grid = U[0].Grid(); | ||||||
|  |  | ||||||
| @@ -157,11 +173,7 @@ public: | |||||||
|  |  | ||||||
|     GaugeMat g(grid); |     GaugeMat g(grid); | ||||||
|     GaugeMat dmuAmu_p(grid); |     GaugeMat dmuAmu_p(grid); | ||||||
|     std::vector<GaugeMat> A(Nd,grid); |     DmuAmu(U,dmuAmu,orthog); | ||||||
|  |  | ||||||
|     GaugeLinkToLieAlgebraField(U,A); |  | ||||||
|  |  | ||||||
|     DmuAmu(A,dmuAmu,orthog); |  | ||||||
|  |  | ||||||
|     std::vector<int> mask(Nd,1); |     std::vector<int> mask(Nd,1); | ||||||
|     for(int mu=0;mu<Nd;mu++) if (mu==orthog) mask[mu]=0; |     for(int mu=0;mu<Nd;mu++) if (mu==orthog) mask[mu]=0; | ||||||
| @@ -205,16 +217,16 @@ public: | |||||||
|     Real trG = TensorRemove(sum(trace(g))).real()/vol/Nc; |     Real trG = TensorRemove(sum(trace(g))).real()/vol/Nc; | ||||||
|  |  | ||||||
|     xform = g*xform ; |     xform = g*xform ; | ||||||
|     SU<Nc>::GaugeTransform(U,g); |     SU<Nc>::GaugeTransform<Gimpl>(U,g); | ||||||
|  |  | ||||||
|     return trG; |     return trG; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static void ExpiAlphaDmuAmu(const std::vector<GaugeMat> &A,GaugeMat &g,Real & alpha, GaugeMat &dmuAmu,int orthog) { |   static void ExpiAlphaDmuAmu(const std::vector<GaugeMat> &U,GaugeMat &g, Real alpha, GaugeMat &dmuAmu,int orthog) { | ||||||
|     GridBase *grid = g.Grid(); |     GridBase *grid = g.Grid(); | ||||||
|     Complex cialpha(0.0,-alpha); |     Complex cialpha(0.0,-alpha); | ||||||
|     GaugeMat ciadmam(grid); |     GaugeMat ciadmam(grid); | ||||||
|     DmuAmu(A,dmuAmu,orthog); |     DmuAmu(U,dmuAmu,orthog); | ||||||
|     ciadmam = dmuAmu*cialpha; |     ciadmam = dmuAmu*cialpha; | ||||||
|     SU<Nc>::taExp(ciadmam,g); |     SU<Nc>::taExp(ciadmam,g); | ||||||
|   }   |   }   | ||||||
|   | |||||||
| @@ -694,32 +694,32 @@ public: | |||||||
|  * Adjoint rep gauge xform |  * Adjoint rep gauge xform | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|   template<typename GaugeField,typename GaugeMat> |   template<typename Gimpl> | ||||||
|   static void GaugeTransform( GaugeField &Umu, GaugeMat &g){ |   static void GaugeTransform(typename Gimpl::GaugeField &Umu, typename Gimpl::GaugeLinkField &g){ | ||||||
|     GridBase *grid = Umu.Grid(); |     GridBase *grid = Umu.Grid(); | ||||||
|     conformable(grid,g.Grid()); |     conformable(grid,g.Grid()); | ||||||
|  |  | ||||||
|     GaugeMat U(grid); |     typename Gimpl::GaugeLinkField U(grid); | ||||||
|     GaugeMat ag(grid); ag = adj(g); |     typename Gimpl::GaugeLinkField ag(grid); ag = adj(g); | ||||||
|  |  | ||||||
|     for(int mu=0;mu<Nd;mu++){ |     for(int mu=0;mu<Nd;mu++){ | ||||||
|       U= PeekIndex<LorentzIndex>(Umu,mu); |       U= PeekIndex<LorentzIndex>(Umu,mu); | ||||||
|       U = g*U*Cshift(ag, mu, 1); |       U = g*U*Gimpl::CshiftLink(ag, mu, 1); //BC-aware | ||||||
|       PokeIndex<LorentzIndex>(Umu,U,mu); |       PokeIndex<LorentzIndex>(Umu,U,mu); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   template<typename GaugeMat> |   template<typename Gimpl> | ||||||
|   static void GaugeTransform( std::vector<GaugeMat> &U, GaugeMat &g){ |   static void GaugeTransform( std::vector<typename Gimpl::GaugeLinkField> &U, typename Gimpl::GaugeLinkField &g){ | ||||||
|     GridBase *grid = g.Grid(); |     GridBase *grid = g.Grid(); | ||||||
|     GaugeMat ag(grid); ag = adj(g); |     typename Gimpl::GaugeLinkField ag(grid); ag = adj(g); | ||||||
|     for(int mu=0;mu<Nd;mu++){ |     for(int mu=0;mu<Nd;mu++){ | ||||||
|       U[mu] = g*U[mu]*Cshift(ag, mu, 1); |       U[mu] = g*U[mu]*Gimpl::CshiftLink(ag, mu, 1); //BC-aware | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   template<typename GaugeField,typename GaugeMat> |   template<typename Gimpl> | ||||||
|   static void RandomGaugeTransform(GridParallelRNG &pRNG, GaugeField &Umu, GaugeMat &g){ |   static void RandomGaugeTransform(GridParallelRNG &pRNG, typename Gimpl::GaugeField &Umu, typename Gimpl::GaugeLinkField &g){ | ||||||
|     LieRandomize(pRNG,g,1.0); |     LieRandomize(pRNG,g,1.0); | ||||||
|     GaugeTransform(Umu,g); |     GaugeTransform<Gimpl>(Umu,g); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Projects the algebra components a lattice matrix (of dimension ncol*ncol -1 ) |   // Projects the algebra components a lattice matrix (of dimension ncol*ncol -1 ) | ||||||
|   | |||||||
| @@ -125,6 +125,56 @@ public: | |||||||
|     return sumplaq / vol / faces / Nc; // Nd , Nc dependent... FIXME |     return sumplaq / vol / faces / Nc; // Nd , Nc dependent... FIXME | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   ////////////////////////////////////////////////// | ||||||
|  |   // sum over all spatial planes of plaquette | ||||||
|  |   ////////////////////////////////////////////////// | ||||||
|  |   static void siteSpatialPlaquette(ComplexField &Plaq, | ||||||
|  |                             const std::vector<GaugeMat> &U) { | ||||||
|  |     ComplexField sitePlaq(U[0].Grid()); | ||||||
|  |     Plaq = Zero(); | ||||||
|  |     for (int mu = 1; mu < Nd-1; mu++) { | ||||||
|  |       for (int nu = 0; nu < mu; nu++) { | ||||||
|  |         traceDirPlaquette(sitePlaq, U, mu, nu); | ||||||
|  |         Plaq = Plaq + sitePlaq; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // sum over all x,y,z and over all spatial planes of plaquette | ||||||
|  |   ////////////////////////////////////////////////// | ||||||
|  |   static std::vector<RealD> timesliceSumSpatialPlaquette(const GaugeLorentz &Umu) { | ||||||
|  |     std::vector<GaugeMat> U(Nd, Umu.Grid()); | ||||||
|  |     // inefficient here | ||||||
|  |     for (int mu = 0; mu < Nd; mu++) { | ||||||
|  |       U[mu] = PeekIndex<LorentzIndex>(Umu, mu); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ComplexField Plaq(Umu.Grid()); | ||||||
|  |  | ||||||
|  |     siteSpatialPlaquette(Plaq, U); | ||||||
|  |     typedef typename ComplexField::scalar_object sobj; | ||||||
|  |     std::vector<sobj> Tq; | ||||||
|  |     sliceSum(Plaq, Tq, Nd-1); | ||||||
|  |  | ||||||
|  |     std::vector<Real> out(Tq.size()); | ||||||
|  |     for(int t=0;t<Tq.size();t++) out[t] = TensorRemove(Tq[t]).real(); | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   ////////////////////////////////////////////////// | ||||||
|  |   // average over all x,y,z and over all spatial planes of plaquette | ||||||
|  |   ////////////////////////////////////////////////// | ||||||
|  |   static std::vector<RealD> timesliceAvgSpatialPlaquette(const GaugeLorentz &Umu) { | ||||||
|  |     std::vector<RealD> sumplaq = timesliceSumSpatialPlaquette(Umu); | ||||||
|  |     int Lt = Umu.Grid()->FullDimensions()[Nd-1]; | ||||||
|  |     assert(sumplaq.size() == Lt); | ||||||
|  |     double vol = Umu.Grid()->gSites() / Lt; | ||||||
|  |     double faces = (1.0 * (Nd - 1)* (Nd - 2)) / 2.0; | ||||||
|  |     for(int t=0;t<Lt;t++) | ||||||
|  |       sumplaq[t] = sumplaq[t] / vol / faces / Nc; // Nd , Nc dependent... FIXME | ||||||
|  |     return sumplaq; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   ////////////////////////////////////////////////// |   ////////////////////////////////////////////////// | ||||||
|   // average over all x,y,z the temporal loop |   // average over all x,y,z the temporal loop | ||||||
| @@ -363,11 +413,11 @@ public: | |||||||
|     GaugeMat u = PeekIndex<LorentzIndex>(Umu, mu);  // some redundant copies |     GaugeMat u = PeekIndex<LorentzIndex>(Umu, mu);  // some redundant copies | ||||||
|     GaugeMat vu = v*u; |     GaugeMat vu = v*u; | ||||||
|       //FS = 0.25*Ta(u*v + Cshift(vu, mu, -1)); |       //FS = 0.25*Ta(u*v + Cshift(vu, mu, -1)); | ||||||
|       FS = (u*v + Cshift(vu, mu, -1)); |       FS = (u*v + Gimpl::CshiftLink(vu, mu, -1)); | ||||||
|       FS = 0.125*(FS - adj(FS)); |       FS = 0.125*(FS - adj(FS)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static Real TopologicalCharge(GaugeLorentz &U){ |   static Real TopologicalCharge(const GaugeLorentz &U){ | ||||||
|     // 4d topological charge |     // 4d topological charge | ||||||
|     assert(Nd==4); |     assert(Nd==4); | ||||||
|     // Bx = -iF(y,z), By = -iF(z,y), Bz = -iF(x,y) |     // Bx = -iF(y,z), By = -iF(z,y), Bz = -iF(x,y) | ||||||
| @@ -390,6 +440,203 @@ public: | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Clover-leaf Wilson loop combination for arbitrary mu-extent M and nu extent N,  mu >= nu | ||||||
|  |   //cf  https://arxiv.org/pdf/hep-lat/9701012.pdf Eq 7  for 1x2 Wilson loop     | ||||||
|  |   //Clockwise ordering | ||||||
|  |   static void CloverleafMxN(GaugeMat &FS, const GaugeMat &Umu, const GaugeMat &Unu, int mu, int nu, int M, int N){   | ||||||
|  | #define Fmu(A) Gimpl::CovShiftForward(Umu, mu, A) | ||||||
|  | #define Bmu(A) Gimpl::CovShiftBackward(Umu, mu, A) | ||||||
|  | #define Fnu(A) Gimpl::CovShiftForward(Unu, nu, A) | ||||||
|  | #define Bnu(A) Gimpl::CovShiftBackward(Unu, nu, A) | ||||||
|  | #define FmuI Gimpl::CovShiftIdentityForward(Umu, mu) | ||||||
|  | #define BmuI Gimpl::CovShiftIdentityBackward(Umu, mu) | ||||||
|  | #define FnuI Gimpl::CovShiftIdentityForward(Unu, nu) | ||||||
|  | #define BnuI Gimpl::CovShiftIdentityBackward(Unu, nu) | ||||||
|  |  | ||||||
|  |     //Upper right loop | ||||||
|  |     GaugeMat tmp = BmuI; | ||||||
|  |     for(int i=1;i<M;i++) | ||||||
|  |       tmp = Bmu(tmp); | ||||||
|  |     for(int j=0;j<N;j++) | ||||||
|  |       tmp = Bnu(tmp); | ||||||
|  |     for(int i=0;i<M;i++) | ||||||
|  |       tmp = Fmu(tmp); | ||||||
|  |     for(int j=0;j<N;j++) | ||||||
|  |       tmp = Fnu(tmp); | ||||||
|  |        | ||||||
|  |     FS = tmp; | ||||||
|  |  | ||||||
|  |     //Upper left loop | ||||||
|  |     tmp = BnuI; | ||||||
|  |     for(int j=1;j<N;j++) | ||||||
|  |       tmp = Bnu(tmp); | ||||||
|  |     for(int i=0;i<M;i++) | ||||||
|  |       tmp = Fmu(tmp); | ||||||
|  |     for(int j=0;j<N;j++) | ||||||
|  |       tmp = Fnu(tmp); | ||||||
|  |     for(int i=0;i<M;i++) | ||||||
|  |       tmp = Bmu(tmp); | ||||||
|  |        | ||||||
|  |     FS = FS + tmp; | ||||||
|  |  | ||||||
|  |     //Lower right loop | ||||||
|  |     tmp = FnuI; | ||||||
|  |     for(int j=1;j<N;j++) | ||||||
|  |       tmp = Fnu(tmp); | ||||||
|  |     for(int i=0;i<M;i++) | ||||||
|  |       tmp = Bmu(tmp); | ||||||
|  |     for(int j=0;j<N;j++) | ||||||
|  |       tmp = Bnu(tmp); | ||||||
|  |     for(int i=0;i<M;i++) | ||||||
|  |       tmp = Fmu(tmp); | ||||||
|  |        | ||||||
|  |     FS = FS + tmp; | ||||||
|  |  | ||||||
|  |     //Lower left loop | ||||||
|  |     tmp = FmuI; | ||||||
|  |     for(int i=1;i<M;i++) | ||||||
|  |       tmp = Fmu(tmp); | ||||||
|  |     for(int j=0;j<N;j++) | ||||||
|  |       tmp = Fnu(tmp); | ||||||
|  |     for(int i=0;i<M;i++) | ||||||
|  |       tmp = Bmu(tmp); | ||||||
|  |     for(int j=0;j<N;j++) | ||||||
|  |       tmp = Bnu(tmp); | ||||||
|  |  | ||||||
|  |     FS = FS + tmp; | ||||||
|  |  | ||||||
|  | #undef Fmu | ||||||
|  | #undef Bmu | ||||||
|  | #undef Fnu | ||||||
|  | #undef Bnu | ||||||
|  | #undef FmuI | ||||||
|  | #undef BmuI | ||||||
|  | #undef FnuI | ||||||
|  | #undef BnuI | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Field strength from MxN Wilson loop | ||||||
|  |   //Note F_numu = - F_munu | ||||||
|  |   static void FieldStrengthMxN(GaugeMat &FS, const GaugeLorentz &U, int mu, int nu, int M, int N){   | ||||||
|  |     GaugeMat Umu = PeekIndex<LorentzIndex>(U, mu); | ||||||
|  |     GaugeMat Unu = PeekIndex<LorentzIndex>(U, nu); | ||||||
|  |     if(M == N){ | ||||||
|  |       GaugeMat F(Umu.Grid()); | ||||||
|  |       CloverleafMxN(F, Umu, Unu, mu, nu, M, N); | ||||||
|  |       FS = 0.125 * ( F - adj(F) ); | ||||||
|  |     }else{ | ||||||
|  |       //Average over both orientations | ||||||
|  |       GaugeMat horizontal(Umu.Grid()), vertical(Umu.Grid()); | ||||||
|  |       CloverleafMxN(horizontal, Umu, Unu, mu, nu, M, N); | ||||||
|  |       CloverleafMxN(vertical, Umu, Unu, mu, nu, N, M); | ||||||
|  |       FS = 0.0625 * ( horizontal - adj(horizontal) + vertical - adj(vertical) ); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Topological charge contribution from MxN Wilson loops | ||||||
|  |   //cf  https://arxiv.org/pdf/hep-lat/9701012.pdf  Eq 6 | ||||||
|  |   //output is the charge by timeslice: sum over timeslices to obtain the total | ||||||
|  |   static std::vector<Real> TimesliceTopologicalChargeMxN(const GaugeLorentz &U, int M, int N){ | ||||||
|  |     assert(Nd == 4); | ||||||
|  |     std::vector<std::vector<GaugeMat*> > F(Nd,std::vector<GaugeMat*>(Nd,nullptr)); | ||||||
|  |     //Note F_numu = - F_munu | ||||||
|  |     //hence we only need to loop over mu,nu,rho,sigma that aren't related by permuting mu,nu  or rho,sigma | ||||||
|  |     //Use nu > mu | ||||||
|  |     for(int mu=0;mu<Nd-1;mu++){ | ||||||
|  |       for(int nu=mu+1; nu<Nd; nu++){ | ||||||
|  | 	F[mu][nu] = new GaugeMat(U.Grid()); | ||||||
|  | 	FieldStrengthMxN(*F[mu][nu], U, mu, nu, M, N); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     Real coeff = -1./(32 * M_PI*M_PI * M*M * N*N); //overall sign to match CPS and Grid conventions, possibly related to time direction = 3 vs 0 | ||||||
|  |  | ||||||
|  |     static const int combs[3][4] = { {0,1,2,3}, {0,2,1,3}, {0,3,1,2} }; | ||||||
|  |     static const int signs[3] = { 1, -1, 1 }; //epsilon_{mu nu rho sigma} | ||||||
|  |  | ||||||
|  |     ComplexField fsum(U.Grid()); | ||||||
|  |     fsum = Zero(); | ||||||
|  |     for(int c=0;c<3;c++){ | ||||||
|  |       int mu = combs[c][0], nu = combs[c][1], rho = combs[c][2], sigma = combs[c][3]; | ||||||
|  |       int eps = signs[c]; | ||||||
|  |       fsum = fsum + (8. * coeff * eps) * trace( (*F[mu][nu]) * (*F[rho][sigma]) );  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(int mu=0;mu<Nd-1;mu++) | ||||||
|  |       for(int nu=mu+1; nu<Nd; nu++) | ||||||
|  | 	delete F[mu][nu]; | ||||||
|  |      | ||||||
|  |     typedef typename ComplexField::scalar_object sobj; | ||||||
|  |     std::vector<sobj> Tq; | ||||||
|  |     sliceSum(fsum, Tq, Nd-1); | ||||||
|  |  | ||||||
|  |     std::vector<Real> out(Tq.size()); | ||||||
|  |     for(int t=0;t<Tq.size();t++) out[t] = TensorRemove(Tq[t]).real(); | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |   static Real TopologicalChargeMxN(const GaugeLorentz &U, int M, int N){ | ||||||
|  |     std::vector<Real> Tq = TimesliceTopologicalChargeMxN(U,M,N); | ||||||
|  |     Real out(0); | ||||||
|  |     for(int t=0;t<Tq.size();t++) out += Tq[t]; | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Generate the contributions to the 5Li topological charge from Wilson loops of the following sizes | ||||||
|  |   //Use coefficients from hep-lat/9701012 | ||||||
|  |   //1x1 : c1=(19.-55.*c5)/9. | ||||||
|  |   //2x2 : c2=(1-64.*c5)/9. | ||||||
|  |   //1x2 : c3=(-64.+640.*c5)/45. | ||||||
|  |   //1x3 : c4=1./5.-2.*c5 | ||||||
|  |   //3x3 : c5=1./20. | ||||||
|  |   //Output array outer index contains the loops in the above order | ||||||
|  |   //Inner index is the time coordinate | ||||||
|  |   static std::vector<std::vector<Real> > TimesliceTopologicalCharge5LiContributions(const GaugeLorentz &U){ | ||||||
|  |     static const int exts[5][2] = { {1,1}, {2,2}, {1,2}, {1,3}, {3,3} };        | ||||||
|  |     std::vector<std::vector<Real> > out(5); | ||||||
|  |     for(int i=0;i<5;i++){	 | ||||||
|  |       out[i] = TimesliceTopologicalChargeMxN(U,exts[i][0],exts[i][1]); | ||||||
|  |     } | ||||||
|  |     return out; | ||||||
|  |   }    | ||||||
|  |  | ||||||
|  |   static std::vector<Real> TopologicalCharge5LiContributions(const GaugeLorentz &U){    | ||||||
|  |     static const int exts[5][2] = { {1,1}, {2,2}, {1,2}, {1,3}, {3,3} }; | ||||||
|  |     std::vector<Real> out(5); | ||||||
|  |     std::cout << GridLogMessage << "Computing topological charge" << std::endl; | ||||||
|  |     for(int i=0;i<5;i++){ | ||||||
|  |       out[i] = TopologicalChargeMxN(U,exts[i][0],exts[i][1]); | ||||||
|  |       std::cout << GridLogMessage << exts[i][0] << "x" << exts[i][1] << " Wilson loop contribution " << out[i] << std::endl; | ||||||
|  |     } | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Compute the 5Li topological charge | ||||||
|  |   static std::vector<Real> TimesliceTopologicalCharge5Li(const GaugeLorentz &U){ | ||||||
|  |     std::vector<std::vector<Real> > loops = TimesliceTopologicalCharge5LiContributions(U); | ||||||
|  |  | ||||||
|  |     double c5=1./20.; | ||||||
|  |     double c4=1./5.-2.*c5; | ||||||
|  |     double c3=(-64.+640.*c5)/45.; | ||||||
|  |     double c2=(1-64.*c5)/9.; | ||||||
|  |     double c1=(19.-55.*c5)/9.; | ||||||
|  |  | ||||||
|  |     int Lt = loops[0].size(); | ||||||
|  |     std::vector<Real> out(Lt,0.); | ||||||
|  |     for(int t=0;t<Lt;t++) | ||||||
|  |       out[t] += c1*loops[0][t] + c2*loops[1][t] + c3*loops[2][t] + c4*loops[3][t] + c5*loops[4][t]; | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static Real TopologicalCharge5Li(const GaugeLorentz &U){ | ||||||
|  |     std::vector<Real> Qt = TimesliceTopologicalCharge5Li(U); | ||||||
|  |     Real Q = 0.; | ||||||
|  |     for(int t=0;t<Qt.size();t++) Q += Qt[t]; | ||||||
|  |     std::cout << GridLogMessage << "5Li Topological charge: " << Q << std::endl; | ||||||
|  |     return Q; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   ////////////////////////////////////////////////////// |   ////////////////////////////////////////////////////// | ||||||
|   // Similar to above for rectangle is required |   // Similar to above for rectangle is required | ||||||
|   ////////////////////////////////////////////////////// |   ////////////////////////////////////////////////////// | ||||||
|   | |||||||
							
								
								
									
										200
									
								
								Grid/random/gaussian.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								Grid/random/gaussian.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | |||||||
|  | // -*- C++ -*- | ||||||
|  | //===--------------------------- random -----------------------------------===// | ||||||
|  | // | ||||||
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||
|  | // See https://llvm.org/LICENSE.txt for license information. | ||||||
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  | // | ||||||
|  | //===----------------------------------------------------------------------===// | ||||||
|  |  | ||||||
|  | // Peter Boyle: Taken from libc++ in Clang/LLVM. | ||||||
|  | // Reason is that libstdc++ and clang differ in their return order in the normal_distribution / box mueller type step. | ||||||
|  | // standardise on one and call it "gaussian_distribution". | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <cstddef> | ||||||
|  | #include <cstdint> | ||||||
|  | #include <cmath> | ||||||
|  | #include <type_traits> | ||||||
|  | #include <initializer_list> | ||||||
|  | #include <limits> | ||||||
|  | #include <algorithm> | ||||||
|  | #include <numeric> | ||||||
|  | #include <vector> | ||||||
|  | #include <string> | ||||||
|  | #include <istream> | ||||||
|  | #include <ostream> | ||||||
|  | #include <random> | ||||||
|  |  | ||||||
|  | // normal_distribution -> gaussian distribution | ||||||
|  | namespace Grid { | ||||||
|  |  | ||||||
|  | template<class _RealType = double> | ||||||
|  | class  gaussian_distribution | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     // types | ||||||
|  |     typedef _RealType result_type; | ||||||
|  |  | ||||||
|  |     class param_type | ||||||
|  |     { | ||||||
|  |         result_type __mean_; | ||||||
|  |         result_type __stddev_; | ||||||
|  |     public: | ||||||
|  |         typedef gaussian_distribution distribution_type; | ||||||
|  |  | ||||||
|  |         strong_inline | ||||||
|  |         explicit param_type(result_type __mean = 0, result_type __stddev = 1) | ||||||
|  |             : __mean_(__mean), __stddev_(__stddev) {} | ||||||
|  |  | ||||||
|  |         strong_inline | ||||||
|  |         result_type mean() const {return __mean_;} | ||||||
|  |         strong_inline | ||||||
|  |         result_type stddev() const {return __stddev_;} | ||||||
|  |  | ||||||
|  |         friend strong_inline | ||||||
|  |             bool operator==(const param_type& __x, const param_type& __y) | ||||||
|  |             {return __x.__mean_ == __y.__mean_ && __x.__stddev_ == __y.__stddev_;} | ||||||
|  |         friend strong_inline | ||||||
|  |             bool operator!=(const param_type& __x, const param_type& __y) | ||||||
|  |             {return !(__x == __y);} | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     param_type __p_; | ||||||
|  |     result_type _V_; | ||||||
|  |     bool _V_hot_; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     // constructors and reset functions | ||||||
|  |     strong_inline | ||||||
|  |     explicit gaussian_distribution(result_type __mean = 0, result_type __stddev = 1) | ||||||
|  |         : __p_(param_type(__mean, __stddev)), _V_hot_(false) {} | ||||||
|  |     strong_inline | ||||||
|  |     explicit gaussian_distribution(const param_type& __p) | ||||||
|  |         : __p_(__p), _V_hot_(false) {} | ||||||
|  |     strong_inline | ||||||
|  |     void reset() {_V_hot_ = false;} | ||||||
|  |  | ||||||
|  |     // generating functions | ||||||
|  |     template<class _URNG> | ||||||
|  |         strong_inline | ||||||
|  |         result_type operator()(_URNG& __g) | ||||||
|  |         {return (*this)(__g, __p_);} | ||||||
|  |     template<class _URNG> result_type operator()(_URNG& __g, const param_type& __p); | ||||||
|  |  | ||||||
|  |     // property functions | ||||||
|  |     strong_inline | ||||||
|  |     result_type mean() const {return __p_.mean();} | ||||||
|  |     strong_inline | ||||||
|  |     result_type stddev() const {return __p_.stddev();} | ||||||
|  |  | ||||||
|  |     strong_inline | ||||||
|  |     param_type param() const {return __p_;} | ||||||
|  |     strong_inline | ||||||
|  |     void param(const param_type& __p) {__p_ = __p;} | ||||||
|  |  | ||||||
|  |     strong_inline | ||||||
|  |     result_type min() const {return -std::numeric_limits<result_type>::infinity();} | ||||||
|  |     strong_inline | ||||||
|  |     result_type max() const {return std::numeric_limits<result_type>::infinity();} | ||||||
|  |  | ||||||
|  |     friend strong_inline | ||||||
|  |         bool operator==(const gaussian_distribution& __x, | ||||||
|  |                         const gaussian_distribution& __y) | ||||||
|  |         {return __x.__p_ == __y.__p_ && __x._V_hot_ == __y._V_hot_ && | ||||||
|  |                 (!__x._V_hot_ || __x._V_ == __y._V_);} | ||||||
|  |     friend strong_inline | ||||||
|  |         bool operator!=(const gaussian_distribution& __x, | ||||||
|  |                         const gaussian_distribution& __y) | ||||||
|  |         {return !(__x == __y);} | ||||||
|  |  | ||||||
|  |     template <class _CharT, class _Traits, class _RT> | ||||||
|  |     friend | ||||||
|  |     std::basic_ostream<_CharT, _Traits>& | ||||||
|  |     operator<<(std::basic_ostream<_CharT, _Traits>& __os, | ||||||
|  |                const gaussian_distribution<_RT>& __x); | ||||||
|  |  | ||||||
|  |     template <class _CharT, class _Traits, class _RT> | ||||||
|  |     friend | ||||||
|  |     std::basic_istream<_CharT, _Traits>& | ||||||
|  |     operator>>(std::basic_istream<_CharT, _Traits>& __is, | ||||||
|  |                gaussian_distribution<_RT>& __x); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <class _RealType> | ||||||
|  | template<class _URNG> | ||||||
|  | _RealType | ||||||
|  | gaussian_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) | ||||||
|  | { | ||||||
|  |     result_type _Up; | ||||||
|  |     if (_V_hot_) | ||||||
|  |     { | ||||||
|  |         _V_hot_ = false; | ||||||
|  |         _Up = _V_; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         std::uniform_real_distribution<result_type> _Uni(-1, 1); | ||||||
|  |         result_type __u; | ||||||
|  |         result_type __v; | ||||||
|  |         result_type __s; | ||||||
|  |         do | ||||||
|  |         { | ||||||
|  |             __u = _Uni(__g); | ||||||
|  |             __v = _Uni(__g); | ||||||
|  |             __s = __u * __u + __v * __v; | ||||||
|  |         } while (__s > 1 || __s == 0); | ||||||
|  |         result_type _Fp = std::sqrt(-2 * std::log(__s) / __s); | ||||||
|  |         _V_ = __v * _Fp; | ||||||
|  |         _V_hot_ = true; | ||||||
|  |         _Up = __u * _Fp; | ||||||
|  |     } | ||||||
|  |     return _Up * __p.stddev() + __p.mean(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class _CharT, class _Traits, class _RT> | ||||||
|  | std::basic_ostream<_CharT, _Traits>& | ||||||
|  | operator<<(std::basic_ostream<_CharT, _Traits>& __os, | ||||||
|  |            const gaussian_distribution<_RT>& __x) | ||||||
|  | { | ||||||
|  |     auto __save_flags = __os.flags(); | ||||||
|  |     __os.flags(std::ios_base::dec | std::ios_base::left | std::ios_base::fixed | | ||||||
|  |                std::ios_base::scientific); | ||||||
|  |     _CharT __sp = __os.widen(' '); | ||||||
|  |     __os.fill(__sp); | ||||||
|  |     __os << __x.mean() << __sp << __x.stddev() << __sp << __x._V_hot_; | ||||||
|  |     if (__x._V_hot_) | ||||||
|  |         __os << __sp << __x._V_; | ||||||
|  |     __os.flags(__save_flags); | ||||||
|  |     return __os; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <class _CharT, class _Traits, class _RT> | ||||||
|  | std::basic_istream<_CharT, _Traits>& | ||||||
|  | operator>>(std::basic_istream<_CharT, _Traits>& __is, | ||||||
|  |            gaussian_distribution<_RT>& __x) | ||||||
|  | { | ||||||
|  |     typedef gaussian_distribution<_RT> _Eng; | ||||||
|  |     typedef typename _Eng::result_type result_type; | ||||||
|  |     typedef typename _Eng::param_type param_type; | ||||||
|  |     auto __save_flags = __is.flags(); | ||||||
|  |     __is.flags(std::ios_base::dec | std::ios_base::skipws); | ||||||
|  |     result_type __mean; | ||||||
|  |     result_type __stddev; | ||||||
|  |     result_type _Vp = 0; | ||||||
|  |     bool _V_hot = false; | ||||||
|  |     __is >> __mean >> __stddev >> _V_hot; | ||||||
|  |     if (_V_hot) | ||||||
|  |         __is >> _Vp; | ||||||
|  |     if (!__is.fail()) | ||||||
|  |     { | ||||||
|  |         __x.param(param_type(__mean, __stddev)); | ||||||
|  |         __x._V_hot_ = _V_hot; | ||||||
|  |         __x._V_ = _Vp; | ||||||
|  |     } | ||||||
|  |     __is.flags(__save_flags); | ||||||
|  |     return __is; | ||||||
|  | } | ||||||
|  | } | ||||||
| @@ -208,5 +208,46 @@ void merge(vobj &vec,const ExtractPointerArray<sobj> &extracted, int offset) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | //Copy a single lane of a SIMD tensor type from one object to another | ||||||
|  | //Output object must be of the same tensor type but may be of a different precision (i.e. it can have a different root data type) | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<class vobjOut, class vobjIn> | ||||||
|  | accelerator_inline  | ||||||
|  | void copyLane(vobjOut & __restrict__ vecOut, int lane_out, const vobjIn & __restrict__ vecIn, int lane_in) | ||||||
|  | { | ||||||
|  |   static_assert( std::is_same<typename vobjOut::DoublePrecision, typename vobjIn::DoublePrecision>::value == 1, "copyLane: tensor types must be the same" ); //if tensor types are same the DoublePrecision type must be the same | ||||||
|  |  | ||||||
|  |   typedef typename vobjOut::vector_type ovector_type;   | ||||||
|  |   typedef typename vobjIn::vector_type ivector_type;   | ||||||
|  |   constexpr int owords=sizeof(vobjOut)/sizeof(ovector_type); | ||||||
|  |   constexpr int iwords=sizeof(vobjIn)/sizeof(ivector_type); | ||||||
|  |   static_assert( owords == iwords, "copyLane: Expected number of vector words in input and output objects to be equal" ); | ||||||
|  |  | ||||||
|  |   typedef typename vobjOut::scalar_type oscalar_type;   | ||||||
|  |   typedef typename vobjIn::scalar_type iscalar_type;   | ||||||
|  |   typedef typename ExtractTypeMap<oscalar_type>::extract_type oextract_type; | ||||||
|  |   typedef typename ExtractTypeMap<iscalar_type>::extract_type iextract_type; | ||||||
|  |  | ||||||
|  |   typedef oextract_type * opointer; | ||||||
|  |   typedef iextract_type * ipointer; | ||||||
|  |  | ||||||
|  |   constexpr int oNsimd=ovector_type::Nsimd(); | ||||||
|  |   constexpr int iNsimd=ivector_type::Nsimd(); | ||||||
|  |  | ||||||
|  |   iscalar_type itmp; | ||||||
|  |   oscalar_type otmp; | ||||||
|  |  | ||||||
|  |   opointer __restrict__  op = (opointer)&vecOut; | ||||||
|  |   ipointer __restrict__  ip = (ipointer)&vecIn; | ||||||
|  |   for(int w=0;w<owords;w++){ | ||||||
|  |     memcpy( (char*)&itmp, (char*)(ip + lane_in + iNsimd*w), sizeof(iscalar_type) ); | ||||||
|  |     otmp = itmp; //potential precision change | ||||||
|  |     memcpy( (char*)(op + lane_out + oNsimd*w), (char*)&otmp, sizeof(oscalar_type) ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| NAMESPACE_END(Grid); | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -206,7 +206,8 @@ inline void *acceleratorAllocShared(size_t bytes) | |||||||
|   auto err = cudaMallocManaged((void **)&ptr,bytes); |   auto err = cudaMallocManaged((void **)&ptr,bytes); | ||||||
|   if( err != cudaSuccess ) { |   if( err != cudaSuccess ) { | ||||||
|     ptr = (void *) NULL; |     ptr = (void *) NULL; | ||||||
|     printf(" cudaMallocManaged failed for %d %s \n",bytes,cudaGetErrorString(err)); |     printf(" cudaMallocManaged failed for %lu %s \n",bytes,cudaGetErrorString(err)); fflush(stdout); | ||||||
|  |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|   } |   } | ||||||
|   return ptr; |   return ptr; | ||||||
| }; | }; | ||||||
| @@ -216,15 +217,47 @@ inline void *acceleratorAllocDevice(size_t bytes) | |||||||
|   auto err = cudaMalloc((void **)&ptr,bytes); |   auto err = cudaMalloc((void **)&ptr,bytes); | ||||||
|   if( err != cudaSuccess ) { |   if( err != cudaSuccess ) { | ||||||
|     ptr = (void *) NULL; |     ptr = (void *) NULL; | ||||||
|     printf(" cudaMalloc failed for %d %s \n",bytes,cudaGetErrorString(err)); |     printf(" cudaMalloc failed for %lu %s \n",bytes,cudaGetErrorString(err)); fflush(stdout); | ||||||
|  |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|   } |   } | ||||||
|   return ptr; |   return ptr; | ||||||
| }; | }; | ||||||
| inline void acceleratorFreeShared(void *ptr){ cudaFree(ptr);}; | inline void acceleratorFreeShared(void *ptr){ | ||||||
| inline void acceleratorFreeDevice(void *ptr){ cudaFree(ptr);}; |   auto err = cudaFree(ptr); | ||||||
| inline void acceleratorCopyToDevice(void *from,void *to,size_t bytes)  { cudaMemcpy(to,from,bytes, cudaMemcpyHostToDevice);} |   if( err != cudaSuccess ) { | ||||||
| inline void acceleratorCopyFromDevice(void *from,void *to,size_t bytes){ cudaMemcpy(to,from,bytes, cudaMemcpyDeviceToHost);} |     printf(" cudaFree(Shared) failed %s \n",cudaGetErrorString(err)); fflush(stdout); | ||||||
| inline void acceleratorMemSet(void *base,int value,size_t bytes) { cudaMemset(base,value,bytes);} |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | inline void acceleratorFreeDevice(void *ptr){ | ||||||
|  |   auto err = cudaFree(ptr); | ||||||
|  |   if( err != cudaSuccess ) { | ||||||
|  |     printf(" cudaFree(Device) failed %s \n",cudaGetErrorString(err)); fflush(stdout); | ||||||
|  |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | inline void acceleratorCopyToDevice(void *from,void *to,size_t bytes)  { | ||||||
|  |   auto err = cudaMemcpy(to,from,bytes, cudaMemcpyHostToDevice); | ||||||
|  |   if( err != cudaSuccess ) { | ||||||
|  |     printf(" cudaMemcpy(host->device) failed for %lu %s \n",bytes,cudaGetErrorString(err)); fflush(stdout); | ||||||
|  |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | inline void acceleratorCopyFromDevice(void *from,void *to,size_t bytes){ | ||||||
|  |   auto err = cudaMemcpy(to,from,bytes, cudaMemcpyDeviceToHost); | ||||||
|  |   if( err != cudaSuccess ) { | ||||||
|  |     printf(" cudaMemcpy(device->host) failed for %lu %s \n",bytes,cudaGetErrorString(err)); fflush(stdout); | ||||||
|  |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | inline void acceleratorMemSet(void *base,int value,size_t bytes) { | ||||||
|  |   auto err = cudaMemset(base,value,bytes); | ||||||
|  |   if( err != cudaSuccess ) { | ||||||
|  |     printf(" cudaMemSet failed for %lu %s \n",bytes,cudaGetErrorString(err)); fflush(stdout); | ||||||
|  |     if (acceleratorAbortOnGpuError) assert(err==cudaSuccess); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| inline void acceleratorCopyDeviceToDeviceAsynch(void *from,void *to,size_t bytes) // Asynch | inline void acceleratorCopyDeviceToDeviceAsynch(void *from,void *to,size_t bytes) // Asynch | ||||||
| { | { | ||||||
|   cudaMemcpyAsync(to,from,bytes, cudaMemcpyDeviceToDevice,copyStream); |   cudaMemcpyAsync(to,from,bytes, cudaMemcpyDeviceToDevice,copyStream); | ||||||
|   | |||||||
							
								
								
									
										473
									
								
								HMC/DWF2p1fIwasakiGparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								HMC/DWF2p1fIwasakiGparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,473 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./HMC/DWF2p1fIwasakiGparity.cc | ||||||
|  |  | ||||||
|  | Copyright (C) 2015-2016 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  | Author: Peter Boyle <pabobyle@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; | ||||||
|  |  | ||||||
|  | //2+1f DWF+I ensemble with G-parity BCs | ||||||
|  | //designed to reproduce ensembles in https://arxiv.org/pdf/1908.08640.pdf | ||||||
|  | struct RatQuoParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(RatQuoParameters, | ||||||
|  | 				  double, bnd_lo, | ||||||
|  | 				  double, bnd_hi, | ||||||
|  | 				  Integer, action_degree, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  Integer, md_degree, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  Integer, reliable_update_freq, | ||||||
|  | 				  Integer, bnd_check_freq); | ||||||
|  |   RatQuoParameters() {  | ||||||
|  |     bnd_lo = 1e-2; | ||||||
|  |     bnd_hi = 30; | ||||||
|  |     action_degree = 10; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_degree = 10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     bnd_check_freq = 20; | ||||||
|  |     reliable_update_freq = 50; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Export(RationalActionParams &into) const{ | ||||||
|  |     into.lo = bnd_lo; | ||||||
|  |     into.hi = bnd_hi; | ||||||
|  |     into.action_degree = action_degree; | ||||||
|  |     into.action_tolerance = action_tolerance; | ||||||
|  |     into.md_degree = md_degree; | ||||||
|  |     into.md_tolerance = md_tolerance; | ||||||
|  |     into.BoundsCheckFreq = bnd_check_freq; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct EvolParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EvolParameters, | ||||||
|  |                                   Integer, StartTrajectory, | ||||||
|  |                                   Integer, Trajectories, | ||||||
|  | 				  Integer, SaveInterval, | ||||||
|  | 				  Integer, Steps, | ||||||
|  |                                   bool, MetropolisTest, | ||||||
|  | 				  std::string, StartingType, | ||||||
|  | 				  std::vector<Integer>, GparityDirs, | ||||||
|  | 				  RatQuoParameters, rat_quo_l, | ||||||
|  | 				  RatQuoParameters, rat_quo_s); | ||||||
|  |  | ||||||
|  |   EvolParameters() { | ||||||
|  |     //For initial thermalization; afterwards user should switch Metropolis on and use StartingType=CheckpointStart | ||||||
|  |     MetropolisTest    = false; | ||||||
|  |     StartTrajectory   = 0; | ||||||
|  |     Trajectories      = 50; | ||||||
|  |     SaveInterval = 5; | ||||||
|  |     StartingType      = "ColdStart"; | ||||||
|  |     GparityDirs.resize(3, 1); //1 for G-parity, 0 for periodic | ||||||
|  |     Steps = 5; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | bool fileExists(const std::string &fn){ | ||||||
|  |   std::ifstream f(fn); | ||||||
|  |   return f.good(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct LanczosParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParameters, | ||||||
|  | 				  double, alpha, | ||||||
|  | 				  double, beta, | ||||||
|  | 				  double, mu, | ||||||
|  | 				  int, ord, | ||||||
|  | 				  int, n_stop, | ||||||
|  | 				  int, n_want, | ||||||
|  | 				  int, n_use, | ||||||
|  | 				  double, tolerance); | ||||||
|  |  | ||||||
|  |   LanczosParameters() { | ||||||
|  |     alpha = 35; | ||||||
|  |     beta = 5; | ||||||
|  |     mu = 0; | ||||||
|  |     ord = 100; | ||||||
|  |     n_stop = 10; | ||||||
|  |     n_want = 10; | ||||||
|  |     n_use = 15; | ||||||
|  |     tolerance = 1e-6; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionActionD, typename FermionFieldD> | ||||||
|  | void computeEigenvalues(std::string param_file, | ||||||
|  | 			GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 			FermionActionD &action, GridParallelRNG &rng){ | ||||||
|  |    | ||||||
|  |   LanczosParameters params; | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "LanczosParameters", params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "LanczosParameters", params); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   action.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   SchurDiagMooeeOperator<FermionActionD, FermionFieldD> hermop(action); | ||||||
|  |   PlainHermOp<FermionFieldD> hermop_wrap(hermop); | ||||||
|  |   //ChebyshevLanczos<FermionFieldD> Cheb(params.alpha, params.beta, params.mu, params.ord); | ||||||
|  |   assert(params.mu == 0.0); | ||||||
|  |  | ||||||
|  |   Chebyshev<FermionFieldD> Cheb(params.beta*params.beta, params.alpha*params.alpha, params.ord+1); | ||||||
|  |   FunctionHermOp<FermionFieldD> Cheb_wrap(Cheb, hermop); | ||||||
|  |  | ||||||
|  |   std::cout << "IRL: alpha=" << params.alpha << " beta=" << params.beta << " mu=" << params.mu << " ord=" << params.ord << std::endl; | ||||||
|  |   ImplicitlyRestartedLanczos<FermionFieldD> IRL(Cheb_wrap, hermop_wrap, params.n_stop, params.n_want, params.n_use, params.tolerance, 10000); | ||||||
|  |  | ||||||
|  |   std::vector<RealD> eval(params.n_use); | ||||||
|  |   std::vector<FermionFieldD> evec(params.n_use, rbGrid); | ||||||
|  |   int Nconv; | ||||||
|  |   IRL.calc(eval, evec, gauss_o, Nconv); | ||||||
|  |  | ||||||
|  |   std::cout << "Eigenvalues:" << std::endl; | ||||||
|  |   for(int i=0;i<params.n_want;i++){ | ||||||
|  |     std::cout << i << " " << eval[i] << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Check the quality of the RHMC approx | ||||||
|  | template<typename FermionActionD, typename FermionFieldD, typename RHMCtype> | ||||||
|  | void checkRHMC(GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 	       FermionActionD &numOp, FermionActionD &denOp, RHMCtype &rhmc, GridParallelRNG &rng, | ||||||
|  | 	       int inv_pow, const std::string &quark_descr){ | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   numOp.ImportGauge(latt); | ||||||
|  |   denOp.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> MdagM(numOp); | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> VdagV(denOp); | ||||||
|  |        | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerAction); //use large tolerance to prevent exit on fail; we are trying to tune here! | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerAction); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "-------------------------------------------------------------------------------" << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerMD);  | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerMD); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main(int argc, char **argv) { | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |   int threads = GridThread::GetThreads(); | ||||||
|  |   // here make a routine to print all the relevant information on the run | ||||||
|  |   std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||||
|  |  | ||||||
|  |   std::string param_file = "params.xml"; | ||||||
|  |   bool file_load_check = false; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--param_file"){ | ||||||
|  |       assert(i!=argc-1); | ||||||
|  |       param_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_check"){ //check the fields load correctly and pass checksum/plaquette repro | ||||||
|  |       file_load_check = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Read the user parameters | ||||||
|  |   EvolParameters user_params; | ||||||
|  |    | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "Params", user_params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "Params", user_params); | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Check the parameters | ||||||
|  |   if(user_params.GparityDirs.size() != Nd-1){ | ||||||
|  |     std::cerr << "Error in input parameters: expect GparityDirs to have size = " << Nd-1 << std::endl; | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<Nd-1;i++) | ||||||
|  |     if(user_params.GparityDirs[i] != 0 && user_params.GparityDirs[i] != 1){ | ||||||
|  |       std::cerr << "Error in input parameters: expect GparityDirs values to be 0 (periodic) or 1 (G-parity)" << std::endl; | ||||||
|  |       exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |    // Typedefs to simplify notation | ||||||
|  |   typedef GparityDomainWallFermionD FermionActionD; | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   typedef typename FermionActionD::FermionField FermionFieldD; | ||||||
|  |  | ||||||
|  |   typedef GparityDomainWallFermionF FermionActionF; | ||||||
|  |   typedef typename FermionActionF::Impl_t FermionImplPolicyF; | ||||||
|  |   typedef typename FermionActionF::FermionField FermionFieldF; | ||||||
|  |  | ||||||
|  |   typedef GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction<FermionImplPolicyD,FermionImplPolicyF> MixedPrecRHMC; | ||||||
|  |   typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicyD> DoublePrecRHMC; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   IntegratorParameters MD; | ||||||
|  |   typedef ConjugateHMCRunnerD<MinimumNorm2> HMCWrapper; //NB: This is the "Omelyan integrator" | ||||||
|  |   typedef HMCWrapper::ImplPolicy GaugeImplPolicy; | ||||||
|  |   MD.name    = std::string("MinimumNorm2"); | ||||||
|  |   MD.MDsteps = user_params.Steps; | ||||||
|  |   MD.trajL   = 1.0; | ||||||
|  |  | ||||||
|  |   HMCparameters HMCparams; | ||||||
|  |   HMCparams.StartTrajectory  = user_params.StartTrajectory; | ||||||
|  |   HMCparams.Trajectories     = user_params.Trajectories; | ||||||
|  |   HMCparams.NoMetropolisUntil= 0; | ||||||
|  |   HMCparams.StartingType     = user_params.StartingType; | ||||||
|  |   HMCparams.MetropolisTest = user_params.MetropolisTest; | ||||||
|  |   HMCparams.MD = MD; | ||||||
|  |   HMCWrapper TheHMC(HMCparams); | ||||||
|  |  | ||||||
|  |   // Grid from the command line arguments --grid and --mpi | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); // use default simd lanes decomposition | ||||||
|  |  | ||||||
|  |   CheckpointerParameters CPparams; | ||||||
|  |   CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   CPparams.rng_prefix    = "ckpoint_rng"; | ||||||
|  |   CPparams.saveInterval  = user_params.SaveInterval; | ||||||
|  |   CPparams.format        = "IEEE64BIG"; | ||||||
|  |   TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   //Note that checkpointing saves the RNG state so that this initialization is required only for the very first configuration | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   typedef PlaquetteMod<GaugeImplPolicy> PlaqObs; | ||||||
|  |   TheHMC.Resources.AddObservable<PlaqObs>(); | ||||||
|  |   ////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   const int Ls      = 16; | ||||||
|  |   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 Grids | ||||||
|  |   auto GridPtrD   = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto GridRBPtrD = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |   auto FGridD     = SpaceTimeGrid::makeFiveDimGrid(Ls,GridPtrD); | ||||||
|  |   auto FrbGridD   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,GridPtrD); | ||||||
|  |  | ||||||
|  |   GridCartesian* GridPtrF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* GridRBPtrF = SpaceTimeGrid::makeFourDimRedBlackGrid(GridPtrF); | ||||||
|  |   auto FGridF     = SpaceTimeGrid::makeFiveDimGrid(Ls,GridPtrF); | ||||||
|  |   auto FrbGridF   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,GridPtrF); | ||||||
|  |  | ||||||
|  |   ConjugateIwasakiGaugeActionD GaugeAction(beta); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeFieldD Ud(GridPtrD); | ||||||
|  |   LatticeGaugeFieldF Uf(GridPtrF); | ||||||
|  |   | ||||||
|  |   //Setup the BCs | ||||||
|  |   FermionActionD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = user_params.GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |  | ||||||
|  |   std::vector<int> dirs4(Nd); | ||||||
|  |   for(int i=0;i<Nd-1;i++) dirs4[i] = user_params.GparityDirs[i]; | ||||||
|  |   dirs4[Nd-1] = 0; //periodic gauge BC in time | ||||||
|  |  | ||||||
|  |   GaugeImplPolicy::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   //Run optional gauge field checksum checker and exit | ||||||
|  |   if(file_load_check){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Collect actions | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level1(1); //light quark + strange quark | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level2(8); //gauge (8 increments per step) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Light action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   FermionActionD Numerator_lD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD, light_mass,M5,Params); | ||||||
|  |   FermionActionD Denominator_lD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_lF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF, light_mass,M5,Params); | ||||||
|  |   FermionActionF Denominator_lF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_l; | ||||||
|  |   rat_act_params_l.inv_pow  = 2; // (M^dag M)^{1/2} | ||||||
|  |   rat_act_params_l.precision= 60; | ||||||
|  |   rat_act_params_l.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_l.Export(rat_act_params_l); | ||||||
|  |   std::cout << GridLogMessage << " Light quark bounds check every " << rat_act_params_l.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |   | ||||||
|  |   MixedPrecRHMC Quotient_l(Denominator_lD, Numerator_lD, Denominator_lF, Numerator_lF, rat_act_params_l, user_params.rat_quo_l.reliable_update_freq); | ||||||
|  |   //DoublePrecRHMC Quotient_l(Denominator_lD, Numerator_lD, rat_act_params_l); | ||||||
|  |   Level1.push_back(&Quotient_l); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Strange action | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   FermionActionD Numerator_sD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD,strange_mass,M5,Params); | ||||||
|  |   FermionActionD Denominator_sD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_sF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF,strange_mass,M5,Params); | ||||||
|  |   FermionActionF Denominator_sF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_s; | ||||||
|  |   rat_act_params_s.inv_pow  = 4; // (M^dag M)^{1/4} | ||||||
|  |   rat_act_params_s.precision= 60; | ||||||
|  |   rat_act_params_s.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_s.Export(rat_act_params_s); | ||||||
|  |   std::cout << GridLogMessage << " Heavy quark bounds check every " << rat_act_params_l.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   MixedPrecRHMC Quotient_s(Denominator_sD, Numerator_sD, Denominator_sF, Numerator_sF, rat_act_params_s, user_params.rat_quo_s.reliable_update_freq);  | ||||||
|  |   //DoublePrecRHMC Quotient_s(Denominator_sD, Numerator_sD, rat_act_params_s);  | ||||||
|  |   Level1.push_back(&Quotient_s);   | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Gauge action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   Level2.push_back(&GaugeAction); | ||||||
|  |   TheHMC.TheAction.push_back(Level1); | ||||||
|  |   TheHMC.TheAction.push_back(Level2); | ||||||
|  |   std::cout << GridLogMessage << " Action complete "<< std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Action tuning | ||||||
|  |   bool tune_rhmc_l=false, tune_rhmc_s=false, eigenrange_l=false, eigenrange_s=false;  | ||||||
|  |   std::string lanc_params_l, lanc_params_s; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--tune_rhmc_l") tune_rhmc_l=true; | ||||||
|  |     else if(sarg == "--tune_rhmc_s") tune_rhmc_s=true; | ||||||
|  |     else if(sarg == "--eigenrange_l"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_l=true; | ||||||
|  |       lanc_params_l = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_s=true; | ||||||
|  |       lanc_params_s = argv[i+1]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if(tune_rhmc_l || tune_rhmc_s || eigenrange_l || eigenrange_s){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     if(eigenrange_l) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_l, FGridD, FrbGridD, Ud, Numerator_lD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(eigenrange_s) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_s, FGridD, FrbGridD, Ud, Numerator_sD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_l) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_l)>(FGridD, FrbGridD, Ud, Numerator_lD, Denominator_lD, Quotient_l, TheHMC.Resources.GetParallelRNG(), 2, "light"); | ||||||
|  |     if(tune_rhmc_s) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_s)>(FGridD, FrbGridD, Ud, Numerator_sD, Denominator_sD, Quotient_s, TheHMC.Resources.GetParallelRNG(), 4, "strange"); | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Run the HMC | ||||||
|  |   std::cout << GridLogMessage << " Running the HMC "<< std::endl; | ||||||
|  |   TheHMC.Run(); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } // main | ||||||
|  |  | ||||||
							
								
								
									
										473
									
								
								HMC/DWF2p1fIwasakiGparityRHMCdouble.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								HMC/DWF2p1fIwasakiGparityRHMCdouble.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,473 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./HMC/DWF2p1fIwasakiGparity.cc | ||||||
|  |  | ||||||
|  | Copyright (C) 2015-2016 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  | Author: Peter Boyle <pabobyle@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; | ||||||
|  |  | ||||||
|  | //2+1f DWF+I ensemble with G-parity BCs | ||||||
|  | //designed to reproduce ensembles in https://arxiv.org/pdf/1908.08640.pdf | ||||||
|  | struct RatQuoParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(RatQuoParameters, | ||||||
|  | 				  double, bnd_lo, | ||||||
|  | 				  double, bnd_hi, | ||||||
|  | 				  Integer, action_degree, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  Integer, md_degree, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  Integer, reliable_update_freq, | ||||||
|  | 				  Integer, bnd_check_freq); | ||||||
|  |   RatQuoParameters() {  | ||||||
|  |     bnd_lo = 1e-2; | ||||||
|  |     bnd_hi = 30; | ||||||
|  |     action_degree = 10; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_degree = 10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     bnd_check_freq = 20; | ||||||
|  |     reliable_update_freq = 50; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Export(RationalActionParams &into) const{ | ||||||
|  |     into.lo = bnd_lo; | ||||||
|  |     into.hi = bnd_hi; | ||||||
|  |     into.action_degree = action_degree; | ||||||
|  |     into.action_tolerance = action_tolerance; | ||||||
|  |     into.md_degree = md_degree; | ||||||
|  |     into.md_tolerance = md_tolerance; | ||||||
|  |     into.BoundsCheckFreq = bnd_check_freq; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct EvolParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EvolParameters, | ||||||
|  |                                   Integer, StartTrajectory, | ||||||
|  |                                   Integer, Trajectories, | ||||||
|  | 				  Integer, SaveInterval, | ||||||
|  | 				  Integer, Steps, | ||||||
|  |                                   bool, MetropolisTest, | ||||||
|  | 				  std::string, StartingType, | ||||||
|  | 				  std::vector<Integer>, GparityDirs, | ||||||
|  | 				  RatQuoParameters, rat_quo_l, | ||||||
|  | 				  RatQuoParameters, rat_quo_s); | ||||||
|  |  | ||||||
|  |   EvolParameters() { | ||||||
|  |     //For initial thermalization; afterwards user should switch Metropolis on and use StartingType=CheckpointStart | ||||||
|  |     MetropolisTest    = false; | ||||||
|  |     StartTrajectory   = 0; | ||||||
|  |     Trajectories      = 50; | ||||||
|  |     SaveInterval = 5; | ||||||
|  |     StartingType      = "ColdStart"; | ||||||
|  |     GparityDirs.resize(3, 1); //1 for G-parity, 0 for periodic | ||||||
|  |     Steps = 5; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | bool fileExists(const std::string &fn){ | ||||||
|  |   std::ifstream f(fn); | ||||||
|  |   return f.good(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct LanczosParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParameters, | ||||||
|  | 				  double, alpha, | ||||||
|  | 				  double, beta, | ||||||
|  | 				  double, mu, | ||||||
|  | 				  int, ord, | ||||||
|  | 				  int, n_stop, | ||||||
|  | 				  int, n_want, | ||||||
|  | 				  int, n_use, | ||||||
|  | 				  double, tolerance); | ||||||
|  |  | ||||||
|  |   LanczosParameters() { | ||||||
|  |     alpha = 35; | ||||||
|  |     beta = 5; | ||||||
|  |     mu = 0; | ||||||
|  |     ord = 100; | ||||||
|  |     n_stop = 10; | ||||||
|  |     n_want = 10; | ||||||
|  |     n_use = 15; | ||||||
|  |     tolerance = 1e-6; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionActionD, typename FermionFieldD> | ||||||
|  | void computeEigenvalues(std::string param_file, | ||||||
|  | 			GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 			FermionActionD &action, GridParallelRNG &rng){ | ||||||
|  |    | ||||||
|  |   LanczosParameters params; | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "LanczosParameters", params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "LanczosParameters", params); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   action.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   SchurDiagMooeeOperator<FermionActionD, FermionFieldD> hermop(action); | ||||||
|  |   PlainHermOp<FermionFieldD> hermop_wrap(hermop); | ||||||
|  |   //ChebyshevLanczos<FermionFieldD> Cheb(params.alpha, params.beta, params.mu, params.ord); | ||||||
|  |   assert(params.mu == 0.0); | ||||||
|  |  | ||||||
|  |   Chebyshev<FermionFieldD> Cheb(params.beta*params.beta, params.alpha*params.alpha, params.ord+1); | ||||||
|  |   FunctionHermOp<FermionFieldD> Cheb_wrap(Cheb, hermop); | ||||||
|  |  | ||||||
|  |   std::cout << "IRL: alpha=" << params.alpha << " beta=" << params.beta << " mu=" << params.mu << " ord=" << params.ord << std::endl; | ||||||
|  |   ImplicitlyRestartedLanczos<FermionFieldD> IRL(Cheb_wrap, hermop_wrap, params.n_stop, params.n_want, params.n_use, params.tolerance, 10000); | ||||||
|  |  | ||||||
|  |   std::vector<RealD> eval(params.n_use); | ||||||
|  |   std::vector<FermionFieldD> evec(params.n_use, rbGrid); | ||||||
|  |   int Nconv; | ||||||
|  |   IRL.calc(eval, evec, gauss_o, Nconv); | ||||||
|  |  | ||||||
|  |   std::cout << "Eigenvalues:" << std::endl; | ||||||
|  |   for(int i=0;i<params.n_want;i++){ | ||||||
|  |     std::cout << i << " " << eval[i] << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Check the quality of the RHMC approx | ||||||
|  | template<typename FermionActionD, typename FermionFieldD, typename RHMCtype> | ||||||
|  | void checkRHMC(GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 	       FermionActionD &numOp, FermionActionD &denOp, RHMCtype &rhmc, GridParallelRNG &rng, | ||||||
|  | 	       int inv_pow, const std::string &quark_descr){ | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   numOp.ImportGauge(latt); | ||||||
|  |   denOp.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> MdagM(numOp); | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> VdagV(denOp); | ||||||
|  |        | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerAction); //use large tolerance to prevent exit on fail; we are trying to tune here! | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerAction); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "-------------------------------------------------------------------------------" << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerMD);  | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerMD); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |   std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main(int argc, char **argv) { | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |   int threads = GridThread::GetThreads(); | ||||||
|  |   // here make a routine to print all the relevant information on the run | ||||||
|  |   std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||||
|  |  | ||||||
|  |   std::string param_file = "params.xml"; | ||||||
|  |   bool file_load_check = false; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--param_file"){ | ||||||
|  |       assert(i!=argc-1); | ||||||
|  |       param_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_check"){ //check the fields load correctly and pass checksum/plaquette repro | ||||||
|  |       file_load_check = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Read the user parameters | ||||||
|  |   EvolParameters user_params; | ||||||
|  |    | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "Params", user_params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "Params", user_params); | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Check the parameters | ||||||
|  |   if(user_params.GparityDirs.size() != Nd-1){ | ||||||
|  |     std::cerr << "Error in input parameters: expect GparityDirs to have size = " << Nd-1 << std::endl; | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<Nd-1;i++) | ||||||
|  |     if(user_params.GparityDirs[i] != 0 && user_params.GparityDirs[i] != 1){ | ||||||
|  |       std::cerr << "Error in input parameters: expect GparityDirs values to be 0 (periodic) or 1 (G-parity)" << std::endl; | ||||||
|  |       exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |    // Typedefs to simplify notation | ||||||
|  |   typedef GparityDomainWallFermionD FermionActionD; | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   typedef typename FermionActionD::FermionField FermionFieldD; | ||||||
|  |  | ||||||
|  |   typedef GparityDomainWallFermionF FermionActionF; | ||||||
|  |   typedef typename FermionActionF::Impl_t FermionImplPolicyF; | ||||||
|  |   typedef typename FermionActionF::FermionField FermionFieldF; | ||||||
|  |  | ||||||
|  |   typedef GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction<FermionImplPolicyD,FermionImplPolicyF> MixedPrecRHMC; | ||||||
|  |   typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicyD> DoublePrecRHMC; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   IntegratorParameters MD; | ||||||
|  |   typedef ConjugateHMCRunnerD<MinimumNorm2> HMCWrapper; //NB: This is the "Omelyan integrator" | ||||||
|  |   typedef HMCWrapper::ImplPolicy GaugeImplPolicy; | ||||||
|  |   MD.name    = std::string("MinimumNorm2"); | ||||||
|  |   MD.MDsteps = user_params.Steps; | ||||||
|  |   MD.trajL   = 1.0; | ||||||
|  |  | ||||||
|  |   HMCparameters HMCparams; | ||||||
|  |   HMCparams.StartTrajectory  = user_params.StartTrajectory; | ||||||
|  |   HMCparams.Trajectories     = user_params.Trajectories; | ||||||
|  |   HMCparams.NoMetropolisUntil= 0; | ||||||
|  |   HMCparams.StartingType     = user_params.StartingType; | ||||||
|  |   HMCparams.MetropolisTest = user_params.MetropolisTest; | ||||||
|  |   HMCparams.MD = MD; | ||||||
|  |   HMCWrapper TheHMC(HMCparams); | ||||||
|  |  | ||||||
|  |   // Grid from the command line arguments --grid and --mpi | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); // use default simd lanes decomposition | ||||||
|  |  | ||||||
|  |   CheckpointerParameters CPparams; | ||||||
|  |   CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   CPparams.rng_prefix    = "ckpoint_rng"; | ||||||
|  |   CPparams.saveInterval  = user_params.SaveInterval; | ||||||
|  |   CPparams.format        = "IEEE64BIG"; | ||||||
|  |   TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   //Note that checkpointing saves the RNG state so that this initialization is required only for the very first configuration | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   typedef PlaquetteMod<GaugeImplPolicy> PlaqObs; | ||||||
|  |   TheHMC.Resources.AddObservable<PlaqObs>(); | ||||||
|  |   ////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   const int Ls      = 16; | ||||||
|  |   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 Grids | ||||||
|  |   auto GridPtrD   = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto GridRBPtrD = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |   auto FGridD     = SpaceTimeGrid::makeFiveDimGrid(Ls,GridPtrD); | ||||||
|  |   auto FrbGridD   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,GridPtrD); | ||||||
|  |  | ||||||
|  |   GridCartesian* GridPtrF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* GridRBPtrF = SpaceTimeGrid::makeFourDimRedBlackGrid(GridPtrF); | ||||||
|  |   auto FGridF     = SpaceTimeGrid::makeFiveDimGrid(Ls,GridPtrF); | ||||||
|  |   auto FrbGridF   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,GridPtrF); | ||||||
|  |  | ||||||
|  |   ConjugateIwasakiGaugeActionD GaugeAction(beta); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeFieldD Ud(GridPtrD); | ||||||
|  |   LatticeGaugeFieldF Uf(GridPtrF); | ||||||
|  |   | ||||||
|  |   //Setup the BCs | ||||||
|  |   FermionActionD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = user_params.GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |  | ||||||
|  |   std::vector<int> dirs4(Nd); | ||||||
|  |   for(int i=0;i<Nd-1;i++) dirs4[i] = user_params.GparityDirs[i]; | ||||||
|  |   dirs4[Nd-1] = 0; //periodic gauge BC in time | ||||||
|  |  | ||||||
|  |   GaugeImplPolicy::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   //Run optional gauge field checksum checker and exit | ||||||
|  |   if(file_load_check){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Collect actions | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level1(1); //light quark + strange quark | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level2(8); //gauge (8 increments per step) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Light action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   FermionActionD Numerator_lD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD, light_mass,M5,Params); | ||||||
|  |   FermionActionD Denominator_lD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_lF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF, light_mass,M5,Params); | ||||||
|  |   FermionActionF Denominator_lF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_l; | ||||||
|  |   rat_act_params_l.inv_pow  = 2; // (M^dag M)^{1/2} | ||||||
|  |   rat_act_params_l.precision= 60; | ||||||
|  |   rat_act_params_l.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_l.Export(rat_act_params_l); | ||||||
|  |   std::cout << GridLogMessage << " Light quark bounds check every " << rat_act_params_l.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |   | ||||||
|  |   //MixedPrecRHMC Quotient_l(Denominator_lD, Numerator_lD, Denominator_lF, Numerator_lF, rat_act_params_l, user_params.rat_quo_l.reliable_update_freq); | ||||||
|  |   DoublePrecRHMC Quotient_l(Denominator_lD, Numerator_lD, rat_act_params_l); | ||||||
|  |   Level1.push_back(&Quotient_l); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Strange action | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   FermionActionD Numerator_sD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD,strange_mass,M5,Params); | ||||||
|  |   FermionActionD Denominator_sD(Ud,*FGridD,*FrbGridD,*GridPtrD,*GridRBPtrD, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_sF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF,strange_mass,M5,Params); | ||||||
|  |   FermionActionF Denominator_sF(Uf,*FGridF,*FrbGridF,*GridPtrF,*GridRBPtrF, pv_mass,M5,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_s; | ||||||
|  |   rat_act_params_s.inv_pow  = 4; // (M^dag M)^{1/4} | ||||||
|  |   rat_act_params_s.precision= 60; | ||||||
|  |   rat_act_params_s.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_s.Export(rat_act_params_s); | ||||||
|  |   std::cout << GridLogMessage << " Heavy quark bounds check every " << rat_act_params_l.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   //MixedPrecRHMC Quotient_s(Denominator_sD, Numerator_sD, Denominator_sF, Numerator_sF, rat_act_params_s, user_params.rat_quo_s.reliable_update_freq);  | ||||||
|  |   DoublePrecRHMC Quotient_s(Denominator_sD, Numerator_sD, rat_act_params_s);  | ||||||
|  |   Level1.push_back(&Quotient_s);   | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Gauge action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   Level2.push_back(&GaugeAction); | ||||||
|  |   TheHMC.TheAction.push_back(Level1); | ||||||
|  |   TheHMC.TheAction.push_back(Level2); | ||||||
|  |   std::cout << GridLogMessage << " Action complete "<< std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Action tuning | ||||||
|  |   bool tune_rhmc_l=false, tune_rhmc_s=false, eigenrange_l=false, eigenrange_s=false;  | ||||||
|  |   std::string lanc_params_l, lanc_params_s; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--tune_rhmc_l") tune_rhmc_l=true; | ||||||
|  |     else if(sarg == "--tune_rhmc_s") tune_rhmc_s=true; | ||||||
|  |     else if(sarg == "--eigenrange_l"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_l=true; | ||||||
|  |       lanc_params_l = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_s=true; | ||||||
|  |       lanc_params_s = argv[i+1]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if(tune_rhmc_l || tune_rhmc_s || eigenrange_l || eigenrange_s){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     if(eigenrange_l) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_l, FGridD, FrbGridD, Ud, Numerator_lD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(eigenrange_s) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_s, FGridD, FrbGridD, Ud, Numerator_sD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_l) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_l)>(FGridD, FrbGridD, Ud, Numerator_lD, Denominator_lD, Quotient_l, TheHMC.Resources.GetParallelRNG(), 2, "light"); | ||||||
|  |     if(tune_rhmc_s) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_s)>(FGridD, FrbGridD, Ud, Numerator_sD, Denominator_sD, Quotient_s, TheHMC.Resources.GetParallelRNG(), 4, "strange"); | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Run the HMC | ||||||
|  |   std::cout << GridLogMessage << " Running the HMC "<< std::endl; | ||||||
|  |   TheHMC.Run(); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } // main | ||||||
|  |  | ||||||
							
								
								
									
										765
									
								
								HMC/Mobius2p1fIDSDRGparityEOFA.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										765
									
								
								HMC/Mobius2p1fIDSDRGparityEOFA.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,765 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./HMC/Mobius2p1fIDSDRGparityEOFA.cc | ||||||
|  |  | ||||||
|  | Copyright (C) 2015-2016 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  | Author: Peter Boyle <pabobyle@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; | ||||||
|  |  | ||||||
|  | //We try to reproduce with G-parity BCs the 246 MeV 1.37 GeV ensemble | ||||||
|  | //To speed things up we will use Mobius DWF with b+c=32/12 and Ls=12 to match the Ls=32 of the original | ||||||
|  | //These parameters match those used in the 2020 K->pipi paper | ||||||
|  |  | ||||||
|  | struct RatQuoParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(RatQuoParameters, | ||||||
|  | 				  double, bnd_lo, | ||||||
|  | 				  double, bnd_hi, | ||||||
|  | 				  Integer, action_degree, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  Integer, md_degree, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  Integer, reliable_update_freq, | ||||||
|  | 				  Integer, bnd_check_freq); | ||||||
|  |   RatQuoParameters() {  | ||||||
|  |     bnd_lo = 1e-2; | ||||||
|  |     bnd_hi = 30; | ||||||
|  |     action_degree = 10; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_degree = 10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     bnd_check_freq = 20; | ||||||
|  |     reliable_update_freq = 50; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Export(RationalActionParams &into) const{ | ||||||
|  |     into.lo = bnd_lo; | ||||||
|  |     into.hi = bnd_hi; | ||||||
|  |     into.action_degree = action_degree; | ||||||
|  |     into.action_tolerance = action_tolerance; | ||||||
|  |     into.md_degree = md_degree; | ||||||
|  |     into.md_tolerance = md_tolerance; | ||||||
|  |     into.BoundsCheckFreq = bnd_check_freq; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct EOFAparameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EOFAparameters, | ||||||
|  | 				  OneFlavourRationalParams, rat_params, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  double, action_mixcg_inner_tolerance, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  double, md_mixcg_inner_tolerance); | ||||||
|  |  | ||||||
|  |   EOFAparameters() {  | ||||||
|  |     action_mixcg_inner_tolerance = 1e-8; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     md_mixcg_inner_tolerance = 1e-8; | ||||||
|  |  | ||||||
|  |     rat_params.lo = 0.1; | ||||||
|  |     rat_params.hi = 25.0; | ||||||
|  |     rat_params.MaxIter  = 10000; | ||||||
|  |     rat_params.tolerance= 1.0e-9; | ||||||
|  |     rat_params.degree   = 14; | ||||||
|  |     rat_params.precision= 50; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct EvolParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EvolParameters, | ||||||
|  |                                   Integer, StartTrajectory, | ||||||
|  |                                   Integer, Trajectories, | ||||||
|  | 				  Integer, SaveInterval, | ||||||
|  | 				  Integer, Steps, | ||||||
|  |                                   bool, MetropolisTest, | ||||||
|  | 				  std::string, StartingType, | ||||||
|  | 				  std::vector<Integer>, GparityDirs, | ||||||
|  | 				  EOFAparameters, eofa_l, | ||||||
|  | 				  RatQuoParameters, rat_quo_s, | ||||||
|  | 				  RatQuoParameters, rat_quo_DSDR); | ||||||
|  |  | ||||||
|  |   EvolParameters() { | ||||||
|  |     //For initial thermalization; afterwards user should switch Metropolis on and use StartingType=CheckpointStart | ||||||
|  |     MetropolisTest    = false; | ||||||
|  |     StartTrajectory   = 0; | ||||||
|  |     Trajectories      = 50; | ||||||
|  |     SaveInterval = 5; | ||||||
|  |     StartingType      = "ColdStart"; | ||||||
|  |     GparityDirs.resize(3, 1); //1 for G-parity, 0 for periodic | ||||||
|  |     Steps = 5; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | bool fileExists(const std::string &fn){ | ||||||
|  |   std::ifstream f(fn); | ||||||
|  |   return f.good(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct LanczosParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParameters, | ||||||
|  | 				  double, alpha, | ||||||
|  | 				  double, beta, | ||||||
|  | 				  double, mu, | ||||||
|  | 				  int, ord, | ||||||
|  | 				  int, n_stop, | ||||||
|  | 				  int, n_want, | ||||||
|  | 				  int, n_use, | ||||||
|  | 				  double, tolerance); | ||||||
|  |  | ||||||
|  |   LanczosParameters() { | ||||||
|  |     alpha = 35; | ||||||
|  |     beta = 5; | ||||||
|  |     mu = 0; | ||||||
|  |     ord = 100; | ||||||
|  |     n_stop = 10; | ||||||
|  |     n_want = 10; | ||||||
|  |     n_use = 15; | ||||||
|  |     tolerance = 1e-6; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionActionD, typename FermionFieldD> | ||||||
|  | void computeEigenvalues(std::string param_file, | ||||||
|  | 			GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 			FermionActionD &action, GridParallelRNG &rng){ | ||||||
|  |    | ||||||
|  |   LanczosParameters params; | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "LanczosParameters", params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "LanczosParameters", params); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   action.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   SchurDiagMooeeOperator<FermionActionD, FermionFieldD> hermop(action); | ||||||
|  |   PlainHermOp<FermionFieldD> hermop_wrap(hermop); | ||||||
|  |   //ChebyshevLanczos<FermionFieldD> Cheb(params.alpha, params.beta, params.mu, params.ord); | ||||||
|  |   assert(params.mu == 0.0); | ||||||
|  |  | ||||||
|  |   Chebyshev<FermionFieldD> Cheb(params.beta*params.beta, params.alpha*params.alpha, params.ord+1); | ||||||
|  |   FunctionHermOp<FermionFieldD> Cheb_wrap(Cheb, hermop); | ||||||
|  |  | ||||||
|  |   std::cout << "IRL: alpha=" << params.alpha << " beta=" << params.beta << " mu=" << params.mu << " ord=" << params.ord << std::endl; | ||||||
|  |   ImplicitlyRestartedLanczos<FermionFieldD> IRL(Cheb_wrap, hermop_wrap, params.n_stop, params.n_want, params.n_use, params.tolerance, 10000); | ||||||
|  |  | ||||||
|  |   std::vector<RealD> eval(params.n_use); | ||||||
|  |   std::vector<FermionFieldD> evec(params.n_use, rbGrid); | ||||||
|  |   int Nconv; | ||||||
|  |   IRL.calc(eval, evec, gauss_o, Nconv); | ||||||
|  |  | ||||||
|  |   std::cout << "Eigenvalues:" << std::endl; | ||||||
|  |   for(int i=0;i<params.n_want;i++){ | ||||||
|  |     std::cout << i << " " << eval[i] << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Check the quality of the RHMC approx | ||||||
|  | //action_or_md toggles checking the action (0), MD (1) or both (2) setups | ||||||
|  | template<typename FermionActionD, typename FermionFieldD, typename RHMCtype> | ||||||
|  | void checkRHMC(GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 	       FermionActionD &numOp, FermionActionD &denOp, RHMCtype &rhmc, GridParallelRNG &rng, | ||||||
|  | 	       int inv_pow, const std::string &quark_descr, int action_or_md){ | ||||||
|  |   assert(action_or_md == 0 || action_or_md == 1 || action_or_md == 2); | ||||||
|  |    | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   numOp.ImportGauge(latt); | ||||||
|  |   denOp.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> MdagM(numOp); | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> VdagV(denOp); | ||||||
|  |  | ||||||
|  |   PowerMethod<FermionFieldD> power_method; | ||||||
|  |   RealD lambda_max; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Get RHMC high bound approx for " << quark_descr << " numerator" << std::endl; | ||||||
|  |  | ||||||
|  |   lambda_max = power_method(MdagM,gauss_o); | ||||||
|  |   std::cout << GridLogMessage << "Got lambda_max "<<lambda_max<<std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Get RHMC high bound approx for " << quark_descr << " denominator" << std::endl; | ||||||
|  |   lambda_max = power_method(VdagV,gauss_o); | ||||||
|  |   std::cout << GridLogMessage << "Got lambda_max "<<lambda_max<<std::endl; | ||||||
|  |  | ||||||
|  |   if(action_or_md == 0 || action_or_md == 2){ | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerAction); //use large tolerance to prevent exit on fail; we are trying to tune here! | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout << "-------------------------------------------------------------------------------" << std::endl; | ||||||
|  |  | ||||||
|  |   if(action_or_md == 1 || action_or_md == 2){ | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerMD);  | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void checkEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 	       GridCartesian* FGrid, GridParallelRNG &rng, const LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA action/bounds check" << std::endl; | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   RealD scale = std::sqrt(0.5); | ||||||
|  |   gaussian(rng,eta); eta = eta * scale; | ||||||
|  |  | ||||||
|  |   //Use the inbuilt check | ||||||
|  |   EOFA.refresh(latt, eta); | ||||||
|  |   EOFA.S(latt); | ||||||
|  |   std::cout << GridLogMessage << "Finished EOFA upper action/bounds check" << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | class EOFAlinop: public LinearOperatorBase<typename FermionImplPolicy::FermionField>{ | ||||||
|  |   ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA; | ||||||
|  |   LatticeGaugeFieldD &U; | ||||||
|  | public: | ||||||
|  |   EOFAlinop(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, LatticeGaugeFieldD &U): EOFA(EOFA), U(U){} | ||||||
|  |  | ||||||
|  |   typedef typename FermionImplPolicy::FermionField Field; | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); }  | ||||||
|  |  | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ assert(0); } | ||||||
|  |   void HermOp(const Field &in, Field &out){ EOFA.Meofa(U, in, out); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void upperBoundEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 		    GridCartesian* FGrid, GridParallelRNG &rng, LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA upper bound compute" << std::endl; | ||||||
|  |   EOFAlinop<FermionImplPolicy> linop(EOFA, latt); | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   gaussian(rng,eta); | ||||||
|  |   PowerMethod<typename FermionImplPolicy::FermionField> power_method; | ||||||
|  |   auto lambda_max = power_method(linop,eta); | ||||||
|  |   std::cout << GridLogMessage << "Upper bound of EOFA operator " << lambda_max << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Applications of M^{-1} cost the same as M for EOFA! | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | class EOFAinvLinop: public LinearOperatorBase<typename FermionImplPolicy::FermionField>{ | ||||||
|  |   ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA; | ||||||
|  |   LatticeGaugeFieldD &U; | ||||||
|  | public: | ||||||
|  |   EOFAinvLinop(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, LatticeGaugeFieldD &U): EOFA(EOFA), U(U){} | ||||||
|  |  | ||||||
|  |   typedef typename FermionImplPolicy::FermionField Field; | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); }  | ||||||
|  |  | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ assert(0); } | ||||||
|  |   void HermOp(const Field &in, Field &out){ EOFA.MeofaInv(U, in, out); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void lowerBoundEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 		    GridCartesian* FGrid, GridParallelRNG &rng, LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA lower bound compute using power method on M^{-1}. Inverse of highest eigenvalue is the lowest eigenvalue of M" << std::endl; | ||||||
|  |   EOFAinvLinop<FermionImplPolicy> linop(EOFA, latt); | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   gaussian(rng,eta); | ||||||
|  |   PowerMethod<typename FermionImplPolicy::FermionField> power_method; | ||||||
|  |   auto lambda_max = power_method(linop,eta); | ||||||
|  |   std::cout << GridLogMessage << "Lower bound of EOFA operator " << 1./lambda_max << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  |   int threads = GridThread::GetThreads(); | ||||||
|  |   // here make a routine to print all the relevant information on the run | ||||||
|  |   std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||||
|  |  | ||||||
|  |   std::string param_file = "params.xml"; | ||||||
|  |   bool file_load_check = false; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--param_file"){ | ||||||
|  |       assert(i!=argc-1); | ||||||
|  |       param_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_check"){ //check the fields load correctly and pass checksum/plaquette repro | ||||||
|  |       file_load_check = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Read the user parameters | ||||||
|  |   EvolParameters user_params; | ||||||
|  |    | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "Params", user_params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     { | ||||||
|  |       Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |       write(wr, "Params", user_params); | ||||||
|  |     } | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Check the parameters | ||||||
|  |   if(user_params.GparityDirs.size() != Nd-1){ | ||||||
|  |     std::cerr << "Error in input parameters: expect GparityDirs to have size = " << Nd-1 << std::endl; | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<Nd-1;i++) | ||||||
|  |     if(user_params.GparityDirs[i] != 0 && user_params.GparityDirs[i] != 1){ | ||||||
|  |       std::cerr << "Error in input parameters: expect GparityDirs values to be 0 (periodic) or 1 (G-parity)" << std::endl; | ||||||
|  |       exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   typedef GparityMobiusEOFAFermionD EOFAactionD; | ||||||
|  |   typedef GparityMobiusFermionD FermionActionD; | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   typedef typename FermionActionD::FermionField FermionFieldD; | ||||||
|  |  | ||||||
|  |   typedef GparityMobiusEOFAFermionF EOFAactionF; | ||||||
|  |   typedef GparityMobiusFermionF FermionActionF; | ||||||
|  |   typedef typename FermionActionF::Impl_t FermionImplPolicyF; | ||||||
|  |   typedef typename FermionActionF::FermionField FermionFieldF; | ||||||
|  |  | ||||||
|  |   typedef GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction<FermionImplPolicyD,FermionImplPolicyF> MixedPrecRHMC; | ||||||
|  |   typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicyD> DoublePrecRHMC; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   IntegratorParameters MD; | ||||||
|  |   typedef ConjugateHMCRunnerD<MinimumNorm2> HMCWrapper; //NB: This is the "Omelyan integrator" | ||||||
|  |   typedef HMCWrapper::ImplPolicy GaugeImplPolicy; | ||||||
|  |   MD.name    = std::string("MinimumNorm2"); | ||||||
|  |   MD.MDsteps = user_params.Steps; | ||||||
|  |   MD.trajL   = 1.0; | ||||||
|  |  | ||||||
|  |   HMCparameters HMCparams; | ||||||
|  |   HMCparams.StartTrajectory  = user_params.StartTrajectory; | ||||||
|  |   HMCparams.Trajectories     = user_params.Trajectories; | ||||||
|  |   HMCparams.NoMetropolisUntil= 0; | ||||||
|  |   HMCparams.StartingType     = user_params.StartingType; | ||||||
|  |   HMCparams.MetropolisTest = user_params.MetropolisTest; | ||||||
|  |   HMCparams.MD = MD; | ||||||
|  |   HMCWrapper TheHMC(HMCparams); | ||||||
|  |  | ||||||
|  |   // Grid from the command line arguments --grid and --mpi | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); // use default simd lanes decomposition | ||||||
|  |  | ||||||
|  |   CheckpointerParameters CPparams; | ||||||
|  |   CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   CPparams.rng_prefix    = "ckpoint_rng"; | ||||||
|  |   CPparams.saveInterval  = user_params.SaveInterval; | ||||||
|  |   CPparams.format        = "IEEE64BIG"; | ||||||
|  |   TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   //Note that checkpointing saves the RNG state so that this initialization is required only for the very first configuration | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   typedef PlaquetteMod<GaugeImplPolicy> PlaqObs; | ||||||
|  |   TheHMC.Resources.AddObservable<PlaqObs>(); | ||||||
|  |   ////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   const int Ls      = 12; | ||||||
|  |   Real beta         = 1.75; | ||||||
|  |   Real light_mass   = 0.0042; //240 MeV | ||||||
|  |   Real strange_mass = 0.045; | ||||||
|  |   Real pv_mass      = 1.0; | ||||||
|  |   RealD M5  = 1.8; | ||||||
|  |   RealD mobius_scale = 32./12.; //b+c | ||||||
|  |  | ||||||
|  |   RealD mob_bmc = 1.0; | ||||||
|  |   RealD mob_b = (mobius_scale + mob_bmc)/2.; | ||||||
|  |   RealD mob_c = (mobius_scale - mob_bmc)/2.; | ||||||
|  |  | ||||||
|  |   //Setup the Grids | ||||||
|  |   auto UGridD   = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto UrbGridD = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |   auto FGridD     = SpaceTimeGrid::makeFiveDimGrid(Ls,UGridD); | ||||||
|  |   auto FrbGridD   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGridD); | ||||||
|  |  | ||||||
|  |   GridCartesian* UGridF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* UrbGridF = SpaceTimeGrid::makeFourDimRedBlackGrid(UGridF); | ||||||
|  |   auto FGridF     = SpaceTimeGrid::makeFiveDimGrid(Ls,UGridF); | ||||||
|  |   auto FrbGridF   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGridF); | ||||||
|  |  | ||||||
|  |   ConjugateIwasakiGaugeActionD GaugeAction(beta); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeFieldD Ud(UGridD); | ||||||
|  |   LatticeGaugeFieldF Uf(UGridF); | ||||||
|  |   | ||||||
|  |   //Setup the BCs | ||||||
|  |   FermionActionD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = user_params.GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |  | ||||||
|  |   std::vector<int> dirs4(Nd); | ||||||
|  |   for(int i=0;i<Nd-1;i++) dirs4[i] = user_params.GparityDirs[i]; | ||||||
|  |   dirs4[Nd-1] = 0; //periodic gauge BC in time | ||||||
|  |  | ||||||
|  |   GaugeImplPolicy::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   //Run optional gauge field checksum checker and exit | ||||||
|  |   if(file_load_check){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Collect actions | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level1(1); //light quark + strange quark | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level2(1); //DSDR | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level3(8); //gauge (8 increments per step) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Light EOFA action | ||||||
|  |   // have to be careful with the parameters, cf. Test_dwf_gpforce_eofa.cc | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   EOFAactionD LopD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, light_mass, light_mass, pv_mass, 0.0, -1, M5, mob_b, mob_c, Params); | ||||||
|  |   EOFAactionF LopF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, light_mass, light_mass, pv_mass, 0.0, -1, M5, mob_b, mob_c, Params); | ||||||
|  |   EOFAactionD RopD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, pv_mass, light_mass, pv_mass, -1.0, 1, M5, mob_b, mob_c, Params); | ||||||
|  |   EOFAactionF RopF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, pv_mass, light_mass, pv_mass, -1.0, 1, M5, mob_b, mob_c, Params); | ||||||
|  |  | ||||||
|  |   typedef SchurDiagMooeeOperator<EOFAactionD,FermionFieldD> EOFAschuropD; | ||||||
|  |   typedef SchurDiagMooeeOperator<EOFAactionF,FermionFieldF> EOFAschuropF; | ||||||
|  |    | ||||||
|  |   EOFAschuropD linopL_D(LopD); | ||||||
|  |   EOFAschuropD linopR_D(RopD); | ||||||
|  |  | ||||||
|  |   EOFAschuropF linopL_F(LopF); | ||||||
|  |   EOFAschuropF linopR_F(RopF); | ||||||
|  |  | ||||||
|  |   typedef MixedPrecisionConjugateGradientOperatorFunction<EOFAactionD, EOFAactionF, EOFAschuropD, EOFAschuropF> EOFA_mxCG; | ||||||
|  |  | ||||||
|  |   EOFA_mxCG ActionMCG_L(user_params.eofa_l.action_tolerance, 10000, 1000, UGridF, FrbGridF, LopF, LopD, linopL_F, linopL_D); | ||||||
|  |   ActionMCG_L.InnerTolerance = user_params.eofa_l.action_mixcg_inner_tolerance; | ||||||
|  |    | ||||||
|  |   EOFA_mxCG ActionMCG_R(user_params.eofa_l.action_tolerance, 10000, 1000, UGridF, FrbGridF, RopF, RopD, linopR_F, linopR_D); | ||||||
|  |   ActionMCG_R.InnerTolerance = user_params.eofa_l.action_mixcg_inner_tolerance; | ||||||
|  |  | ||||||
|  |   EOFA_mxCG DerivMCG_L(user_params.eofa_l.md_tolerance, 10000, 1000, UGridF, FrbGridF, LopF, LopD, linopL_F, linopL_D); | ||||||
|  |   DerivMCG_L.InnerTolerance = user_params.eofa_l.md_mixcg_inner_tolerance; | ||||||
|  |  | ||||||
|  |   EOFA_mxCG DerivMCG_R(user_params.eofa_l.md_tolerance, 10000, 1000, UGridF, FrbGridF, RopF, RopD, linopR_F, linopR_D); | ||||||
|  |   DerivMCG_R.InnerTolerance = user_params.eofa_l.md_mixcg_inner_tolerance; | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << "Set EOFA action solver action tolerance outer=" << ActionMCG_L.Tolerance << " inner=" << ActionMCG_L.InnerTolerance << std::endl; | ||||||
|  |   std::cout << GridLogMessage << "Set EOFA MD solver tolerance outer=" << DerivMCG_L.Tolerance << " inner=" << DerivMCG_L.InnerTolerance << std::endl; | ||||||
|  |  | ||||||
|  |   ConjugateGradient<FermionFieldD>      ActionCG(user_params.eofa_l.action_tolerance, 10000); | ||||||
|  |   ConjugateGradient<FermionFieldD>  DerivativeCG(user_params.eofa_l.md_tolerance, 10000); | ||||||
|  |  | ||||||
|  |   // ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicyD> EOFA(LopD, RopD,  | ||||||
|  |   // 								   ActionCG, ActionCG, ActionCG,  | ||||||
|  |   // 								   DerivativeCG, DerivativeCG,  | ||||||
|  |   // 								   user_params.eofa_l.rat_params, true); | ||||||
|  |  | ||||||
|  |   // ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicyD> EOFA(LopD, RopD,  | ||||||
|  |   // 								   ActionMCG_L, ActionMCG_R,  | ||||||
|  |   // 								   ActionMCG_L, ActionMCG_R,  | ||||||
|  |   // 								   DerivMCG_L, DerivMCG_R,  | ||||||
|  |   // 								   user_params.eofa_l.rat_params, true); | ||||||
|  |  | ||||||
|  |   ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction<FermionImplPolicyD, FermionImplPolicyF> EOFA(LopF, RopF, | ||||||
|  | 													LopD, RopD,  | ||||||
|  | 													ActionMCG_L, ActionMCG_R,  | ||||||
|  | 													ActionMCG_L, ActionMCG_R,  | ||||||
|  | 													DerivMCG_L, DerivMCG_R,  | ||||||
|  | 													user_params.eofa_l.rat_params, true); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   Level1.push_back(&EOFA); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Strange action | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   FermionActionD Numerator_sD(Ud,*FGridD,*FrbGridD,*UGridD,*UrbGridD,strange_mass,M5,mob_b,mob_c,Params); | ||||||
|  |   FermionActionD Denominator_sD(Ud,*FGridD,*FrbGridD,*UGridD,*UrbGridD, pv_mass,M5,mob_b,mob_c,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_sF(Uf,*FGridF,*FrbGridF,*UGridF,*UrbGridF,strange_mass,M5,mob_b,mob_c,Params); | ||||||
|  |   FermionActionF Denominator_sF(Uf,*FGridF,*FrbGridF,*UGridF,*UrbGridF, pv_mass,M5,mob_b,mob_c,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_s; | ||||||
|  |   rat_act_params_s.inv_pow  = 4; // (M^dag M)^{1/4} | ||||||
|  |   rat_act_params_s.precision= 60; | ||||||
|  |   rat_act_params_s.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_s.Export(rat_act_params_s); | ||||||
|  |   std::cout << GridLogMessage << " Heavy quark bounds check every " << rat_act_params_s.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   //MixedPrecRHMC Quotient_s(Denominator_sD, Numerator_sD, Denominator_sF, Numerator_sF, rat_act_params_s, user_params.rat_quo_s.reliable_update_freq);  | ||||||
|  |   DoublePrecRHMC Quotient_s(Denominator_sD, Numerator_sD, rat_act_params_s);  | ||||||
|  |   Level1.push_back(&Quotient_s);   | ||||||
|  |  | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   // DSDR action | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   RealD dsdr_mass=-1.8;    | ||||||
|  |   //Use same DSDR twists as https://arxiv.org/pdf/1208.4412.pdf | ||||||
|  |   RealD dsdr_epsilon_f = 0.02; //numerator (in determinant) | ||||||
|  |   RealD dsdr_epsilon_b = 0.5;  | ||||||
|  |   GparityWilsonTMFermionD Numerator_DSDR_D(Ud, *UGridD, *UrbGridD, dsdr_mass, dsdr_epsilon_f, Params); | ||||||
|  |   GparityWilsonTMFermionF Numerator_DSDR_F(Uf, *UGridF, *UrbGridF, dsdr_mass, dsdr_epsilon_f, Params); | ||||||
|  |  | ||||||
|  |   GparityWilsonTMFermionD Denominator_DSDR_D(Ud, *UGridD, *UrbGridD, dsdr_mass, dsdr_epsilon_b, Params); | ||||||
|  |   GparityWilsonTMFermionF Denominator_DSDR_F(Uf, *UGridF, *UrbGridF, dsdr_mass, dsdr_epsilon_b, Params); | ||||||
|  |   | ||||||
|  |   RationalActionParams rat_act_params_DSDR; | ||||||
|  |   rat_act_params_DSDR.inv_pow  = 2; // (M^dag M)^{1/2} | ||||||
|  |   rat_act_params_DSDR.precision= 60; | ||||||
|  |   rat_act_params_DSDR.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_DSDR.Export(rat_act_params_DSDR); | ||||||
|  |   std::cout << GridLogMessage << "DSDR quark bounds check every " << rat_act_params_DSDR.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   DoublePrecRHMC Quotient_DSDR(Denominator_DSDR_D, Numerator_DSDR_D, rat_act_params_DSDR); | ||||||
|  |   Level2.push_back(&Quotient_DSDR); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Gauge action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   Level3.push_back(&GaugeAction); | ||||||
|  |  | ||||||
|  |   TheHMC.TheAction.push_back(Level1); | ||||||
|  |   TheHMC.TheAction.push_back(Level2); | ||||||
|  |   TheHMC.TheAction.push_back(Level3); | ||||||
|  |   std::cout << GridLogMessage << " Action complete "<< std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Action tuning | ||||||
|  |   bool  | ||||||
|  |     tune_rhmc_s=false, eigenrange_s=false,  | ||||||
|  |     tune_rhmc_DSDR=false, eigenrange_DSDR=false,  | ||||||
|  |     check_eofa=false,  | ||||||
|  |     upper_bound_eofa=false, lower_bound_eofa(false); | ||||||
|  |  | ||||||
|  |   std::string lanc_params_s; | ||||||
|  |   std::string lanc_params_DSDR; | ||||||
|  |   int tune_rhmc_s_action_or_md; | ||||||
|  |   int tune_rhmc_DSDR_action_or_md; | ||||||
|  |  | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--tune_rhmc_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       tune_rhmc_s=true; | ||||||
|  |       tune_rhmc_s_action_or_md = std::stoi(argv[i+1]); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_s=true; | ||||||
|  |       lanc_params_s = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--tune_rhmc_DSDR"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       tune_rhmc_DSDR=true; | ||||||
|  |       tune_rhmc_DSDR_action_or_md = std::stoi(argv[i+1]); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_DSDR"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_DSDR=true; | ||||||
|  |       lanc_params_DSDR = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--check_eofa") check_eofa = true; | ||||||
|  |     else if(sarg == "--upper_bound_eofa") upper_bound_eofa = true; | ||||||
|  |     else if(sarg == "--lower_bound_eofa") lower_bound_eofa = true; | ||||||
|  |   } | ||||||
|  |   if(tune_rhmc_s || eigenrange_s || tune_rhmc_DSDR || eigenrange_DSDR ||check_eofa || upper_bound_eofa || lower_bound_eofa) { | ||||||
|  |     std::cout << GridLogMessage << "Running checks" << std::endl; | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << "EOFA action solver action tolerance outer=" << ActionMCG_L.Tolerance << " inner=" << ActionMCG_L.InnerTolerance << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "EOFA MD solver tolerance outer=" << DerivMCG_L.Tolerance << " inner=" << DerivMCG_L.InnerTolerance << std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if(check_eofa) checkEOFA(EOFA, FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(upper_bound_eofa) upperBoundEOFA(EOFA, FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(lower_bound_eofa) lowerBoundEOFA(EOFA, FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(eigenrange_s) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_s, FGridD, FrbGridD, Ud, Numerator_sD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_s) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_s)>(FGridD, FrbGridD, Ud, Numerator_sD, Denominator_sD, Quotient_s, TheHMC.Resources.GetParallelRNG(), 4, "strange",  tune_rhmc_s_action_or_md); | ||||||
|  |     if(eigenrange_DSDR) computeEigenvalues<GparityWilsonTMFermionD, GparityWilsonTMFermionD::FermionField>(lanc_params_DSDR, UGridD, UrbGridD, Ud, Numerator_DSDR_D, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_DSDR) checkRHMC<GparityWilsonTMFermionD, GparityWilsonTMFermionD::FermionField, decltype(Quotient_DSDR)>(UGridD, UrbGridD, Ud, Numerator_DSDR_D, Denominator_DSDR_D, Quotient_DSDR, TheHMC.Resources.GetParallelRNG(), 2, "DSDR", tune_rhmc_DSDR_action_or_md); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Run the HMC | ||||||
|  |   std::cout << GridLogMessage << " Running the HMC "<< std::endl; | ||||||
|  |   TheHMC.Run(); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } // main | ||||||
							
								
								
									
										918
									
								
								HMC/Mobius2p1fIDSDRGparityEOFA_40ID.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										918
									
								
								HMC/Mobius2p1fIDSDRGparityEOFA_40ID.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,918 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./HMC/Mobius2p1fIDSDRGparityEOFA.cc | ||||||
|  |  | ||||||
|  | Copyright (C) 2015-2016 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  | Author: Peter Boyle <pabobyle@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; | ||||||
|  |  | ||||||
|  | //Production binary for the 40ID G-parity ensemble | ||||||
|  |  | ||||||
|  | struct RatQuoParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(RatQuoParameters, | ||||||
|  | 				  double, bnd_lo, | ||||||
|  | 				  double, bnd_hi, | ||||||
|  | 				  Integer, action_degree, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  Integer, md_degree, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  Integer, reliable_update_freq, | ||||||
|  | 				  Integer, bnd_check_freq); | ||||||
|  |   RatQuoParameters() {  | ||||||
|  |     bnd_lo = 1e-2; | ||||||
|  |     bnd_hi = 30; | ||||||
|  |     action_degree = 10; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_degree = 10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     bnd_check_freq = 20; | ||||||
|  |     reliable_update_freq = 50; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Export(RationalActionParams &into) const{ | ||||||
|  |     into.lo = bnd_lo; | ||||||
|  |     into.hi = bnd_hi; | ||||||
|  |     into.action_degree = action_degree; | ||||||
|  |     into.action_tolerance = action_tolerance; | ||||||
|  |     into.md_degree = md_degree; | ||||||
|  |     into.md_tolerance = md_tolerance; | ||||||
|  |     into.BoundsCheckFreq = bnd_check_freq; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct EOFAparameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EOFAparameters, | ||||||
|  | 				  OneFlavourRationalParams, rat_params, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  double, action_mixcg_inner_tolerance, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  double, md_mixcg_inner_tolerance); | ||||||
|  |  | ||||||
|  |   EOFAparameters() {  | ||||||
|  |     action_mixcg_inner_tolerance = 1e-8; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     md_mixcg_inner_tolerance = 1e-8; | ||||||
|  |  | ||||||
|  |     rat_params.lo = 1.0; | ||||||
|  |     rat_params.hi = 25.0; | ||||||
|  |     rat_params.MaxIter  = 50000; | ||||||
|  |     rat_params.tolerance= 1.0e-9; | ||||||
|  |     rat_params.degree   = 14; | ||||||
|  |     rat_params.precision= 50; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct EvolParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EvolParameters, | ||||||
|  |                                   Integer, StartTrajectory, | ||||||
|  |                                   Integer, Trajectories, | ||||||
|  | 				  Integer, SaveInterval, | ||||||
|  | 				  Integer, Steps, | ||||||
|  | 				  RealD, TrajectoryLength, | ||||||
|  |                                   bool, MetropolisTest, | ||||||
|  | 				  std::string, StartingType, | ||||||
|  | 				  std::vector<Integer>, GparityDirs, | ||||||
|  | 				  std::vector<EOFAparameters>, eofa_l, | ||||||
|  | 				  RatQuoParameters, rat_quo_s, | ||||||
|  | 				  RatQuoParameters, rat_quo_DSDR); | ||||||
|  |  | ||||||
|  |   EvolParameters() { | ||||||
|  |     //For initial thermalization; afterwards user should switch Metropolis on and use StartingType=CheckpointStart | ||||||
|  |     MetropolisTest    = false; | ||||||
|  |     StartTrajectory   = 0; | ||||||
|  |     Trajectories      = 50; | ||||||
|  |     SaveInterval = 5; | ||||||
|  |     StartingType      = "ColdStart"; | ||||||
|  |     GparityDirs.resize(3, 1); //1 for G-parity, 0 for periodic | ||||||
|  |     Steps = 5; | ||||||
|  |     TrajectoryLength = 1.0; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | bool fileExists(const std::string &fn){ | ||||||
|  |   std::ifstream f(fn); | ||||||
|  |   return f.good(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct LanczosParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParameters, | ||||||
|  | 				  double, alpha, | ||||||
|  | 				  double, beta, | ||||||
|  | 				  double, mu, | ||||||
|  | 				  int, ord, | ||||||
|  | 				  int, n_stop, | ||||||
|  | 				  int, n_want, | ||||||
|  | 				  int, n_use, | ||||||
|  | 				  double, tolerance); | ||||||
|  |  | ||||||
|  |   LanczosParameters() { | ||||||
|  |     alpha = 35; | ||||||
|  |     beta = 5; | ||||||
|  |     mu = 0; | ||||||
|  |     ord = 100; | ||||||
|  |     n_stop = 10; | ||||||
|  |     n_want = 10; | ||||||
|  |     n_use = 15; | ||||||
|  |     tolerance = 1e-6; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionActionD, typename FermionFieldD> | ||||||
|  | void computeEigenvalues(std::string param_file, | ||||||
|  | 			GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 			FermionActionD &action, GridParallelRNG &rng){ | ||||||
|  |    | ||||||
|  |   LanczosParameters params; | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "LanczosParameters", params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "LanczosParameters", params); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   action.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   SchurDiagMooeeOperator<FermionActionD, FermionFieldD> hermop(action); | ||||||
|  |   PlainHermOp<FermionFieldD> hermop_wrap(hermop); | ||||||
|  |   //ChebyshevLanczos<FermionFieldD> Cheb(params.alpha, params.beta, params.mu, params.ord); | ||||||
|  |   assert(params.mu == 0.0); | ||||||
|  |  | ||||||
|  |   Chebyshev<FermionFieldD> Cheb(params.beta*params.beta, params.alpha*params.alpha, params.ord+1); | ||||||
|  |   FunctionHermOp<FermionFieldD> Cheb_wrap(Cheb, hermop); | ||||||
|  |  | ||||||
|  |   std::cout << "IRL: alpha=" << params.alpha << " beta=" << params.beta << " mu=" << params.mu << " ord=" << params.ord << std::endl; | ||||||
|  |   ImplicitlyRestartedLanczos<FermionFieldD> IRL(Cheb_wrap, hermop_wrap, params.n_stop, params.n_want, params.n_use, params.tolerance, 50000); | ||||||
|  |  | ||||||
|  |   std::vector<RealD> eval(params.n_use); | ||||||
|  |   std::vector<FermionFieldD> evec(params.n_use, rbGrid); | ||||||
|  |   int Nconv; | ||||||
|  |   IRL.calc(eval, evec, gauss_o, Nconv); | ||||||
|  |  | ||||||
|  |   std::cout << "Eigenvalues:" << std::endl; | ||||||
|  |   for(int i=0;i<params.n_want;i++){ | ||||||
|  |     std::cout << i << " " << eval[i] << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Check the quality of the RHMC approx | ||||||
|  | //action_or_md toggles checking the action (0), MD (1) or both (2) setups | ||||||
|  | template<typename FermionActionD, typename FermionFieldD, typename RHMCtype> | ||||||
|  | void checkRHMC(GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 	       FermionActionD &numOp, FermionActionD &denOp, RHMCtype &rhmc, GridParallelRNG &rng, | ||||||
|  | 	       int inv_pow, const std::string &quark_descr, int action_or_md){ | ||||||
|  |   assert(action_or_md == 0 || action_or_md == 1 || action_or_md == 2); | ||||||
|  |    | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   numOp.ImportGauge(latt); | ||||||
|  |   denOp.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> MdagM(numOp); | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> VdagV(denOp); | ||||||
|  |  | ||||||
|  |   PowerMethod<FermionFieldD> power_method; | ||||||
|  |   RealD lambda_max; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Get RHMC high bound approx for " << quark_descr << " numerator" << std::endl; | ||||||
|  |  | ||||||
|  |   lambda_max = power_method(MdagM,gauss_o); | ||||||
|  |   std::cout << GridLogMessage << "Got lambda_max "<<lambda_max<<std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Get RHMC high bound approx for " << quark_descr << " denominator" << std::endl; | ||||||
|  |   lambda_max = power_method(VdagV,gauss_o); | ||||||
|  |   std::cout << GridLogMessage << "Got lambda_max "<<lambda_max<<std::endl; | ||||||
|  |  | ||||||
|  |   if(action_or_md == 0 || action_or_md == 2){ | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 50000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerAction); //use large tolerance to prevent exit on fail; we are trying to tune here! | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 50000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 50000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 50000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout << "-------------------------------------------------------------------------------" << std::endl; | ||||||
|  |  | ||||||
|  |   if(action_or_md == 1 || action_or_md == 2){ | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 50000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerMD);  | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 50000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 50000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 50000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void checkEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 	       GridCartesian* FGrid, GridParallelRNG &rng, const LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA action/bounds check" << std::endl; | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   RealD scale = std::sqrt(0.5); | ||||||
|  |   gaussian(rng,eta); eta = eta * scale; | ||||||
|  |  | ||||||
|  |   //Use the inbuilt check | ||||||
|  |   EOFA.refresh(latt, eta); | ||||||
|  |   EOFA.S(latt); | ||||||
|  |   std::cout << GridLogMessage << "Finished EOFA upper action/bounds check" << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | class EOFAlinop: public LinearOperatorBase<typename FermionImplPolicy::FermionField>{ | ||||||
|  |   ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA; | ||||||
|  |   LatticeGaugeFieldD &U; | ||||||
|  | public: | ||||||
|  |   EOFAlinop(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, LatticeGaugeFieldD &U): EOFA(EOFA), U(U){} | ||||||
|  |  | ||||||
|  |   typedef typename FermionImplPolicy::FermionField Field; | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); }  | ||||||
|  |  | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ assert(0); } | ||||||
|  |   void HermOp(const Field &in, Field &out){ EOFA.Meofa(U, in, out); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void upperBoundEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 		    GridCartesian* FGrid, GridParallelRNG &rng, LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA upper bound compute" << std::endl; | ||||||
|  |   EOFAlinop<FermionImplPolicy> linop(EOFA, latt); | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   gaussian(rng,eta); | ||||||
|  |   PowerMethod<typename FermionImplPolicy::FermionField> power_method; | ||||||
|  |   auto lambda_max = power_method(linop,eta); | ||||||
|  |   std::cout << GridLogMessage << "Upper bound of EOFA operator " << lambda_max << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Applications of M^{-1} cost the same as M for EOFA! | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | class EOFAinvLinop: public LinearOperatorBase<typename FermionImplPolicy::FermionField>{ | ||||||
|  |   ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA; | ||||||
|  |   LatticeGaugeFieldD &U; | ||||||
|  | public: | ||||||
|  |   EOFAinvLinop(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, LatticeGaugeFieldD &U): EOFA(EOFA), U(U){} | ||||||
|  |  | ||||||
|  |   typedef typename FermionImplPolicy::FermionField Field; | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); }  | ||||||
|  |  | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ assert(0); } | ||||||
|  |   void HermOp(const Field &in, Field &out){ EOFA.MeofaInv(U, in, out); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void lowerBoundEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 		    GridCartesian* FGrid, GridParallelRNG &rng, LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA lower bound compute using power method on M^{-1}. Inverse of highest eigenvalue is the lowest eigenvalue of M" << std::endl; | ||||||
|  |   EOFAinvLinop<FermionImplPolicy> linop(EOFA, latt); | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   gaussian(rng,eta); | ||||||
|  |   PowerMethod<typename FermionImplPolicy::FermionField> power_method; | ||||||
|  |   auto lambda_max = power_method(linop,eta); | ||||||
|  |   std::cout << GridLogMessage << "Lower bound of EOFA operator " << 1./lambda_max << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   template<class FermionOperatorD, class FermionOperatorF, class SchurOperatorD, class  SchurOperatorF>  | ||||||
|  |   class MixedPrecisionReliableUpdateConjugateGradientOperatorFunction : public OperatorFunction<typename FermionOperatorD::FermionField> { | ||||||
|  |   public: | ||||||
|  |     typedef typename FermionOperatorD::FermionField FieldD; | ||||||
|  |     typedef typename FermionOperatorF::FermionField FieldF; | ||||||
|  |  | ||||||
|  |     using OperatorFunction<FieldD>::operator(); | ||||||
|  |  | ||||||
|  |     RealD Tolerance; | ||||||
|  |     Integer MaxIterations; | ||||||
|  |  | ||||||
|  |     RealD Delta; //reliable update parameter | ||||||
|  |  | ||||||
|  |     GridBase* SinglePrecGrid4; //Grid for single-precision fields | ||||||
|  |     GridBase* SinglePrecGrid5; //Grid for single-precision fields | ||||||
|  |  | ||||||
|  |     FermionOperatorF &FermOpF; | ||||||
|  |     FermionOperatorD &FermOpD;; | ||||||
|  |     SchurOperatorF &LinOpF; | ||||||
|  |     SchurOperatorD &LinOpD; | ||||||
|  |      | ||||||
|  |     MixedPrecisionReliableUpdateConjugateGradientOperatorFunction(RealD tol,  | ||||||
|  | 								  RealD delta, | ||||||
|  | 								  Integer maxit,  | ||||||
|  | 								  GridBase* _sp_grid4,  | ||||||
|  | 								  GridBase* _sp_grid5,  | ||||||
|  | 								  FermionOperatorF &_FermOpF, | ||||||
|  | 								  FermionOperatorD &_FermOpD, | ||||||
|  | 								  SchurOperatorF   &_LinOpF, | ||||||
|  | 								  SchurOperatorD   &_LinOpD):  | ||||||
|  |       LinOpF(_LinOpF), | ||||||
|  |       LinOpD(_LinOpD), | ||||||
|  |       FermOpF(_FermOpF), | ||||||
|  |       FermOpD(_FermOpD), | ||||||
|  |       Tolerance(tol),  | ||||||
|  |       Delta(delta), | ||||||
|  |       MaxIterations(maxit),  | ||||||
|  |       SinglePrecGrid4(_sp_grid4), | ||||||
|  |       SinglePrecGrid5(_sp_grid5) | ||||||
|  |     {  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     void operator()(LinearOperatorBase<FieldD> &LinOpU, const FieldD &src, FieldD &psi) { | ||||||
|  |  | ||||||
|  |       std::cout << GridLogMessage << " Mixed precision reliable CG update 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 | ||||||
|  |       //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |       ConjugateGradientReliableUpdate<FieldD,FieldF> MPCG(Tolerance,MaxIterations,Delta,SinglePrecGrid5,LinOpF,LinOpD); | ||||||
|  |       std::cout << GridLogMessage << "Calling mixed precision reliable update Conjugate Gradient" <<std::endl; | ||||||
|  |       MPCG(src,psi); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main(int argc, char **argv) { | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |   int threads = GridThread::GetThreads(); | ||||||
|  |   // here make a routine to print all the relevant information on the run | ||||||
|  |   std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||||
|  |  | ||||||
|  |   std::string param_file = "params.xml"; | ||||||
|  |   bool file_load_check = false; | ||||||
|  |  | ||||||
|  |   std::string serial_seeds = "1 2 3 4 5"; | ||||||
|  |   std::string parallel_seeds = "6 7 8 9 10"; | ||||||
|  |  | ||||||
|  |   int i=1; | ||||||
|  |   while(i < argc){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--param_file"){ | ||||||
|  |       assert(i!=argc-1); | ||||||
|  |       param_file = argv[i+1]; | ||||||
|  |       i+=2; | ||||||
|  |     }else if(sarg == "--read_check"){ //check the fields load correctly and pass checksum/plaquette repro | ||||||
|  |       file_load_check = true; | ||||||
|  |       i++; | ||||||
|  |     }else if(sarg == "--set_seeds"){ //set the rng seeds. Expects two vector args, e.g.  --set_seeds 1.2.3.4 5.6.7.8 | ||||||
|  |       assert(i < argc-2); | ||||||
|  |       std::vector<int> tmp; | ||||||
|  |       GridCmdOptionIntVector(argv[i+1],tmp); | ||||||
|  |       { | ||||||
|  | 	std::stringstream ss; | ||||||
|  | 	for(int j=0;j<tmp.size()-1;j++) ss << tmp[j] << " "; | ||||||
|  | 	ss << tmp.back(); | ||||||
|  | 	serial_seeds = ss.str(); | ||||||
|  |       } | ||||||
|  |       GridCmdOptionIntVector(argv[i+2],tmp); | ||||||
|  |       { | ||||||
|  | 	std::stringstream ss; | ||||||
|  | 	for(int j=0;j<tmp.size()-1;j++) ss << tmp[j] << " "; | ||||||
|  | 	ss << tmp.back(); | ||||||
|  | 	parallel_seeds = ss.str(); | ||||||
|  |       } | ||||||
|  |       i+=3; | ||||||
|  |       std::cout << GridLogMessage << "Set serial seeds to " << serial_seeds << std::endl; | ||||||
|  |       std::cout << GridLogMessage << "Set parallel seeds to " << parallel_seeds << std::endl; | ||||||
|  |        | ||||||
|  |     }else{ | ||||||
|  |       i++; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |    | ||||||
|  |   //Read the user parameters | ||||||
|  |   EvolParameters user_params; | ||||||
|  |    | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "Params", user_params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     { | ||||||
|  |       Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |       write(wr, "Params", user_params); | ||||||
|  |     } | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Check the parameters | ||||||
|  |   if(user_params.GparityDirs.size() != Nd-1){ | ||||||
|  |     std::cerr << "Error in input parameters: expect GparityDirs to have size = " << Nd-1 << std::endl; | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<Nd-1;i++) | ||||||
|  |     if(user_params.GparityDirs[i] != 0 && user_params.GparityDirs[i] != 1){ | ||||||
|  |       std::cerr << "Error in input parameters: expect GparityDirs values to be 0 (periodic) or 1 (G-parity)" << std::endl; | ||||||
|  |       exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   typedef GparityMobiusEOFAFermionD EOFAactionD; | ||||||
|  |   typedef GparityMobiusFermionD FermionActionD; | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   typedef typename FermionActionD::FermionField FermionFieldD; | ||||||
|  |  | ||||||
|  |   typedef GparityMobiusEOFAFermionF EOFAactionF; | ||||||
|  |   typedef GparityMobiusFermionF FermionActionF; | ||||||
|  |   typedef typename FermionActionF::Impl_t FermionImplPolicyF; | ||||||
|  |   typedef typename FermionActionF::FermionField FermionFieldF; | ||||||
|  |  | ||||||
|  |   typedef GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction<FermionImplPolicyD,FermionImplPolicyF> MixedPrecRHMC; | ||||||
|  |   typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicyD> DoublePrecRHMC; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   IntegratorParameters MD; | ||||||
|  |   typedef ConjugateHMCRunnerD<MinimumNorm2> HMCWrapper; //NB: This is the "Omelyan integrator" | ||||||
|  |   MD.name    = std::string("MinimumNorm2"); | ||||||
|  |  | ||||||
|  |   // typedef ConjugateHMCRunnerD<ForceGradient> HMCWrapper; | ||||||
|  |   // MD.name    = std::string("ForceGradient"); | ||||||
|  |    | ||||||
|  |   MD.MDsteps = user_params.Steps; | ||||||
|  |   MD.trajL   = user_params.TrajectoryLength; | ||||||
|  |  | ||||||
|  |   typedef HMCWrapper::ImplPolicy GaugeImplPolicy; | ||||||
|  |    | ||||||
|  |   HMCparameters HMCparams; | ||||||
|  |   HMCparams.StartTrajectory  = user_params.StartTrajectory; | ||||||
|  |   HMCparams.Trajectories     = user_params.Trajectories; | ||||||
|  |   HMCparams.NoMetropolisUntil= 0; | ||||||
|  |   HMCparams.StartingType     = user_params.StartingType; | ||||||
|  |   HMCparams.MetropolisTest = user_params.MetropolisTest; | ||||||
|  |   HMCparams.MD = MD; | ||||||
|  |   HMCWrapper TheHMC(HMCparams); | ||||||
|  |  | ||||||
|  |   // Grid from the command line arguments --grid and --mpi | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); // use default simd lanes decomposition | ||||||
|  |  | ||||||
|  |   CheckpointerParameters CPparams; | ||||||
|  |   CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   CPparams.rng_prefix    = "ckpoint_rng"; | ||||||
|  |   CPparams.saveInterval  = user_params.SaveInterval; | ||||||
|  |   CPparams.format        = "IEEE64BIG"; | ||||||
|  |   TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   //Note that checkpointing saves the RNG state so that this initialization is required only for the very first configuration | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = serial_seeds; | ||||||
|  |   RNGpar.parallel_seeds = parallel_seeds; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   typedef PlaquetteMod<GaugeImplPolicy> PlaqObs; | ||||||
|  |   TheHMC.Resources.AddObservable<PlaqObs>(); | ||||||
|  |   ////////////////////////////////////////////// | ||||||
|  |   //aiming for ainv=1.723 GeV | ||||||
|  |   //                                  me         bob | ||||||
|  |   //Estimated  a(ml+mres) [40ID] = 0.001305    0.00131 | ||||||
|  |   //           a(mh+mres) [40ID] = 0.035910    0.03529 | ||||||
|  |   //Estimate Ls=12, b+c=2  mres~0.0011 | ||||||
|  |  | ||||||
|  |   //1/24/2022 initial mres measurement gives mres=0.001,  adjusted light quark mass to 0.0003 from 0.0001 | ||||||
|  |    | ||||||
|  |   const int Ls      = 12; | ||||||
|  |   Real beta         = 1.848; | ||||||
|  |   Real light_mass   = 0.0003; | ||||||
|  |   Real strange_mass = 0.0342; | ||||||
|  |   Real pv_mass      = 1.0; | ||||||
|  |   RealD M5  = 1.8; | ||||||
|  |   RealD mobius_scale = 2.; //b+c | ||||||
|  |  | ||||||
|  |   RealD mob_bmc = 1.0; | ||||||
|  |   RealD mob_b = (mobius_scale + mob_bmc)/2.; | ||||||
|  |   RealD mob_c = (mobius_scale - mob_bmc)/2.; | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage | ||||||
|  | 	    << "Ensemble parameters:" << std::endl | ||||||
|  | 	    << "Ls=" << Ls << std::endl | ||||||
|  | 	    << "beta=" << beta << std::endl | ||||||
|  | 	    << "light_mass=" << light_mass << std::endl | ||||||
|  | 	    << "strange_mass=" << strange_mass << std::endl | ||||||
|  | 	    << "mobius_scale=" << mobius_scale << std::endl; | ||||||
|  |    | ||||||
|  |   //Setup the Grids | ||||||
|  |   auto UGridD   = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto UrbGridD = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |   auto FGridD     = SpaceTimeGrid::makeFiveDimGrid(Ls,UGridD); | ||||||
|  |   auto FrbGridD   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGridD); | ||||||
|  |  | ||||||
|  |   GridCartesian* UGridF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* UrbGridF = SpaceTimeGrid::makeFourDimRedBlackGrid(UGridF); | ||||||
|  |   auto FGridF     = SpaceTimeGrid::makeFiveDimGrid(Ls,UGridF); | ||||||
|  |   auto FrbGridF   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGridF); | ||||||
|  |  | ||||||
|  |   ConjugateIwasakiGaugeActionD GaugeAction(beta); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeFieldD Ud(UGridD); | ||||||
|  |   LatticeGaugeFieldF Uf(UGridF); | ||||||
|  |   | ||||||
|  |   //Setup the BCs | ||||||
|  |   FermionActionD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = user_params.GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |  | ||||||
|  |   std::vector<int> dirs4(Nd); | ||||||
|  |   for(int i=0;i<Nd-1;i++) dirs4[i] = user_params.GparityDirs[i]; | ||||||
|  |   dirs4[Nd-1] = 0; //periodic gauge BC in time | ||||||
|  |  | ||||||
|  |   GaugeImplPolicy::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   //Run optional gauge field checksum checker and exit | ||||||
|  |   if(file_load_check){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Collect actions | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level1(1); //light quark + strange quark | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level2(4); //DSDR | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level3(2); //gauge | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Light EOFA action | ||||||
|  |   // have to be careful with the parameters, cf. Test_dwf_gpforce_eofa.cc | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   typedef SchurDiagMooeeOperator<EOFAactionD,FermionFieldD> EOFAschuropD; | ||||||
|  |   typedef SchurDiagMooeeOperator<EOFAactionF,FermionFieldF> EOFAschuropF; | ||||||
|  |   typedef ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction<FermionImplPolicyD, FermionImplPolicyF> EOFAmixPrecPFaction; | ||||||
|  |   typedef MixedPrecisionConjugateGradientOperatorFunction<EOFAactionD, EOFAactionF, EOFAschuropD, EOFAschuropF> EOFA_mxCG; | ||||||
|  |   typedef MixedPrecisionReliableUpdateConjugateGradientOperatorFunction<EOFAactionD, EOFAactionF, EOFAschuropD, EOFAschuropF> EOFA_relupCG; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   std::vector<RealD> eofa_light_masses = { light_mass ,  0.004,   0.016,   0.064,   0.256    }; | ||||||
|  |   std::vector<RealD> eofa_pv_masses =    { 0.004       , 0.016,   0.064,   0.256,   1.0      }; | ||||||
|  |   int n_light_hsb = 5; | ||||||
|  |   assert(user_params.eofa_l.size() == n_light_hsb); | ||||||
|  |    | ||||||
|  |   EOFAmixPrecPFaction* EOFA_pfactions[n_light_hsb]; | ||||||
|  |  | ||||||
|  |   for(int i=0;i<n_light_hsb;i++){ | ||||||
|  |     RealD iml = eofa_light_masses[i]; | ||||||
|  |     RealD ipv = eofa_pv_masses[i]; | ||||||
|  |  | ||||||
|  |     EOFAactionD* LopD = new EOFAactionD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, iml, iml, ipv, 0.0, -1, M5, mob_b, mob_c, Params); | ||||||
|  |     EOFAactionF* LopF = new EOFAactionF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, iml, iml, ipv, 0.0, -1, M5, mob_b, mob_c, Params); | ||||||
|  |     EOFAactionD* RopD = new EOFAactionD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, ipv, iml, ipv, -1.0, 1, M5, mob_b, mob_c, Params); | ||||||
|  |     EOFAactionF* RopF = new EOFAactionF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, ipv, iml, ipv, -1.0, 1, M5, mob_b, mob_c, Params); | ||||||
|  |  | ||||||
|  |     EOFAschuropD* linopL_D = new EOFAschuropD(*LopD); | ||||||
|  |     EOFAschuropD* linopR_D = new EOFAschuropD(*RopD); | ||||||
|  |      | ||||||
|  |     EOFAschuropF* linopL_F = new EOFAschuropF(*LopF); | ||||||
|  |     EOFAschuropF* linopR_F = new EOFAschuropF(*RopF); | ||||||
|  |  | ||||||
|  | #if 1 | ||||||
|  |     //Note reusing user_params.eofa_l.action(|md)_mixcg_inner_tolerance  as Delta for now | ||||||
|  |     EOFA_relupCG* ActionMCG_L = new EOFA_relupCG(user_params.eofa_l[i].action_tolerance, user_params.eofa_l[i].action_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     EOFA_relupCG* ActionMCG_R = new EOFA_relupCG(user_params.eofa_l[i].action_tolerance, user_params.eofa_l[i].action_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |  | ||||||
|  |     EOFA_relupCG* DerivMCG_L = new EOFA_relupCG(user_params.eofa_l[i].md_tolerance, user_params.eofa_l[i].md_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     EOFA_relupCG* DerivMCG_R = new EOFA_relupCG(user_params.eofa_l[i].md_tolerance, user_params.eofa_l[i].md_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |     EOFA_mxCG* ActionMCG_L = new EOFA_mxCG(user_params.eofa_l[i].action_tolerance, 50000, 1000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     ActionMCG_L->InnerTolerance = user_params.eofa_l[i].action_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* ActionMCG_R = new EOFA_mxCG(user_params.eofa_l[i].action_tolerance, 50000, 1000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |     ActionMCG_R->InnerTolerance = user_params.eofa_l[i].action_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* DerivMCG_L = new EOFA_mxCG(user_params.eofa_l[i].md_tolerance, 50000, 1000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     DerivMCG_L->InnerTolerance = user_params.eofa_l[i].md_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* DerivMCG_R = new EOFA_mxCG(user_params.eofa_l[i].md_tolerance, 50000, 1000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |     DerivMCG_R->InnerTolerance = user_params.eofa_l[i].md_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     std::cout << GridLogMessage << "Set EOFA action solver action tolerance outer=" << ActionMCG_L->Tolerance << " inner=" << ActionMCG_L->InnerTolerance << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "Set EOFA MD solver tolerance outer=" << DerivMCG_L->Tolerance << " inner=" << DerivMCG_L->InnerTolerance << std::endl; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     EOFAmixPrecPFaction* EOFA = new EOFAmixPrecPFaction(*LopF, *RopF, | ||||||
|  | 							*LopD, *RopD,  | ||||||
|  | 							*ActionMCG_L, *ActionMCG_R,  | ||||||
|  | 							*ActionMCG_L, *ActionMCG_R,  | ||||||
|  | 							*DerivMCG_L, *DerivMCG_R,  | ||||||
|  | 							user_params.eofa_l[i].rat_params, true); | ||||||
|  |     EOFA_pfactions[i] = EOFA; | ||||||
|  |     Level1.push_back(EOFA); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Strange action | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   FermionActionD Numerator_sD(Ud,*FGridD,*FrbGridD,*UGridD,*UrbGridD,strange_mass,M5,mob_b,mob_c,Params); | ||||||
|  |   FermionActionD Denominator_sD(Ud,*FGridD,*FrbGridD,*UGridD,*UrbGridD, pv_mass,M5,mob_b,mob_c,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_sF(Uf,*FGridF,*FrbGridF,*UGridF,*UrbGridF,strange_mass,M5,mob_b,mob_c,Params); | ||||||
|  |   FermionActionF Denominator_sF(Uf,*FGridF,*FrbGridF,*UGridF,*UrbGridF, pv_mass,M5,mob_b,mob_c,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_s; | ||||||
|  |   rat_act_params_s.inv_pow  = 4; // (M^dag M)^{1/4} | ||||||
|  |   rat_act_params_s.precision= 60; | ||||||
|  |   rat_act_params_s.MaxIter  = 50000; | ||||||
|  |   user_params.rat_quo_s.Export(rat_act_params_s); | ||||||
|  |   std::cout << GridLogMessage << " Heavy quark bounds check every " << rat_act_params_s.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   //MixedPrecRHMC Quotient_s(Denominator_sD, Numerator_sD, Denominator_sF, Numerator_sF, rat_act_params_s, user_params.rat_quo_s.reliable_update_freq);  | ||||||
|  |   DoublePrecRHMC Quotient_s(Denominator_sD, Numerator_sD, rat_act_params_s);  | ||||||
|  |   Level1.push_back(&Quotient_s);   | ||||||
|  |  | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   // DSDR action | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   RealD dsdr_mass=-1.8;    | ||||||
|  |   //Use same DSDR twists as https://arxiv.org/pdf/1208.4412.pdf | ||||||
|  |   RealD dsdr_epsilon_f = 0.02; //numerator (in determinant) | ||||||
|  |   RealD dsdr_epsilon_b = 0.5;  | ||||||
|  |   GparityWilsonTMFermionD Numerator_DSDR_D(Ud, *UGridD, *UrbGridD, dsdr_mass, dsdr_epsilon_f, Params); | ||||||
|  |   GparityWilsonTMFermionF Numerator_DSDR_F(Uf, *UGridF, *UrbGridF, dsdr_mass, dsdr_epsilon_f, Params); | ||||||
|  |  | ||||||
|  |   GparityWilsonTMFermionD Denominator_DSDR_D(Ud, *UGridD, *UrbGridD, dsdr_mass, dsdr_epsilon_b, Params); | ||||||
|  |   GparityWilsonTMFermionF Denominator_DSDR_F(Uf, *UGridF, *UrbGridF, dsdr_mass, dsdr_epsilon_b, Params); | ||||||
|  |   | ||||||
|  |   RationalActionParams rat_act_params_DSDR; | ||||||
|  |   rat_act_params_DSDR.inv_pow  = 2; // (M^dag M)^{1/2} | ||||||
|  |   rat_act_params_DSDR.precision= 60; | ||||||
|  |   rat_act_params_DSDR.MaxIter  = 50000; | ||||||
|  |   user_params.rat_quo_DSDR.Export(rat_act_params_DSDR); | ||||||
|  |   std::cout << GridLogMessage << "DSDR quark bounds check every " << rat_act_params_DSDR.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   DoublePrecRHMC Quotient_DSDR(Denominator_DSDR_D, Numerator_DSDR_D, rat_act_params_DSDR); | ||||||
|  |   Level2.push_back(&Quotient_DSDR); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Gauge action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   Level3.push_back(&GaugeAction); | ||||||
|  |  | ||||||
|  |   TheHMC.TheAction.push_back(Level1); | ||||||
|  |   TheHMC.TheAction.push_back(Level2); | ||||||
|  |   TheHMC.TheAction.push_back(Level3); | ||||||
|  |   std::cout << GridLogMessage << " Action complete "<< std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Action tuning | ||||||
|  |   bool  | ||||||
|  |     tune_rhmc_s=false, eigenrange_s=false,  | ||||||
|  |     tune_rhmc_DSDR=false, eigenrange_DSDR=false,  | ||||||
|  |     check_eofa=false,  | ||||||
|  |     upper_bound_eofa=false, lower_bound_eofa(false); | ||||||
|  |  | ||||||
|  |   std::string lanc_params_s; | ||||||
|  |   std::string lanc_params_DSDR; | ||||||
|  |   int tune_rhmc_s_action_or_md; | ||||||
|  |   int tune_rhmc_DSDR_action_or_md; | ||||||
|  |   int eofa_which_hsb; | ||||||
|  |  | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--tune_rhmc_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       tune_rhmc_s=true; | ||||||
|  |       tune_rhmc_s_action_or_md = std::stoi(argv[i+1]); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_s=true; | ||||||
|  |       lanc_params_s = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--tune_rhmc_DSDR"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       tune_rhmc_DSDR=true; | ||||||
|  |       tune_rhmc_DSDR_action_or_md = std::stoi(argv[i+1]); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_DSDR"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_DSDR=true; | ||||||
|  |       lanc_params_DSDR = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--check_eofa"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       check_eofa = true; | ||||||
|  |       eofa_which_hsb = std::stoi(argv[i+1]); //-1 indicates all hasenbusch | ||||||
|  |       assert(eofa_which_hsb == -1 || (eofa_which_hsb >= 0 && eofa_which_hsb < n_light_hsb) ); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--upper_bound_eofa"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       upper_bound_eofa = true; | ||||||
|  |       eofa_which_hsb = std::stoi(argv[i+1]); | ||||||
|  |       assert(eofa_which_hsb >= 0 && eofa_which_hsb < n_light_hsb); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--lower_bound_eofa"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       lower_bound_eofa = true;       | ||||||
|  |       eofa_which_hsb = std::stoi(argv[i+1]); | ||||||
|  |       assert(eofa_which_hsb >= 0 && eofa_which_hsb < n_light_hsb); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if(tune_rhmc_s || eigenrange_s || tune_rhmc_DSDR || eigenrange_DSDR ||check_eofa || upper_bound_eofa || lower_bound_eofa) { | ||||||
|  |     std::cout << GridLogMessage << "Running checks" << std::endl; | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |  | ||||||
|  |     //std::cout << GridLogMessage << "EOFA action solver action tolerance outer=" << ActionMCG_L.Tolerance << " inner=" << ActionMCG_L.InnerTolerance << std::endl; | ||||||
|  |     //std::cout << GridLogMessage << "EOFA MD solver tolerance outer=" << DerivMCG_L.Tolerance << " inner=" << DerivMCG_L.InnerTolerance << std::endl; | ||||||
|  |  | ||||||
|  |     if(check_eofa){ | ||||||
|  |       if(eofa_which_hsb >= 0){ | ||||||
|  | 	std::cout << GridLogMessage << "Starting checking EOFA Hasenbusch " << eofa_which_hsb << std::endl; | ||||||
|  | 	checkEOFA(*EOFA_pfactions[eofa_which_hsb], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  | 	std::cout << GridLogMessage << "Finished checking EOFA Hasenbusch " << eofa_which_hsb << std::endl; | ||||||
|  |       }else{ | ||||||
|  | 	for(int i=0;i<n_light_hsb;i++){ | ||||||
|  | 	  std::cout << GridLogMessage << "Starting checking EOFA Hasenbusch " << i << std::endl; | ||||||
|  | 	  checkEOFA(*EOFA_pfactions[i], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  | 	  std::cout << GridLogMessage << "Finished checking EOFA Hasenbusch " << i << std::endl; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     }	   | ||||||
|  |     if(upper_bound_eofa) upperBoundEOFA(*EOFA_pfactions[eofa_which_hsb], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(lower_bound_eofa) lowerBoundEOFA(*EOFA_pfactions[eofa_which_hsb], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(eigenrange_s) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_s, FGridD, FrbGridD, Ud, Numerator_sD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_s) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_s)>(FGridD, FrbGridD, Ud, Numerator_sD, Denominator_sD, Quotient_s, TheHMC.Resources.GetParallelRNG(), 4, "strange",  tune_rhmc_s_action_or_md); | ||||||
|  |     if(eigenrange_DSDR) computeEigenvalues<GparityWilsonTMFermionD, GparityWilsonTMFermionD::FermionField>(lanc_params_DSDR, UGridD, UrbGridD, Ud, Numerator_DSDR_D, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_DSDR) checkRHMC<GparityWilsonTMFermionD, GparityWilsonTMFermionD::FermionField, decltype(Quotient_DSDR)>(UGridD, UrbGridD, Ud, Numerator_DSDR_D, Denominator_DSDR_D, Quotient_DSDR, TheHMC.Resources.GetParallelRNG(), 2, "DSDR", tune_rhmc_DSDR_action_or_md); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Run the HMC | ||||||
|  |   std::cout << GridLogMessage << " Running the HMC "<< std::endl; | ||||||
|  |   TheHMC.Run(); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } // main | ||||||
							
								
								
									
										873
									
								
								HMC/Mobius2p1fIDSDRGparityEOFA_48ID.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										873
									
								
								HMC/Mobius2p1fIDSDRGparityEOFA_48ID.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,873 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid | ||||||
|  |  | ||||||
|  | Source file: ./HMC/Mobius2p1fIDSDRGparityEOFA.cc | ||||||
|  |  | ||||||
|  | Copyright (C) 2015-2016 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  | Author: Peter Boyle <pabobyle@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; | ||||||
|  |  | ||||||
|  | //Production binary for the 40ID G-parity ensemble | ||||||
|  |  | ||||||
|  | struct RatQuoParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(RatQuoParameters, | ||||||
|  | 				  double, bnd_lo, | ||||||
|  | 				  double, bnd_hi, | ||||||
|  | 				  Integer, action_degree, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  Integer, md_degree, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  Integer, reliable_update_freq, | ||||||
|  | 				  Integer, bnd_check_freq); | ||||||
|  |   RatQuoParameters() {  | ||||||
|  |     bnd_lo = 1e-2; | ||||||
|  |     bnd_hi = 30; | ||||||
|  |     action_degree = 10; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_degree = 10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     bnd_check_freq = 20; | ||||||
|  |     reliable_update_freq = 50; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Export(RationalActionParams &into) const{ | ||||||
|  |     into.lo = bnd_lo; | ||||||
|  |     into.hi = bnd_hi; | ||||||
|  |     into.action_degree = action_degree; | ||||||
|  |     into.action_tolerance = action_tolerance; | ||||||
|  |     into.md_degree = md_degree; | ||||||
|  |     into.md_tolerance = md_tolerance; | ||||||
|  |     into.BoundsCheckFreq = bnd_check_freq; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct EOFAparameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EOFAparameters, | ||||||
|  | 				  OneFlavourRationalParams, rat_params, | ||||||
|  | 				  double, action_tolerance, | ||||||
|  | 				  double, action_mixcg_inner_tolerance, | ||||||
|  | 				  double, md_tolerance, | ||||||
|  | 				  double, md_mixcg_inner_tolerance); | ||||||
|  |  | ||||||
|  |   EOFAparameters() {  | ||||||
|  |     action_mixcg_inner_tolerance = 1e-8; | ||||||
|  |     action_tolerance = 1e-10; | ||||||
|  |     md_tolerance = 1e-8; | ||||||
|  |     md_mixcg_inner_tolerance = 1e-8; | ||||||
|  |  | ||||||
|  |     rat_params.lo = 1.0; | ||||||
|  |     rat_params.hi = 25.0; | ||||||
|  |     rat_params.MaxIter  = 10000; | ||||||
|  |     rat_params.tolerance= 1.0e-9; | ||||||
|  |     rat_params.degree   = 14; | ||||||
|  |     rat_params.precision= 50; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct EvolParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(EvolParameters, | ||||||
|  |                                   Integer, StartTrajectory, | ||||||
|  |                                   Integer, Trajectories, | ||||||
|  | 				  Integer, SaveInterval, | ||||||
|  | 				  Integer, Steps, | ||||||
|  | 				  RealD, TrajectoryLength, | ||||||
|  |                                   bool, MetropolisTest, | ||||||
|  | 				  std::string, StartingType, | ||||||
|  | 				  std::vector<Integer>, GparityDirs, | ||||||
|  | 				  std::vector<EOFAparameters>, eofa_l, | ||||||
|  | 				  RatQuoParameters, rat_quo_s, | ||||||
|  | 				  RatQuoParameters, rat_quo_DSDR); | ||||||
|  |  | ||||||
|  |   EvolParameters() { | ||||||
|  |     //For initial thermalization; afterwards user should switch Metropolis on and use StartingType=CheckpointStart | ||||||
|  |     MetropolisTest    = false; | ||||||
|  |     StartTrajectory   = 0; | ||||||
|  |     Trajectories      = 50; | ||||||
|  |     SaveInterval = 5; | ||||||
|  |     StartingType      = "ColdStart"; | ||||||
|  |     GparityDirs.resize(3, 1); //1 for G-parity, 0 for periodic | ||||||
|  |     Steps = 5; | ||||||
|  |     TrajectoryLength = 1.0; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | bool fileExists(const std::string &fn){ | ||||||
|  |   std::ifstream f(fn); | ||||||
|  |   return f.good(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct LanczosParameters: Serializable { | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParameters, | ||||||
|  | 				  double, alpha, | ||||||
|  | 				  double, beta, | ||||||
|  | 				  double, mu, | ||||||
|  | 				  int, ord, | ||||||
|  | 				  int, n_stop, | ||||||
|  | 				  int, n_want, | ||||||
|  | 				  int, n_use, | ||||||
|  | 				  double, tolerance); | ||||||
|  |  | ||||||
|  |   LanczosParameters() { | ||||||
|  |     alpha = 35; | ||||||
|  |     beta = 5; | ||||||
|  |     mu = 0; | ||||||
|  |     ord = 100; | ||||||
|  |     n_stop = 10; | ||||||
|  |     n_want = 10; | ||||||
|  |     n_use = 15; | ||||||
|  |     tolerance = 1e-6; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionActionD, typename FermionFieldD> | ||||||
|  | void computeEigenvalues(std::string param_file, | ||||||
|  | 			GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 			FermionActionD &action, GridParallelRNG &rng){ | ||||||
|  |    | ||||||
|  |   LanczosParameters params; | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "LanczosParameters", params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |     write(wr, "LanczosParameters", params); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   action.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   SchurDiagMooeeOperator<FermionActionD, FermionFieldD> hermop(action); | ||||||
|  |   PlainHermOp<FermionFieldD> hermop_wrap(hermop); | ||||||
|  |   //ChebyshevLanczos<FermionFieldD> Cheb(params.alpha, params.beta, params.mu, params.ord); | ||||||
|  |   assert(params.mu == 0.0); | ||||||
|  |  | ||||||
|  |   Chebyshev<FermionFieldD> Cheb(params.beta*params.beta, params.alpha*params.alpha, params.ord+1); | ||||||
|  |   FunctionHermOp<FermionFieldD> Cheb_wrap(Cheb, hermop); | ||||||
|  |  | ||||||
|  |   std::cout << "IRL: alpha=" << params.alpha << " beta=" << params.beta << " mu=" << params.mu << " ord=" << params.ord << std::endl; | ||||||
|  |   ImplicitlyRestartedLanczos<FermionFieldD> IRL(Cheb_wrap, hermop_wrap, params.n_stop, params.n_want, params.n_use, params.tolerance, 10000); | ||||||
|  |  | ||||||
|  |   std::vector<RealD> eval(params.n_use); | ||||||
|  |   std::vector<FermionFieldD> evec(params.n_use, rbGrid); | ||||||
|  |   int Nconv; | ||||||
|  |   IRL.calc(eval, evec, gauss_o, Nconv); | ||||||
|  |  | ||||||
|  |   std::cout << "Eigenvalues:" << std::endl; | ||||||
|  |   for(int i=0;i<params.n_want;i++){ | ||||||
|  |     std::cout << i << " " << eval[i] << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Check the quality of the RHMC approx | ||||||
|  | //action_or_md toggles checking the action (0), MD (1) or both (2) setups | ||||||
|  | template<typename FermionActionD, typename FermionFieldD, typename RHMCtype> | ||||||
|  | void checkRHMC(GridCartesian* Grid, GridRedBlackCartesian* rbGrid, const LatticeGaugeFieldD &latt,  //expect lattice to have been initialized to something | ||||||
|  | 	       FermionActionD &numOp, FermionActionD &denOp, RHMCtype &rhmc, GridParallelRNG &rng, | ||||||
|  | 	       int inv_pow, const std::string &quark_descr, int action_or_md){ | ||||||
|  |   assert(action_or_md == 0 || action_or_md == 1 || action_or_md == 2); | ||||||
|  |    | ||||||
|  |   FermionFieldD gauss_o(rbGrid); | ||||||
|  |   FermionFieldD gauss(Grid); | ||||||
|  |   gaussian(rng, gauss); | ||||||
|  |   pickCheckerboard(Odd, gauss_o, gauss); | ||||||
|  |  | ||||||
|  |   numOp.ImportGauge(latt); | ||||||
|  |   denOp.ImportGauge(latt); | ||||||
|  |  | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> MdagM(numOp); | ||||||
|  |   SchurDifferentiableOperator<FermionImplPolicyD> VdagV(denOp); | ||||||
|  |  | ||||||
|  |   PowerMethod<FermionFieldD> power_method; | ||||||
|  |   RealD lambda_max; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Get RHMC high bound approx for " << quark_descr << " numerator" << std::endl; | ||||||
|  |  | ||||||
|  |   lambda_max = power_method(MdagM,gauss_o); | ||||||
|  |   std::cout << GridLogMessage << "Got lambda_max "<<lambda_max<<std::endl; | ||||||
|  |  | ||||||
|  |   std::cout << "Starting: Get RHMC high bound approx for " << quark_descr << " denominator" << std::endl; | ||||||
|  |   lambda_max = power_method(VdagV,gauss_o); | ||||||
|  |   std::cout << GridLogMessage << "Got lambda_max "<<lambda_max<<std::endl; | ||||||
|  |  | ||||||
|  |   if(action_or_md == 0 || action_or_md == 2){ | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerAction); //use large tolerance to prevent exit on fail; we are trying to tune here! | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerAction); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC action approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout << "-------------------------------------------------------------------------------" << std::endl; | ||||||
|  |  | ||||||
|  |   if(action_or_md == 1 || action_or_md == 2){ | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegPowerMD);  | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, MdagM,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark numerator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << inv_pow << std::endl; | ||||||
|  |  | ||||||
|  |     std::cout << "Starting: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |     InversePowerBoundsCheck(2*inv_pow, 10000, 1e16, VdagV,gauss_o, rhmc.ApproxNegHalfPowerMD); | ||||||
|  |     std::cout << "Finished: Checking quality of RHMC MD approx for " << quark_descr << " quark denominator and power -1/" << 2*inv_pow << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void checkEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 	       GridCartesian* FGrid, GridParallelRNG &rng, const LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA action/bounds check" << std::endl; | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   RealD scale = std::sqrt(0.5); | ||||||
|  |   gaussian(rng,eta); eta = eta * scale; | ||||||
|  |  | ||||||
|  |   //Use the inbuilt check | ||||||
|  |   EOFA.refresh(latt, eta); | ||||||
|  |   EOFA.S(latt); | ||||||
|  |   std::cout << GridLogMessage << "Finished EOFA upper action/bounds check" << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | class EOFAlinop: public LinearOperatorBase<typename FermionImplPolicy::FermionField>{ | ||||||
|  |   ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA; | ||||||
|  |   LatticeGaugeFieldD &U; | ||||||
|  | public: | ||||||
|  |   EOFAlinop(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, LatticeGaugeFieldD &U): EOFA(EOFA), U(U){} | ||||||
|  |  | ||||||
|  |   typedef typename FermionImplPolicy::FermionField Field; | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); }  | ||||||
|  |  | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ assert(0); } | ||||||
|  |   void HermOp(const Field &in, Field &out){ EOFA.Meofa(U, in, out); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void upperBoundEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 		    GridCartesian* FGrid, GridParallelRNG &rng, LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA upper bound compute" << std::endl; | ||||||
|  |   EOFAlinop<FermionImplPolicy> linop(EOFA, latt); | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   gaussian(rng,eta); | ||||||
|  |   PowerMethod<typename FermionImplPolicy::FermionField> power_method; | ||||||
|  |   auto lambda_max = power_method(linop,eta); | ||||||
|  |   std::cout << GridLogMessage << "Upper bound of EOFA operator " << lambda_max << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Applications of M^{-1} cost the same as M for EOFA! | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | class EOFAinvLinop: public LinearOperatorBase<typename FermionImplPolicy::FermionField>{ | ||||||
|  |   ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA; | ||||||
|  |   LatticeGaugeFieldD &U; | ||||||
|  | public: | ||||||
|  |   EOFAinvLinop(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, LatticeGaugeFieldD &U): EOFA(EOFA), U(U){} | ||||||
|  |  | ||||||
|  |   typedef typename FermionImplPolicy::FermionField Field; | ||||||
|  |   void OpDiag (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void OpDir  (const Field &in, Field &out,int dir,int disp){ assert(0); } | ||||||
|  |   void OpDirAll  (const Field &in, std::vector<Field> &out){ assert(0); }  | ||||||
|  |  | ||||||
|  |   void Op     (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void AdjOp  (const Field &in, Field &out){ assert(0); } | ||||||
|  |   void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ assert(0); } | ||||||
|  |   void HermOp(const Field &in, Field &out){ EOFA.MeofaInv(U, in, out); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename FermionImplPolicy> | ||||||
|  | void lowerBoundEOFA(ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> &EOFA, | ||||||
|  | 		    GridCartesian* FGrid, GridParallelRNG &rng, LatticeGaugeFieldD &latt){ | ||||||
|  |   std::cout << GridLogMessage << "Starting EOFA lower bound compute using power method on M^{-1}. Inverse of highest eigenvalue is the lowest eigenvalue of M" << std::endl; | ||||||
|  |   EOFAinvLinop<FermionImplPolicy> linop(EOFA, latt); | ||||||
|  |   typename FermionImplPolicy::FermionField eta(FGrid); | ||||||
|  |   gaussian(rng,eta); | ||||||
|  |   PowerMethod<typename FermionImplPolicy::FermionField> power_method; | ||||||
|  |   auto lambda_max = power_method(linop,eta); | ||||||
|  |   std::cout << GridLogMessage << "Lower bound of EOFA operator " << 1./lambda_max << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   template<class FermionOperatorD, class FermionOperatorF, class SchurOperatorD, class  SchurOperatorF>  | ||||||
|  |   class MixedPrecisionReliableUpdateConjugateGradientOperatorFunction : public OperatorFunction<typename FermionOperatorD::FermionField> { | ||||||
|  |   public: | ||||||
|  |     typedef typename FermionOperatorD::FermionField FieldD; | ||||||
|  |     typedef typename FermionOperatorF::FermionField FieldF; | ||||||
|  |  | ||||||
|  |     using OperatorFunction<FieldD>::operator(); | ||||||
|  |  | ||||||
|  |     RealD Tolerance; | ||||||
|  |     Integer MaxIterations; | ||||||
|  |  | ||||||
|  |     RealD Delta; //reliable update parameter | ||||||
|  |  | ||||||
|  |     GridBase* SinglePrecGrid4; //Grid for single-precision fields | ||||||
|  |     GridBase* SinglePrecGrid5; //Grid for single-precision fields | ||||||
|  |  | ||||||
|  |     FermionOperatorF &FermOpF; | ||||||
|  |     FermionOperatorD &FermOpD;; | ||||||
|  |     SchurOperatorF &LinOpF; | ||||||
|  |     SchurOperatorD &LinOpD; | ||||||
|  |      | ||||||
|  |     MixedPrecisionReliableUpdateConjugateGradientOperatorFunction(RealD tol,  | ||||||
|  | 								  RealD delta, | ||||||
|  | 								  Integer maxit,  | ||||||
|  | 								  GridBase* _sp_grid4,  | ||||||
|  | 								  GridBase* _sp_grid5,  | ||||||
|  | 								  FermionOperatorF &_FermOpF, | ||||||
|  | 								  FermionOperatorD &_FermOpD, | ||||||
|  | 								  SchurOperatorF   &_LinOpF, | ||||||
|  | 								  SchurOperatorD   &_LinOpD):  | ||||||
|  |       LinOpF(_LinOpF), | ||||||
|  |       LinOpD(_LinOpD), | ||||||
|  |       FermOpF(_FermOpF), | ||||||
|  |       FermOpD(_FermOpD), | ||||||
|  |       Tolerance(tol),  | ||||||
|  |       Delta(delta), | ||||||
|  |       MaxIterations(maxit),  | ||||||
|  |       SinglePrecGrid4(_sp_grid4), | ||||||
|  |       SinglePrecGrid5(_sp_grid5) | ||||||
|  |     {  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     void operator()(LinearOperatorBase<FieldD> &LinOpU, const FieldD &src, FieldD &psi) { | ||||||
|  |  | ||||||
|  |       std::cout << GridLogMessage << " Mixed precision reliable CG update 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 | ||||||
|  |       //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |       ConjugateGradientReliableUpdate<FieldD,FieldF> MPCG(Tolerance,MaxIterations,Delta,SinglePrecGrid5,LinOpF,LinOpD); | ||||||
|  |       std::cout << GridLogMessage << "Calling mixed precision reliable update Conjugate Gradient" <<std::endl; | ||||||
|  |       MPCG(src,psi); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NAMESPACE_END(Grid); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main(int argc, char **argv) { | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |   int threads = GridThread::GetThreads(); | ||||||
|  |   // here make a routine to print all the relevant information on the run | ||||||
|  |   std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||||
|  |  | ||||||
|  |   std::string param_file = "params.xml"; | ||||||
|  |   bool file_load_check = false; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--param_file"){ | ||||||
|  |       assert(i!=argc-1); | ||||||
|  |       param_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_check"){ //check the fields load correctly and pass checksum/plaquette repro | ||||||
|  |       file_load_check = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Read the user parameters | ||||||
|  |   EvolParameters user_params; | ||||||
|  |    | ||||||
|  |   if(fileExists(param_file)){ | ||||||
|  |     std::cout << GridLogMessage << " Reading " << param_file << std::endl; | ||||||
|  |     Grid::XmlReader rd(param_file); | ||||||
|  |     read(rd, "Params", user_params); | ||||||
|  |   }else if(!GlobalSharedMemory::WorldRank){ | ||||||
|  |     std::cout << GridLogMessage << " File " << param_file << " does not exist" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << " Writing xml template to " << param_file << ".templ" << std::endl; | ||||||
|  |     { | ||||||
|  |       Grid::XmlWriter wr(param_file + ".templ"); | ||||||
|  |       write(wr, "Params", user_params); | ||||||
|  |     } | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Check the parameters | ||||||
|  |   if(user_params.GparityDirs.size() != Nd-1){ | ||||||
|  |     std::cerr << "Error in input parameters: expect GparityDirs to have size = " << Nd-1 << std::endl; | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<Nd-1;i++) | ||||||
|  |     if(user_params.GparityDirs[i] != 0 && user_params.GparityDirs[i] != 1){ | ||||||
|  |       std::cerr << "Error in input parameters: expect GparityDirs values to be 0 (periodic) or 1 (G-parity)" << std::endl; | ||||||
|  |       exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   typedef GparityMobiusEOFAFermionD EOFAactionD; | ||||||
|  |   typedef GparityMobiusFermionD FermionActionD; | ||||||
|  |   typedef typename FermionActionD::Impl_t FermionImplPolicyD; | ||||||
|  |   typedef typename FermionActionD::FermionField FermionFieldD; | ||||||
|  |  | ||||||
|  |   typedef GparityMobiusEOFAFermionF EOFAactionF; | ||||||
|  |   typedef GparityMobiusFermionF FermionActionF; | ||||||
|  |   typedef typename FermionActionF::Impl_t FermionImplPolicyF; | ||||||
|  |   typedef typename FermionActionF::FermionField FermionFieldF; | ||||||
|  |  | ||||||
|  |   typedef GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction<FermionImplPolicyD,FermionImplPolicyF> MixedPrecRHMC; | ||||||
|  |   typedef GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicyD> DoublePrecRHMC; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   IntegratorParameters MD; | ||||||
|  |   typedef ConjugateHMCRunnerD<MinimumNorm2> HMCWrapper; //NB: This is the "Omelyan integrator" | ||||||
|  |   typedef HMCWrapper::ImplPolicy GaugeImplPolicy; | ||||||
|  |   MD.name    = std::string("MinimumNorm2"); | ||||||
|  |   MD.MDsteps = user_params.Steps; | ||||||
|  |   MD.trajL   = user_params.TrajectoryLength; | ||||||
|  |  | ||||||
|  |   HMCparameters HMCparams; | ||||||
|  |   HMCparams.StartTrajectory  = user_params.StartTrajectory; | ||||||
|  |   HMCparams.Trajectories     = user_params.Trajectories; | ||||||
|  |   HMCparams.NoMetropolisUntil= 0; | ||||||
|  |   HMCparams.StartingType     = user_params.StartingType; | ||||||
|  |   HMCparams.MetropolisTest = user_params.MetropolisTest; | ||||||
|  |   HMCparams.MD = MD; | ||||||
|  |   HMCWrapper TheHMC(HMCparams); | ||||||
|  |  | ||||||
|  |   // Grid from the command line arguments --grid and --mpi | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); // use default simd lanes decomposition | ||||||
|  |  | ||||||
|  |   CheckpointerParameters CPparams; | ||||||
|  |   CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   CPparams.rng_prefix    = "ckpoint_rng"; | ||||||
|  |   CPparams.saveInterval  = user_params.SaveInterval; | ||||||
|  |   CPparams.format        = "IEEE64BIG"; | ||||||
|  |   TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   //Note that checkpointing saves the RNG state so that this initialization is required only for the very first configuration | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   typedef PlaquetteMod<GaugeImplPolicy> PlaqObs; | ||||||
|  |   TheHMC.Resources.AddObservable<PlaqObs>(); | ||||||
|  |   ////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   //aiming for ainv=2.068             me          Bob | ||||||
|  |   //Estimated  a(ml+mres) [48ID] = 0.001048    0.00104  | ||||||
|  |   //           a(mh+mres) [48ID] = 0.028847    0.02805 | ||||||
|  |   //Estimate Ls=12, b+c=2  mres~0.0003 | ||||||
|  |  | ||||||
|  |   const int Ls      = 12; | ||||||
|  |   Real beta         = 1.946; | ||||||
|  |   Real light_mass   = 0.00074;   //0.00104 - mres_approx; | ||||||
|  |   Real strange_mass = 0.02775;    //0.02805 - mres_approx | ||||||
|  |   Real pv_mass      = 1.0; | ||||||
|  |   RealD M5  = 1.8; | ||||||
|  |   RealD mobius_scale = 2.; //b+c | ||||||
|  |  | ||||||
|  |   RealD mob_bmc = 1.0; | ||||||
|  |   RealD mob_b = (mobius_scale + mob_bmc)/2.; | ||||||
|  |   RealD mob_c = (mobius_scale - mob_bmc)/2.; | ||||||
|  |  | ||||||
|  |   //Setup the Grids | ||||||
|  |   auto UGridD   = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto UrbGridD = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |   auto FGridD     = SpaceTimeGrid::makeFiveDimGrid(Ls,UGridD); | ||||||
|  |   auto FrbGridD   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGridD); | ||||||
|  |  | ||||||
|  |   GridCartesian* UGridF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* UrbGridF = SpaceTimeGrid::makeFourDimRedBlackGrid(UGridF); | ||||||
|  |   auto FGridF     = SpaceTimeGrid::makeFiveDimGrid(Ls,UGridF); | ||||||
|  |   auto FrbGridF   = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGridF); | ||||||
|  |  | ||||||
|  |   ConjugateIwasakiGaugeActionD GaugeAction(beta); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeFieldD Ud(UGridD); | ||||||
|  |   LatticeGaugeFieldF Uf(UGridF); | ||||||
|  |   | ||||||
|  |   //Setup the BCs | ||||||
|  |   FermionActionD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = user_params.GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |  | ||||||
|  |   std::vector<int> dirs4(Nd); | ||||||
|  |   for(int i=0;i<Nd-1;i++) dirs4[i] = user_params.GparityDirs[i]; | ||||||
|  |   dirs4[Nd-1] = 0; //periodic gauge BC in time | ||||||
|  |  | ||||||
|  |   GaugeImplPolicy::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   //Run optional gauge field checksum checker and exit | ||||||
|  |   if(file_load_check){ | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Collect actions | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level1(1); //light quark + strange quark | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level2(4); //DSDR | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level3(2); //gauge | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Light EOFA action | ||||||
|  |   // have to be careful with the parameters, cf. Test_dwf_gpforce_eofa.cc | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   typedef SchurDiagMooeeOperator<EOFAactionD,FermionFieldD> EOFAschuropD; | ||||||
|  |   typedef SchurDiagMooeeOperator<EOFAactionF,FermionFieldF> EOFAschuropF; | ||||||
|  |   typedef ExactOneFlavourRatioMixedPrecHeatbathPseudoFermionAction<FermionImplPolicyD, FermionImplPolicyF> EOFAmixPrecPFaction; | ||||||
|  |   typedef MixedPrecisionConjugateGradientOperatorFunction<EOFAactionD, EOFAactionF, EOFAschuropD, EOFAschuropF> EOFA_mxCG; | ||||||
|  |   typedef MixedPrecisionReliableUpdateConjugateGradientOperatorFunction<EOFAactionD, EOFAactionF, EOFAschuropD, EOFAschuropF> EOFA_relupCG; | ||||||
|  |    | ||||||
|  |   std::vector<RealD> eofa_light_masses = { light_mass ,  0.004,   0.016,   0.064,   0.256    }; | ||||||
|  |   std::vector<RealD> eofa_pv_masses =    { 0.004       , 0.016,   0.064,   0.256,   1.0      }; | ||||||
|  |   int n_light_hsb = 5; | ||||||
|  |   assert(user_params.eofa_l.size() == n_light_hsb); | ||||||
|  |    | ||||||
|  |   EOFAmixPrecPFaction* EOFA_pfactions[n_light_hsb]; | ||||||
|  |  | ||||||
|  |   for(int i=0;i<n_light_hsb;i++){ | ||||||
|  |     RealD iml = eofa_light_masses[i]; | ||||||
|  |     RealD ipv = eofa_pv_masses[i]; | ||||||
|  |  | ||||||
|  |     EOFAactionD* LopD = new EOFAactionD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, iml, iml, ipv, 0.0, -1, M5, mob_b, mob_c, Params); | ||||||
|  |     EOFAactionF* LopF = new EOFAactionF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, iml, iml, ipv, 0.0, -1, M5, mob_b, mob_c, Params); | ||||||
|  |     EOFAactionD* RopD = new EOFAactionD(Ud, *FGridD, *FrbGridD, *UGridD, *UrbGridD, ipv, iml, ipv, -1.0, 1, M5, mob_b, mob_c, Params); | ||||||
|  |     EOFAactionF* RopF = new EOFAactionF(Uf, *FGridF, *FrbGridF, *UGridF, *UrbGridF, ipv, iml, ipv, -1.0, 1, M5, mob_b, mob_c, Params); | ||||||
|  |  | ||||||
|  |     EOFAschuropD* linopL_D = new EOFAschuropD(*LopD); | ||||||
|  |     EOFAschuropD* linopR_D = new EOFAschuropD(*RopD); | ||||||
|  |      | ||||||
|  |     EOFAschuropF* linopL_F = new EOFAschuropF(*LopF); | ||||||
|  |     EOFAschuropF* linopR_F = new EOFAschuropF(*RopF); | ||||||
|  |  | ||||||
|  | #if 1 | ||||||
|  |     //Note reusing user_params.eofa_l.action(|md)_mixcg_inner_tolerance  as Delta for now | ||||||
|  |     EOFA_relupCG* ActionMCG_L = new EOFA_relupCG(user_params.eofa_l[i].action_tolerance, user_params.eofa_l[i].action_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     EOFA_relupCG* ActionMCG_R = new EOFA_relupCG(user_params.eofa_l[i].action_tolerance, user_params.eofa_l[i].action_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |  | ||||||
|  |     EOFA_relupCG* DerivMCG_L = new EOFA_relupCG(user_params.eofa_l[i].md_tolerance, user_params.eofa_l[i].md_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     EOFA_relupCG* DerivMCG_R = new EOFA_relupCG(user_params.eofa_l[i].md_tolerance, user_params.eofa_l[i].md_mixcg_inner_tolerance, 50000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* ActionMCG_L = new EOFA_mxCG(user_params.eofa_l[i].action_tolerance, 10000, 1000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     ActionMCG_L->InnerTolerance = user_params.eofa_l[i].action_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* ActionMCG_R = new EOFA_mxCG(user_params.eofa_l[i].action_tolerance, 10000, 1000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |     ActionMCG_R->InnerTolerance = user_params.eofa_l[i].action_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* DerivMCG_L = new EOFA_mxCG(user_params.eofa_l[i].md_tolerance, 10000, 1000, UGridF, FrbGridF, *LopF, *LopD, *linopL_F, *linopL_D); | ||||||
|  |     DerivMCG_L->InnerTolerance = user_params.eofa_l[i].md_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     EOFA_mxCG* DerivMCG_R = new EOFA_mxCG(user_params.eofa_l[i].md_tolerance, 10000, 1000, UGridF, FrbGridF, *RopF, *RopD, *linopR_F, *linopR_D); | ||||||
|  |     DerivMCG_R->InnerTolerance = user_params.eofa_l[i].md_mixcg_inner_tolerance; | ||||||
|  |      | ||||||
|  |     std::cout << GridLogMessage << "Set EOFA action solver action tolerance outer=" << ActionMCG_L->Tolerance << " inner=" << ActionMCG_L->InnerTolerance << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "Set EOFA MD solver tolerance outer=" << DerivMCG_L->Tolerance << " inner=" << DerivMCG_L->InnerTolerance << std::endl; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     EOFAmixPrecPFaction* EOFA = new EOFAmixPrecPFaction(*LopF, *RopF, | ||||||
|  | 							*LopD, *RopD,  | ||||||
|  | 							*ActionMCG_L, *ActionMCG_R,  | ||||||
|  | 							*ActionMCG_L, *ActionMCG_R,  | ||||||
|  | 							*DerivMCG_L, *DerivMCG_R,  | ||||||
|  | 							user_params.eofa_l[i].rat_params, true); | ||||||
|  |     EOFA_pfactions[i] = EOFA; | ||||||
|  |     Level1.push_back(EOFA); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   // Strange action | ||||||
|  |   //////////////////////////////////// | ||||||
|  |   FermionActionD Numerator_sD(Ud,*FGridD,*FrbGridD,*UGridD,*UrbGridD,strange_mass,M5,mob_b,mob_c,Params); | ||||||
|  |   FermionActionD Denominator_sD(Ud,*FGridD,*FrbGridD,*UGridD,*UrbGridD, pv_mass,M5,mob_b,mob_c,Params); | ||||||
|  |  | ||||||
|  |   FermionActionF Numerator_sF(Uf,*FGridF,*FrbGridF,*UGridF,*UrbGridF,strange_mass,M5,mob_b,mob_c,Params); | ||||||
|  |   FermionActionF Denominator_sF(Uf,*FGridF,*FrbGridF,*UGridF,*UrbGridF, pv_mass,M5,mob_b,mob_c,Params); | ||||||
|  |  | ||||||
|  |   RationalActionParams rat_act_params_s; | ||||||
|  |   rat_act_params_s.inv_pow  = 4; // (M^dag M)^{1/4} | ||||||
|  |   rat_act_params_s.precision= 60; | ||||||
|  |   rat_act_params_s.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_s.Export(rat_act_params_s); | ||||||
|  |   std::cout << GridLogMessage << " Heavy quark bounds check every " << rat_act_params_s.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   //MixedPrecRHMC Quotient_s(Denominator_sD, Numerator_sD, Denominator_sF, Numerator_sF, rat_act_params_s, user_params.rat_quo_s.reliable_update_freq);  | ||||||
|  |   DoublePrecRHMC Quotient_s(Denominator_sD, Numerator_sD, rat_act_params_s);  | ||||||
|  |   Level1.push_back(&Quotient_s);   | ||||||
|  |  | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   // DSDR action | ||||||
|  |   /////////////////////////////////// | ||||||
|  |   RealD dsdr_mass=-1.8;    | ||||||
|  |   //Use same DSDR twists as https://arxiv.org/pdf/1208.4412.pdf | ||||||
|  |   RealD dsdr_epsilon_f = 0.02; //numerator (in determinant) | ||||||
|  |   RealD dsdr_epsilon_b = 0.5;  | ||||||
|  |   GparityWilsonTMFermionD Numerator_DSDR_D(Ud, *UGridD, *UrbGridD, dsdr_mass, dsdr_epsilon_f, Params); | ||||||
|  |   GparityWilsonTMFermionF Numerator_DSDR_F(Uf, *UGridF, *UrbGridF, dsdr_mass, dsdr_epsilon_f, Params); | ||||||
|  |  | ||||||
|  |   GparityWilsonTMFermionD Denominator_DSDR_D(Ud, *UGridD, *UrbGridD, dsdr_mass, dsdr_epsilon_b, Params); | ||||||
|  |   GparityWilsonTMFermionF Denominator_DSDR_F(Uf, *UGridF, *UrbGridF, dsdr_mass, dsdr_epsilon_b, Params); | ||||||
|  |   | ||||||
|  |   RationalActionParams rat_act_params_DSDR; | ||||||
|  |   rat_act_params_DSDR.inv_pow  = 2; // (M^dag M)^{1/2} | ||||||
|  |   rat_act_params_DSDR.precision= 60; | ||||||
|  |   rat_act_params_DSDR.MaxIter  = 10000; | ||||||
|  |   user_params.rat_quo_DSDR.Export(rat_act_params_DSDR); | ||||||
|  |   std::cout << GridLogMessage << "DSDR quark bounds check every " << rat_act_params_DSDR.BoundsCheckFreq << " trajectories (avg)" << std::endl; | ||||||
|  |  | ||||||
|  |   DoublePrecRHMC Quotient_DSDR(Denominator_DSDR_D, Numerator_DSDR_D, rat_act_params_DSDR); | ||||||
|  |   Level2.push_back(&Quotient_DSDR); | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Gauge action | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   Level3.push_back(&GaugeAction); | ||||||
|  |  | ||||||
|  |   TheHMC.TheAction.push_back(Level1); | ||||||
|  |   TheHMC.TheAction.push_back(Level2); | ||||||
|  |   TheHMC.TheAction.push_back(Level3); | ||||||
|  |   std::cout << GridLogMessage << " Action complete "<< std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Action tuning | ||||||
|  |   bool  | ||||||
|  |     tune_rhmc_s=false, eigenrange_s=false,  | ||||||
|  |     tune_rhmc_DSDR=false, eigenrange_DSDR=false,  | ||||||
|  |     check_eofa=false,  | ||||||
|  |     upper_bound_eofa=false, lower_bound_eofa(false); | ||||||
|  |  | ||||||
|  |   std::string lanc_params_s; | ||||||
|  |   std::string lanc_params_DSDR; | ||||||
|  |   int tune_rhmc_s_action_or_md; | ||||||
|  |   int tune_rhmc_DSDR_action_or_md; | ||||||
|  |   int eofa_which_hsb; | ||||||
|  |  | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--tune_rhmc_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       tune_rhmc_s=true; | ||||||
|  |       tune_rhmc_s_action_or_md = std::stoi(argv[i+1]); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_s"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_s=true; | ||||||
|  |       lanc_params_s = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--tune_rhmc_DSDR"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       tune_rhmc_DSDR=true; | ||||||
|  |       tune_rhmc_DSDR_action_or_md = std::stoi(argv[i+1]); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--eigenrange_DSDR"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       eigenrange_DSDR=true; | ||||||
|  |       lanc_params_DSDR = argv[i+1]; | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--check_eofa"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       check_eofa = true; | ||||||
|  |       eofa_which_hsb = std::stoi(argv[i+1]); //-1 indicates all hasenbusch | ||||||
|  |       assert(eofa_which_hsb == -1 || (eofa_which_hsb >= 0 && eofa_which_hsb < n_light_hsb) ); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--upper_bound_eofa"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       upper_bound_eofa = true; | ||||||
|  |       eofa_which_hsb = std::stoi(argv[i+1]); | ||||||
|  |       assert(eofa_which_hsb >= 0 && eofa_which_hsb < n_light_hsb); | ||||||
|  |     } | ||||||
|  |     else if(sarg == "--lower_bound_eofa"){ | ||||||
|  |       assert(i < argc-1); | ||||||
|  |       lower_bound_eofa = true;       | ||||||
|  |       eofa_which_hsb = std::stoi(argv[i+1]); | ||||||
|  |       assert(eofa_which_hsb >= 0 && eofa_which_hsb < n_light_hsb); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if(tune_rhmc_s || eigenrange_s || tune_rhmc_DSDR || eigenrange_DSDR ||check_eofa || upper_bound_eofa || lower_bound_eofa) { | ||||||
|  |     std::cout << GridLogMessage << "Running checks" << std::endl; | ||||||
|  |     TheHMC.initializeGaugeFieldAndRNGs(Ud); | ||||||
|  |  | ||||||
|  |     //std::cout << GridLogMessage << "EOFA action solver action tolerance outer=" << ActionMCG_L.Tolerance << " inner=" << ActionMCG_L.InnerTolerance << std::endl; | ||||||
|  |     //std::cout << GridLogMessage << "EOFA MD solver tolerance outer=" << DerivMCG_L.Tolerance << " inner=" << DerivMCG_L.InnerTolerance << std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if(check_eofa){ | ||||||
|  |       if(eofa_which_hsb >= 0){ | ||||||
|  | 	std::cout << GridLogMessage << "Starting checking EOFA Hasenbusch " << eofa_which_hsb << std::endl; | ||||||
|  | 	checkEOFA(*EOFA_pfactions[eofa_which_hsb], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  | 	std::cout << GridLogMessage << "Finished checking EOFA Hasenbusch " << eofa_which_hsb << std::endl; | ||||||
|  |       }else{ | ||||||
|  | 	for(int i=0;i<n_light_hsb;i++){ | ||||||
|  | 	  std::cout << GridLogMessage << "Starting checking EOFA Hasenbusch " << i << std::endl; | ||||||
|  | 	  checkEOFA(*EOFA_pfactions[i], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  | 	  std::cout << GridLogMessage << "Finished checking EOFA Hasenbusch " << i << std::endl; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |     }	   | ||||||
|  |     if(upper_bound_eofa) upperBoundEOFA(*EOFA_pfactions[eofa_which_hsb], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(lower_bound_eofa) lowerBoundEOFA(*EOFA_pfactions[eofa_which_hsb], FGridD, TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |     if(eigenrange_s) computeEigenvalues<FermionActionD, FermionFieldD>(lanc_params_s, FGridD, FrbGridD, Ud, Numerator_sD, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_s) checkRHMC<FermionActionD, FermionFieldD, decltype(Quotient_s)>(FGridD, FrbGridD, Ud, Numerator_sD, Denominator_sD, Quotient_s, TheHMC.Resources.GetParallelRNG(), 4, "strange",  tune_rhmc_s_action_or_md); | ||||||
|  |     if(eigenrange_DSDR) computeEigenvalues<GparityWilsonTMFermionD, GparityWilsonTMFermionD::FermionField>(lanc_params_DSDR, UGridD, UrbGridD, Ud, Numerator_DSDR_D, TheHMC.Resources.GetParallelRNG()); | ||||||
|  |     if(tune_rhmc_DSDR) checkRHMC<GparityWilsonTMFermionD, GparityWilsonTMFermionD::FermionField, decltype(Quotient_DSDR)>(UGridD, UrbGridD, Ud, Numerator_DSDR_D, Denominator_DSDR_D, Quotient_DSDR, TheHMC.Resources.GetParallelRNG(), 2, "DSDR", tune_rhmc_DSDR_action_or_md); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Run the HMC | ||||||
|  |   std::cout << GridLogMessage << " Running the HMC "<< std::endl; | ||||||
|  |   TheHMC.Run(); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << " Done" << std::endl; | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } // main | ||||||
| @@ -1,19 +1,27 @@ | |||||||
| #!/bin/bash | #!/bin/bash | ||||||
|  |  | ||||||
| LOG=$1 | LOG=$1 | ||||||
| SWEEPS=`grep dH $LOG | wc -l` | SWEEPS=`grep dH.= $LOG | wc -l` | ||||||
| SWEEPS=`expr $SWEEPS - 80` | SWEEPS=`expr $SWEEPS - 100` | ||||||
| echo | echo | ||||||
| echo $SWEEPS thermalised sweeps | echo $SWEEPS thermalised sweeps | ||||||
| echo | echo | ||||||
| plaq=`grep Plaq $LOG | tail -n $SWEEPS | awk '{ S=S+$10} END { print S/NR} ' ` | plaq=`grep Plaq $LOG | tail -n $SWEEPS | awk '{ S=S+$12} END { print S/NR} ' ` | ||||||
| plaqe=`grep Plaq $LOG | tail -n $SWEEPS | awk '{ S=S+$10 ; SS=SS+$10*$10 } END { print sqrt( (SS/NR - S*S/NR/NR)/NR) } ' ` | plaqe=`grep Plaq $LOG | tail -n $SWEEPS | awk '{ S=S+$12 ; SS=SS+$12*$12 } END { print sqrt( (SS/NR - S*S/NR/NR)/NR) } ' ` | ||||||
| echo "Plaquette: $plaq (${plaqe})" | echo "Plaquette: $plaq (${plaqe})" | ||||||
| echo | echo | ||||||
|  |  | ||||||
| dHv=`grep dH $LOG | tail -n $SWEEPS | awk '{ S=S+$10 ; SS=SS+$10*$10 } END { print sqrt(SS/NR) } ' ` | grep  Plaq $LOG | tail -n $SWEEPS | awk '{ S=S+$12/20; if(NR%20==0){ print NR/20, " ", S; S=0;} } '  > plaq.binned | ||||||
| edH=`grep dH $LOG | tail -n $SWEEPS | awk '{ S=S+exp(-$10)} END { print S/NR} '` |  | ||||||
| echo "<e-dH>: $edH" | plaq=`cat plaq.binned  | awk '{ S=S+$2} END { print S/NR} ' ` | ||||||
|  | plaqe=`cat plaq.binned | awk '{ S=S+$2 ; SS=SS+$2*$2 } END { print sqrt( (SS/NR - S*S/NR/NR)/NR) } ' ` | ||||||
|  | echo "Binned Plaquette: $plaq (${plaqe})" | ||||||
|  | echo | ||||||
|  |  | ||||||
|  | dHv=`grep dH.= $LOG | tail -n $SWEEPS | awk '{ S=S+$16 ; SS=SS+$16*$16 } END { print sqrt(SS/NR) } ' ` | ||||||
|  | edH=`grep dH.= $LOG | tail -n $SWEEPS | awk '{ S=S+exp(-$16)} END { print S/NR} '` | ||||||
|  | dedH=`grep dH.= $LOG | tail -n $SWEEPS | awk '{ S=S+exp(-$16); SS=SS+exp(-$16)*exp(-$16)} END { print sqrt( (SS/NR - S*S/NR/NR)/NR) } '` | ||||||
|  | echo "<e-dH>: $edH (${dedH})" | ||||||
| echo "<rms dH>: $dHv" | echo "<rms dH>: $dHv" | ||||||
|  |  | ||||||
| TRAJ=`grep Acc $LOG | wc -l` | TRAJ=`grep Acc $LOG | wc -l` | ||||||
| @@ -22,12 +30,13 @@ PACC=`expr  100 \* ${ACC} / ${TRAJ} ` | |||||||
| echo | echo | ||||||
| echo "Acceptance $PACC %  $ACC / $TRAJ " | echo "Acceptance $PACC %  $ACC / $TRAJ " | ||||||
|  |  | ||||||
| grep Plaq $LOG | awk '{ print $10 }' | uniq > plaq.dat | grep Plaq $LOG | awk '{ print $12 }' | uniq > plaq.dat | ||||||
| grep dH $LOG | awk '{ print $10 }' > dH.dat | grep dH.= $LOG | awk '{ print $16 }' > dH.dat | ||||||
| echo set yrange [-0.2:1.0] > plot.gnu | echo set yrange [0.58:0.60] > plot.gnu | ||||||
| echo set terminal 'pdf' >> plot.gnu | echo set terminal 'pdf' >> plot.gnu | ||||||
|  | echo "f(x) =0.588" >> plot.gnu | ||||||
| echo "set output 'plaq.${LOG}.pdf'" >> plot.gnu | echo "set output 'plaq.${LOG}.pdf'" >> plot.gnu | ||||||
| echo "plot 'plaq.dat' w l, 'dH.dat' w l " >> plot.gnu | echo "plot 'plaq.dat' w l, f(x) " >> plot.gnu | ||||||
| echo | echo | ||||||
| gnuplot plot.gnu >& gnu.errs | gnuplot plot.gnu >& gnu.errs | ||||||
| open plaq.${LOG}.pdf | open plaq.${LOG}.pdf | ||||||
|   | |||||||
							
								
								
									
										184
									
								
								tests/IO/Test_field_array_io.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								tests/IO/Test_field_array_io.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/IO/Test_field_array_io.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  | #include <Grid/Grid.h> | ||||||
|  |  | ||||||
|  | using namespace std; | ||||||
|  | using namespace Grid; | ||||||
|  |  | ||||||
|  | //This test demonstrates and checks a single-file write of an arbitrary array of fields | ||||||
|  |  | ||||||
|  | uint64_t writeHeader(const uint32_t size, const uint32_t checksum, const std::string &format, const std::string &file){ | ||||||
|  |   std::ofstream fout(file,std::ios::out|std::ios::in); | ||||||
|  |   fout.seekp(0,std::ios::beg); | ||||||
|  |   fout << std::setw(10) << size << std::endl; | ||||||
|  |   fout << std::hex << std::setw(10) << checksum << std::endl; | ||||||
|  |   fout << format << std::endl; | ||||||
|  |   return fout.tellp(); | ||||||
|  | } | ||||||
|  |   | ||||||
|  | uint64_t readHeader(uint32_t &size, uint32_t &checksum, std::string &format, const std::string &file){ | ||||||
|  |   std::ifstream fin(file); | ||||||
|  |   std::string line; | ||||||
|  |   getline(fin,line); | ||||||
|  |   { | ||||||
|  |     std::stringstream ss; ss <<line ; ss >> size; | ||||||
|  |   } | ||||||
|  |   getline(fin,line); | ||||||
|  |   { | ||||||
|  |     std::stringstream ss; ss <<line ; ss >> std::hex >> checksum; | ||||||
|  |   } | ||||||
|  |   getline(fin,format); | ||||||
|  |   removeWhitespace(format); | ||||||
|  |        | ||||||
|  |   return fin.tellg(); | ||||||
|  | } | ||||||
|  |   | ||||||
|  | template<typename FieldType> | ||||||
|  | void writeFieldArray(const std::string &file, const std::vector<FieldType> &data){ | ||||||
|  |   typedef typename FieldType::vector_object vobj; | ||||||
|  |   typedef typename FieldType::scalar_object sobj; | ||||||
|  |   GridBase* grid = data[0].Grid(); //assume all fields have the same Grid | ||||||
|  |   BinarySimpleMunger<sobj, sobj> munge; //straight copy | ||||||
|  |  | ||||||
|  |   //We need a 2-pass header write, first to establish the size, the second pass writes the checksum | ||||||
|  |   std::string format = getFormatString<typename FieldType::vector_object>(); | ||||||
|  |  | ||||||
|  |   uint64_t offset; //leave 64 bits for header | ||||||
|  |   if ( grid->IsBoss() ) {  | ||||||
|  |     NerscIO::truncate(file); | ||||||
|  |     offset = writeHeader(data.size(), 0, format, file); | ||||||
|  |   } | ||||||
|  |   grid->Broadcast(0,(void *)&offset,sizeof(offset)); //use as a barrier | ||||||
|  |  | ||||||
|  |   std::cout << "Data offset write " << offset << std::endl; | ||||||
|  |   std::cout << "Data size write " << data.size() << std::endl; | ||||||
|  |   uint64_t field_size = uint64_t(grid->gSites()) * sizeof(sobj); | ||||||
|  |   std::cout << "Field size = " << field_size << " B" << std::endl; | ||||||
|  |  | ||||||
|  |   uint32_t checksum = 0; | ||||||
|  |   for(int i=0;i<data.size();i++){ | ||||||
|  |     std::cout << "Data field write " << i << " offset " << offset << std::endl; | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     BinaryIO::writeLatticeObject<vobj,sobj>(const_cast<FieldType &>(data[i]),file,munge,offset,format, | ||||||
|  | 					    nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |     offset += field_size; | ||||||
|  |     checksum ^= nersc_csum + 0x9e3779b9 + (checksum<<6) + (checksum>>2); | ||||||
|  |   } | ||||||
|  |   std::cout << "Write checksum " << checksum << std::endl; | ||||||
|  |  | ||||||
|  |   if ( grid->IsBoss() ) {  | ||||||
|  |     writeHeader(data.size(), checksum, format, file); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename FieldType> | ||||||
|  | void readFieldArray(std::vector<FieldType> &data, const std::string &file){ | ||||||
|  |   typedef typename FieldType::vector_object vobj; | ||||||
|  |   typedef typename FieldType::scalar_object sobj; | ||||||
|  |   assert(data.size() > 0); | ||||||
|  |   GridBase* grid = data[0].Grid(); //assume all fields have the same Grid | ||||||
|  |   BinarySimpleUnmunger<sobj, sobj> munge; //straight copy | ||||||
|  |    | ||||||
|  |   uint32_t hdr_checksum, hdr_size; | ||||||
|  |   std::string format; | ||||||
|  |   uint64_t offset = readHeader(hdr_size, hdr_checksum, format, file); | ||||||
|  |    | ||||||
|  |   std::cout << "Data offset read " << offset << std::endl;   | ||||||
|  |   std::cout << "Data size read " << hdr_size << std::endl; | ||||||
|  |   assert(data.size() == hdr_size); | ||||||
|  |  | ||||||
|  |   uint64_t field_size = uint64_t(grid->gSites()) * sizeof(sobj); | ||||||
|  |  | ||||||
|  |   uint32_t checksum = 0; | ||||||
|  |  | ||||||
|  |   for(int i=0;i<data.size();i++){ | ||||||
|  |     std::cout << "Data field read " << i << " offset " << offset << std::endl; | ||||||
|  |     uint32_t nersc_csum,scidac_csuma,scidac_csumb; | ||||||
|  |     BinaryIO::readLatticeObject<vobj,sobj>(data[i],file,munge,offset,format, | ||||||
|  | 					   nersc_csum,scidac_csuma,scidac_csumb); | ||||||
|  |     offset += field_size; | ||||||
|  |     checksum ^= nersc_csum + 0x9e3779b9 + (checksum<<6) + (checksum>>2); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout << "Header checksum " << hdr_checksum << std::endl;     | ||||||
|  |   std::cout << "Read checksum " << checksum << std::endl; | ||||||
|  |      | ||||||
|  |  | ||||||
|  |   assert( hdr_checksum == checksum ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main (int argc, char ** argv) | ||||||
|  | { | ||||||
|  |   Grid_init(&argc,&argv); | ||||||
|  |  | ||||||
|  |   Coordinate latt   = GridDefaultLatt(); | ||||||
|  |   Coordinate simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||||
|  |   Coordinate mpi_layout  = GridDefaultMpi(); | ||||||
|  |  | ||||||
|  |   const int Ls=8; | ||||||
|  |  | ||||||
|  |   GridCartesian         * UGrid   = SpaceTimeGrid::makeFourDimGrid(latt, simd_layout, mpi_layout); | ||||||
|  |   GridRedBlackCartesian * UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||||
|  |   GridCartesian         * FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid); | ||||||
|  |   GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid); | ||||||
|  |  | ||||||
|  |   std::vector<int> seeds4({1,2,3,4}); | ||||||
|  |   std::vector<int> seeds5({5,6,7,8}); | ||||||
|  |   GridParallelRNG RNG5(FGrid);  RNG5.SeedFixedIntegers(seeds5); | ||||||
|  |   GridParallelRNG RNG4(UGrid);  RNG4.SeedFixedIntegers(seeds4); | ||||||
|  |  | ||||||
|  |   typedef DomainWallFermionD::FermionField FermionField; | ||||||
|  |  | ||||||
|  |   int nfield = 20; | ||||||
|  |   std::vector<FermionField> data(nfield, FGrid); | ||||||
|  |  | ||||||
|  |   for(int i=0;i<data.size();i++) | ||||||
|  |     gaussian(RNG5, data[i]); | ||||||
|  |    | ||||||
|  |   std::string file = "test_field_array_io.0"; | ||||||
|  |   writeFieldArray(file, data); | ||||||
|  |  | ||||||
|  |   std::vector<FermionField> data_r(nfield, FGrid); | ||||||
|  |   readFieldArray(data_r, file); | ||||||
|  |    | ||||||
|  |   for(int i=0;i<nfield;i++){ | ||||||
|  |     FermionField diff = data_r[i] - data[i]; | ||||||
|  |     RealD norm_diff = norm2(diff); | ||||||
|  |     std::cout << "Norm2 of difference between stored and loaded data index " << i << " : " << norm_diff << std::endl; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   std::cout << "Done" << std::endl; | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  | } | ||||||
| @@ -299,12 +299,12 @@ int main (int argc, char ** argv) | |||||||
|     SpinColourVectorD ferm; gaussian(sRNG,ferm); |     SpinColourVectorD ferm; gaussian(sRNG,ferm); | ||||||
|     pokeSite(ferm,src,point); |     pokeSite(ferm,src,point); | ||||||
|  |  | ||||||
|     const int Ls=32; |     const int Ls=64; | ||||||
|     GridCartesian         * FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls,&GRID); |     GridCartesian         * FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls,&GRID); | ||||||
|     GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,&GRID); |     GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,&GRID); | ||||||
|  |  | ||||||
|     RealD mass=0.01; |     RealD mass=1.0; | ||||||
|     RealD M5  =0.8; |     RealD M5  =0.99; | ||||||
|     DomainWallFermionD Ddwf(Umu,*FGrid,*FrbGrid,GRID,RBGRID,mass,M5); |     DomainWallFermionD Ddwf(Umu,*FGrid,*FrbGrid,GRID,RBGRID,mass,M5); | ||||||
|  |  | ||||||
|     // Momentum space prop |     // Momentum space prop | ||||||
| @@ -353,6 +353,12 @@ int main (int argc, char ** argv) | |||||||
|     std::cout << " Taking difference" <<std::endl; |     std::cout << " Taking difference" <<std::endl; | ||||||
|     std::cout << "Ddwf result4 "<<norm2(result4)<<std::endl; |     std::cout << "Ddwf result4 "<<norm2(result4)<<std::endl; | ||||||
|     std::cout << "Ddwf ref     "<<norm2(ref)<<std::endl; |     std::cout << "Ddwf ref     "<<norm2(ref)<<std::endl; | ||||||
|  |     auto twopoint = localInnerProduct(result4,result4); | ||||||
|  |     std::vector<TComplex> pion_prop; | ||||||
|  |     sliceSum(twopoint,pion_prop,Nd-1); | ||||||
|  |     for(int t=0;t<pion_prop.size();t++){ | ||||||
|  |       std::cout << "Pion_prop["<<t<<"]="<<pion_prop[t]<<std::endl; | ||||||
|  |     } | ||||||
|      |      | ||||||
|     diff = ref - result4; |     diff = ref - result4; | ||||||
|     std::cout << "result - ref     "<<norm2(diff)<<std::endl; |     std::cout << "result - ref     "<<norm2(diff)<<std::endl; | ||||||
| @@ -383,7 +389,7 @@ int main (int argc, char ** argv) | |||||||
|     GridCartesian         * FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls,&GRID); |     GridCartesian         * FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls,&GRID); | ||||||
|     GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,&GRID); |     GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,&GRID); | ||||||
|  |  | ||||||
|     RealD mass=0.01; |     RealD mass=1.0; | ||||||
|     RealD M5  =0.8; |     RealD M5  =0.8; | ||||||
|  |  | ||||||
|     OverlapWilsonCayleyTanhFermionD Dov(Umu,*FGrid,*FrbGrid,GRID,RBGRID,mass,M5,1.0); |     OverlapWilsonCayleyTanhFermionD Dov(Umu,*FGrid,*FrbGrid,GRID,RBGRID,mass,M5,1.0); | ||||||
|   | |||||||
| @@ -29,14 +29,10 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | |||||||
| #include <Grid/Grid.h> | #include <Grid/Grid.h> | ||||||
|  |  | ||||||
| using namespace Grid; | using namespace Grid; | ||||||
|  ; |  | ||||||
|  |  | ||||||
| int main (int argc, char ** argv) | template<typename Gimpl> | ||||||
| { | void run(double alpha, bool do_fft_gfix){ | ||||||
|   std::vector<int> seeds({1,2,3,4}); |   std::vector<int> seeds({1,2,3,4}); | ||||||
|  |  | ||||||
|   Grid_init(&argc,&argv); |  | ||||||
|  |  | ||||||
|   int threads = GridThread::GetThreads(); |   int threads = GridThread::GetThreads(); | ||||||
|  |  | ||||||
|   Coordinate latt_size   = GridDefaultLatt(); |   Coordinate latt_size   = GridDefaultLatt(); | ||||||
| @@ -55,10 +51,7 @@ int main (int argc, char ** argv) | |||||||
|   FFT theFFT(&GRID); |   FFT theFFT(&GRID); | ||||||
|  |  | ||||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; |   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||||
|  |   std::cout<<GridLogMessage << "Using alpha=" << alpha << std::endl; | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |  | ||||||
|   std::cout<< "* Testing we can gauge fix steep descent a RGT of Unit gauge    *" <<std::endl; |  | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |  | ||||||
|  |  | ||||||
|   //  int coulomb_dir = -1; |   //  int coulomb_dir = -1; | ||||||
|   int coulomb_dir = Nd-1; |   int coulomb_dir = Nd-1; | ||||||
| @@ -73,80 +66,164 @@ int main (int argc, char ** argv) | |||||||
|   LatticeColourMatrix   xform2(&GRID); // Gauge xform |   LatticeColourMatrix   xform2(&GRID); // Gauge xform | ||||||
|   LatticeColourMatrix   xform3(&GRID); // Gauge xform |   LatticeColourMatrix   xform3(&GRID); // Gauge xform | ||||||
|  |  | ||||||
|  |   //######################################################################################### | ||||||
|  |  | ||||||
|  |   std::cout<< "*********************************************************************************************************" <<std::endl; | ||||||
|  |   std::cout<< "* Testing steepest descent fixing to Landau gauge with randomly transformed unit gauge configuration    *" <<std::endl; | ||||||
|  |   std::cout<< "*********************************************************************************************************" <<std::endl; | ||||||
|  |    | ||||||
|   SU<Nc>::ColdConfiguration(pRNG,Umu); // Unit gauge |   SU<Nc>::ColdConfiguration(pRNG,Umu); // Unit gauge | ||||||
|   Uorg=Umu; |   Uorg=Umu; | ||||||
|  |  | ||||||
|  |   Real init_plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|  |   std::cout << " Initial plaquette "<< init_plaq << std::endl; | ||||||
|  |  | ||||||
|  |   //Apply a random gauge transformation to the unit gauge config | ||||||
|   Urnd=Umu; |   Urnd=Umu; | ||||||
|  |   SU<Nc>::RandomGaugeTransform<Gimpl>(pRNG,Urnd,g); | ||||||
|  |  | ||||||
|   SU<Nc>::RandomGaugeTransform(pRNG,Urnd,g); // Unit gauge |   //Gauge fix the randomly transformed field  | ||||||
|  |  | ||||||
|   Real plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |  | ||||||
|   std::cout << " Initial plaquette "<<plaq << std::endl; |  | ||||||
|  |  | ||||||
|   Real alpha=0.1; |  | ||||||
|  |  | ||||||
|   Umu = Urnd; |   Umu = Urnd; | ||||||
|   FourierAcceleratedGaugeFixer<PeriodicGimplR>::SteepestDescentGaugeFix(Umu,xform1,alpha,10000,1.0e-12, 1.0e-12,false); |   FourierAcceleratedGaugeFixer<Gimpl>::SteepestDescentGaugeFix(Umu,xform1,alpha,10000,1.0e-12, 1.0e-12,false); | ||||||
|  |  | ||||||
|   // Check the gauge xform matrices |   // Check the gauge xform matrices | ||||||
|   Utmp=Urnd; |   Utmp=Urnd; | ||||||
|   SU<Nc>::GaugeTransform(Utmp,xform1); |   SU<Nc>::GaugeTransform<Gimpl>(Utmp,xform1); | ||||||
|   Utmp = Utmp - Umu; |   Utmp = Utmp - Umu; | ||||||
|   std::cout << " Norm Difference of xformed gauge "<< norm2(Utmp) << std::endl; |   std::cout << " Check the output gauge transformation matrices applied to the original field produce the xformed field "<< norm2(Utmp) << " (expect 0)" << std::endl; | ||||||
|    |    | ||||||
|  |  | ||||||
|   plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |   Real plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|   std::cout << " Final plaquette "<<plaq << std::endl; |   std::cout << " Final plaquette "<<plaq << " diff " << plaq - init_plaq << " (expect 0)" << std::endl; | ||||||
|  |  | ||||||
|   Uorg = Uorg - Umu; |   Uorg = Uorg - Umu; | ||||||
|   std::cout << " Norm Difference "<< norm2(Uorg) << std::endl; |   std::cout << " Norm difference between a unit gauge configuration and the gauge fixed configuration "<< norm2(Uorg) << " (expect 0)" << std::endl; | ||||||
|   std::cout << " Norm "<< norm2(Umu) << std::endl; |   std::cout << " Norm of gauge fixed configuration "<< norm2(Umu) << std::endl; | ||||||
|  |  | ||||||
|  |   //######################################################################################### | ||||||
|  |   if(do_fft_gfix){ | ||||||
|  |     std::cout<< "*************************************************************************************" <<std::endl; | ||||||
|  |     std::cout<< "* Testing Fourier accelerated fixing to Landau gauge with unit gauge configuration  *" <<std::endl; | ||||||
|  |     std::cout<< "*************************************************************************************" <<std::endl; | ||||||
|  |     Umu=Urnd; | ||||||
|  |     FourierAcceleratedGaugeFixer<Gimpl>::SteepestDescentGaugeFix(Umu,xform2,alpha,10000,1.0e-12, 1.0e-12,true); | ||||||
|  |  | ||||||
|  |     Utmp=Urnd; | ||||||
|  |     SU<Nc>::GaugeTransform<Gimpl>(Utmp,xform2); | ||||||
|  |     Utmp = Utmp - Umu; | ||||||
|  |     std::cout << " Check the output gauge transformation matrices applied to the original field produce the xformed field "<< norm2(Utmp) << " (expect 0)" << std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |     plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|   std::cout<< "* Testing Fourier accelerated fixing                            *" <<std::endl; |     std::cout << " Final plaquette "<<plaq << " diff " << plaq - init_plaq << " (expect 0)" << std::endl; | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |   } | ||||||
|   Umu=Urnd; |   //######################################################################################### | ||||||
|   FourierAcceleratedGaugeFixer<PeriodicGimplR>::SteepestDescentGaugeFix(Umu,xform2,alpha,10000,1.0e-12, 1.0e-12,true); |  | ||||||
|  |  | ||||||
|   Utmp=Urnd; |   std::cout<< "******************************************************************************************" <<std::endl; | ||||||
|   SU<Nc>::GaugeTransform(Utmp,xform2); |   std::cout<< "* Testing steepest descent fixing to Landau gauge with random configuration             **" <<std::endl; | ||||||
|   Utmp = Utmp - Umu; |   std::cout<< "******************************************************************************************" <<std::endl; | ||||||
|   std::cout << " Norm Difference of xformed gauge "<< norm2(Utmp) << std::endl; |  | ||||||
|  |  | ||||||
|  |   SU<Nc>::HotConfiguration(pRNG,Umu); | ||||||
|  |  | ||||||
|   plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |   init_plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|   std::cout << " Final plaquette "<<plaq << std::endl; |   std::cout << " Initial plaquette "<< init_plaq << std::endl; | ||||||
|  |  | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |   FourierAcceleratedGaugeFixer<Gimpl>::SteepestDescentGaugeFix(Umu,alpha,10000,1.0e-12, 1.0e-12,false); | ||||||
|   std::cout<< "* Testing non-unit configuration                                *" <<std::endl; |  | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |  | ||||||
|  |  | ||||||
|   SU<Nc>::HotConfiguration(pRNG,Umu); // Unit gauge |   plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|  |   std::cout << " Final plaquette "<<plaq << " diff " << plaq - init_plaq << " (expect 0)" << std::endl; | ||||||
|  |  | ||||||
|   plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |   //######################################################################################### | ||||||
|   std::cout << " Initial plaquette "<<plaq << std::endl; |   if(do_fft_gfix){ | ||||||
|  |     std::cout<< "******************************************************************************************" <<std::endl; | ||||||
|  |     std::cout<< "* Testing Fourier accelerated fixing to Landau gauge with random configuration          **" <<std::endl; | ||||||
|  |     std::cout<< "******************************************************************************************" <<std::endl; | ||||||
|  |  | ||||||
|   FourierAcceleratedGaugeFixer<PeriodicGimplR>::SteepestDescentGaugeFix(Umu,alpha,10000,1.0e-12, 1.0e-12,true); |     SU<Nc>::HotConfiguration(pRNG,Umu); | ||||||
|  |  | ||||||
|   plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |     init_plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|   std::cout << " Final plaquette "<<plaq << std::endl; |     std::cout << " Initial plaquette "<< init_plaq << std::endl; | ||||||
|  |  | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |     FourierAcceleratedGaugeFixer<Gimpl>::SteepestDescentGaugeFix(Umu,alpha,10000,1.0e-12, 1.0e-12,true); | ||||||
|   std::cout<< "* Testing Fourier accelerated fixing to coulomb gauge           *" <<std::endl; |  | ||||||
|   std::cout<< "*****************************************************************" <<std::endl; |     plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|  |     std::cout << " Final plaquette "<<plaq << " diff " << plaq - init_plaq << " (expect 0)" << std::endl; | ||||||
|  |   } | ||||||
|  |   //######################################################################################### | ||||||
|  |    | ||||||
|  |   std::cout<< "*******************************************************************************************" <<std::endl; | ||||||
|  |   std::cout<< "* Testing steepest descent fixing to coulomb gauge with random configuration           *" <<std::endl; | ||||||
|  |   std::cout<< "*******************************************************************************************" <<std::endl; | ||||||
|  |  | ||||||
|   Umu=Urnd; |   Umu=Urnd; | ||||||
|   SU<Nc>::HotConfiguration(pRNG,Umu); // Unit gauge |   SU<Nc>::HotConfiguration(pRNG,Umu); | ||||||
|  |  | ||||||
|   plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |   init_plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|   std::cout << " Initial plaquette "<<plaq << std::endl; |   std::cout << " Initial plaquette "<< init_plaq << std::endl; | ||||||
|  |  | ||||||
|   FourierAcceleratedGaugeFixer<PeriodicGimplR>::SteepestDescentGaugeFix(Umu,xform3,alpha,10000,1.0e-12, 1.0e-12,true,coulomb_dir); |   FourierAcceleratedGaugeFixer<Gimpl>::SteepestDescentGaugeFix(Umu,xform3,alpha,10000,1.0e-12, 1.0e-12,false,coulomb_dir); | ||||||
|  |  | ||||||
|   std::cout << Umu<<std::endl; |   plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|  |   std::cout << " Final plaquette "<<plaq << " diff " << plaq - init_plaq << " (expect 0)" << std::endl; | ||||||
|  |  | ||||||
|   plaq=WilsonLoops<PeriodicGimplR>::avgPlaquette(Umu); |  | ||||||
|   std::cout << " Final plaquette "<<plaq << std::endl; |   //######################################################################################### | ||||||
|  |   if(do_fft_gfix){ | ||||||
|  |     std::cout<< "*******************************************************************************************" <<std::endl; | ||||||
|  |     std::cout<< "* Testing Fourier accelerated fixing to coulomb gauge with random configuration           *" <<std::endl; | ||||||
|  |     std::cout<< "*******************************************************************************************" <<std::endl; | ||||||
|  |  | ||||||
|  |     Umu=Urnd; | ||||||
|  |     SU<Nc>::HotConfiguration(pRNG,Umu); | ||||||
|  |  | ||||||
|  |     init_plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|  |     std::cout << " Initial plaquette "<< init_plaq << std::endl; | ||||||
|  |  | ||||||
|  |     FourierAcceleratedGaugeFixer<Gimpl>::SteepestDescentGaugeFix(Umu,xform3,alpha,10000,1.0e-12, 1.0e-12,true,coulomb_dir); | ||||||
|  |  | ||||||
|  |     plaq=WilsonLoops<Gimpl>::avgPlaquette(Umu); | ||||||
|  |     std::cout << " Final plaquette "<<plaq << " diff " << plaq - init_plaq << " (expect 0)" << std::endl; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main (int argc, char ** argv) | ||||||
|  | { | ||||||
|  |   Grid_init(&argc,&argv); | ||||||
|  |  | ||||||
|  |   double alpha=0.1; //step size | ||||||
|  |   std::string gimpl = "periodic"; | ||||||
|  |   bool do_fft_gfix = true; //test fourier transformed gfix as well as steepest descent | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string sarg(argv[i]); | ||||||
|  |     if(sarg == "--gimpl"){ | ||||||
|  |       assert(i<argc-1 && "--gimpl option requires an argument"); | ||||||
|  |       gimpl = argv[i+1]; | ||||||
|  |       if(gimpl != "periodic" && gimpl != "conjugate") | ||||||
|  | 	assert(0 && "Invalid gimpl"); | ||||||
|  |     }else if(sarg == "--no-fft-gfix"){ | ||||||
|  |       std::cout << "Not doing the Fourier accelerated gauge fixing tests" << std::endl; | ||||||
|  |       do_fft_gfix = false; | ||||||
|  |     }else if(sarg == "--alpha"){ | ||||||
|  |       assert(i<argc-1 && "--alpha option requires an argument"); | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> alpha; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   if(gimpl == "periodic"){ | ||||||
|  |     std::cout << GridLogMessage << "Using periodic boundary condition" << std::endl; | ||||||
|  |     run<PeriodicGimplR>(alpha, do_fft_gfix); | ||||||
|  |   }else{ | ||||||
|  |     std::vector<int> conjdirs = {1,1,0,0}; //test with 2 conjugate dirs and 2 not | ||||||
|  |     std::cout << GridLogMessage << "Using complex conjugate boundary conditions in dimensions "; | ||||||
|  |     for(int i=0;i<Nd;i++) | ||||||
|  |       if(conjdirs[i]) | ||||||
|  | 	std::cout << i << " ";    | ||||||
|  |     std::cout << std::endl; | ||||||
|  |  | ||||||
|  |     ConjugateGimplR::setDirections(conjdirs); | ||||||
|  |     run<ConjugateGimplR>(alpha, do_fft_gfix); | ||||||
|  |   } | ||||||
|    |    | ||||||
|   Grid_finalize(); |   Grid_finalize(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -228,6 +228,59 @@ void checkGammaL(const Gamma::Algebra a, GridSerialRNG &rng) | |||||||
|   std::cout << std::endl; |   std::cout << std::endl; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void checkChargeConjMatrix(){ | ||||||
|  |   //Check the properties of the charge conjugation matrix | ||||||
|  |   //In the Grid basis C = -\gamma^2 \gamma^4 | ||||||
|  |   SpinMatrix C = testAlgebra[Gamma::Algebra::MinusGammaY] * testAlgebra[Gamma::Algebra::GammaT]; | ||||||
|  |   SpinMatrix mC = -C; | ||||||
|  |   SpinMatrix one = testAlgebra[Gamma::Algebra::Identity]; | ||||||
|  |  | ||||||
|  |   std::cout << "Testing properties of charge conjugation matrix C = -\\gamma^2 \\gamma^4 (in Grid's basis)" << std::endl; | ||||||
|  |  | ||||||
|  |   //C^T = -C | ||||||
|  |   SpinMatrix Ct = transpose(C); | ||||||
|  |   std::cout << GridLogMessage << "C^T=-C "; | ||||||
|  |   test(Ct, mC); | ||||||
|  |   std::cout << std::endl; | ||||||
|  |  | ||||||
|  |   //C^\dagger = -C | ||||||
|  |   SpinMatrix Cdag = adj(C); | ||||||
|  |   std::cout << GridLogMessage << "C^dag=-C "; | ||||||
|  |   test(Cdag, mC); | ||||||
|  |   std::cout << std::endl; | ||||||
|  |  | ||||||
|  |   //C^* = C | ||||||
|  |   SpinMatrix Cstar = conjugate(C); | ||||||
|  |   std::cout << GridLogMessage << "C^*=C "; | ||||||
|  |   test(Cstar, C); | ||||||
|  |   std::cout << std::endl; | ||||||
|  |  | ||||||
|  |   //C^{-1} = -C | ||||||
|  |   SpinMatrix CinvC = mC * C; | ||||||
|  |   std::cout << GridLogMessage << "C^{-1}=-C "; | ||||||
|  |   test(CinvC, one); | ||||||
|  |   std::cout << std::endl; | ||||||
|  |  | ||||||
|  |   // C^{-1} \gamma^\mu C = -[\gamma^\mu]^T | ||||||
|  |   Gamma::Algebra gmu_a[4] = { Gamma::Algebra::GammaX, Gamma::Algebra::GammaY, Gamma::Algebra::GammaZ, Gamma::Algebra::GammaT }; | ||||||
|  |   for(int mu=0;mu<4;mu++){ | ||||||
|  |     SpinMatrix gmu = testAlgebra[gmu_a[mu]]; | ||||||
|  |     SpinMatrix Cinv_gmu_C = mC * gmu * C; | ||||||
|  |     SpinMatrix mgmu_T = -transpose(gmu); | ||||||
|  |     std::cout << GridLogMessage << "C^{-1} \\gamma^" << mu << " C = -[\\gamma^" << mu << "]^T "; | ||||||
|  |     test(Cinv_gmu_C, mgmu_T); | ||||||
|  |     std::cout << std::endl; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   //[C, \gamma^5] = 0 | ||||||
|  |   SpinMatrix Cg5 = C * testAlgebra[Gamma::Algebra::Gamma5]; | ||||||
|  |   SpinMatrix g5C = testAlgebra[Gamma::Algebra::Gamma5] * C; | ||||||
|  |   std::cout << GridLogMessage << "C \\gamma^5 = \\gamma^5 C"; | ||||||
|  |   test(Cg5, g5C); | ||||||
|  |   std::cout << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
|   Grid_init(&argc,&argv); |   Grid_init(&argc,&argv); | ||||||
| @@ -271,6 +324,13 @@ int main(int argc, char *argv[]) | |||||||
|     checkGammaL(i, sRNG); |     checkGammaL(i, sRNG); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << "======== Charge conjugation matrix check" << std::endl; | ||||||
|  |   checkChargeConjMatrix(); | ||||||
|  |   std::cout << GridLogMessage << std::endl; | ||||||
|  |    | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    | ||||||
|   Grid_finalize(); |   Grid_finalize(); | ||||||
|    |    | ||||||
|   return EXIT_SUCCESS; |   return EXIT_SUCCESS; | ||||||
|   | |||||||
| @@ -55,6 +55,7 @@ static_assert(same_vComplex == 1, "Dirac Operators must have same underlying SIM | |||||||
| int main (int argc, char ** argv) | int main (int argc, char ** argv) | ||||||
| { | { | ||||||
|   int nu = 0; |   int nu = 0; | ||||||
|  |   int tbc_aprd = 0; //use antiperiodic BCs in the time direction? | ||||||
|    |    | ||||||
|   Grid_init(&argc,&argv); |   Grid_init(&argc,&argv); | ||||||
|  |  | ||||||
| @@ -62,6 +63,9 @@ int main (int argc, char ** argv) | |||||||
|     if(std::string(argv[i]) == "--Gparity-dir"){ |     if(std::string(argv[i]) == "--Gparity-dir"){ | ||||||
|       std::stringstream ss; ss << argv[i+1]; ss >> nu; |       std::stringstream ss; ss << argv[i+1]; ss >> nu; | ||||||
|       std::cout << GridLogMessage << "Set Gparity direction to " << nu << std::endl; |       std::cout << GridLogMessage << "Set Gparity direction to " << nu << std::endl; | ||||||
|  |     }else if(std::string(argv[i]) == "--Tbc-APRD"){ | ||||||
|  |       tbc_aprd = 1; | ||||||
|  |       std::cout << GridLogMessage << "Using antiperiodic BCs in the time direction" << std::endl; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -155,13 +159,18 @@ int main (int argc, char ** argv) | |||||||
|  |  | ||||||
|   //Coordinate grid for reference |   //Coordinate grid for reference | ||||||
|   LatticeInteger    xcoor_1f5(FGrid_1f); |   LatticeInteger    xcoor_1f5(FGrid_1f); | ||||||
|   LatticeCoordinate(xcoor_1f5,1+nu); |   LatticeCoordinate(xcoor_1f5,1+nu); //note '1+nu'! This is because for 5D fields the s-direction is direction 0 | ||||||
|   Replicate(src,src_1f); |   Replicate(src,src_1f); | ||||||
|   src_1f   = where( xcoor_1f5 >= Integer(L), 2.0*src_1f,src_1f ); |   src_1f   = where( xcoor_1f5 >= Integer(L), 2.0*src_1f,src_1f ); | ||||||
|  |  | ||||||
|   RealD mass=0.0; |   RealD mass=0.0; | ||||||
|   RealD M5=1.8; |   RealD M5=1.8; | ||||||
|   StandardDiracOp Ddwf(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f,mass,M5 DOP_PARAMS); |  | ||||||
|  |   //Standard Dirac op | ||||||
|  |   AcceleratorVector<Complex,4> bc_std(Nd, 1.0); | ||||||
|  |   if(tbc_aprd) bc_std[Nd-1] = -1.; //antiperiodic time BC | ||||||
|  |   StandardDiracOp::ImplParams std_params(bc_std); | ||||||
|  |   StandardDiracOp Ddwf(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f,mass,M5 DOP_PARAMS, std_params); | ||||||
|  |  | ||||||
|   StandardFermionField    src_o_1f(FrbGrid_1f); |   StandardFermionField    src_o_1f(FrbGrid_1f); | ||||||
|   StandardFermionField result_o_1f(FrbGrid_1f); |   StandardFermionField result_o_1f(FrbGrid_1f); | ||||||
| @@ -172,9 +181,11 @@ int main (int argc, char ** argv) | |||||||
|   ConjugateGradient<StandardFermionField> CG(1.0e-8,10000); |   ConjugateGradient<StandardFermionField> CG(1.0e-8,10000); | ||||||
|   CG(HermOpEO,src_o_1f,result_o_1f); |   CG(HermOpEO,src_o_1f,result_o_1f); | ||||||
|    |    | ||||||
|   //  const int nu = 3; |   //Gparity Dirac op | ||||||
|   std::vector<int> twists(Nd,0); |   std::vector<int> twists(Nd,0); | ||||||
|   twists[nu] = 1; |   twists[nu] = 1; | ||||||
|  |   if(tbc_aprd) twists[Nd-1] = 1; | ||||||
|  |  | ||||||
|   GparityDiracOp::ImplParams params; |   GparityDiracOp::ImplParams params; | ||||||
|   params.twists = twists; |   params.twists = twists; | ||||||
|   GparityDiracOp GPDdwf(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f,mass,M5 DOP_PARAMS,params); |   GparityDiracOp GPDdwf(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f,mass,M5 DOP_PARAMS,params); | ||||||
| @@ -271,8 +282,11 @@ int main (int argc, char ** argv) | |||||||
|   std::cout << "2f cb "<<result_o_2f.Checkerboard()<<std::endl; |   std::cout << "2f cb "<<result_o_2f.Checkerboard()<<std::endl; | ||||||
|   std::cout << "1f cb "<<result_o_1f.Checkerboard()<<std::endl; |   std::cout << "1f cb "<<result_o_1f.Checkerboard()<<std::endl; | ||||||
|  |  | ||||||
|   std::cout << " result norms " <<norm2(result_o_2f)<<" " <<norm2(result_o_1f)<<std::endl; |   //Compare norms | ||||||
|  |   std::cout << " result norms 2f: " <<norm2(result_o_2f)<<" 1f: " <<norm2(result_o_1f)<<std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Take the 2f solution and convert into the corresponding 1f solution (odd cb only) | ||||||
|   StandardFermionField    res0o  (FrbGrid_2f);  |   StandardFermionField    res0o  (FrbGrid_2f);  | ||||||
|   StandardFermionField    res1o  (FrbGrid_2f);  |   StandardFermionField    res1o  (FrbGrid_2f);  | ||||||
|   StandardFermionField    res0  (FGrid_2f);  |   StandardFermionField    res0  (FGrid_2f);  | ||||||
| @@ -281,12 +295,13 @@ int main (int argc, char ** argv) | |||||||
|   res0=Zero(); |   res0=Zero(); | ||||||
|   res1=Zero(); |   res1=Zero(); | ||||||
|  |  | ||||||
|   res0o = PeekIndex<0>(result_o_2f,0); |   res0o = PeekIndex<0>(result_o_2f,0); //flavor 0, odd cb | ||||||
|   res1o = PeekIndex<0>(result_o_2f,1); |   res1o = PeekIndex<0>(result_o_2f,1); //flavor 1, odd cb | ||||||
|  |  | ||||||
|   std::cout << "res cb "<<res0o.Checkerboard()<<std::endl; |   std::cout << "res cb "<<res0o.Checkerboard()<<std::endl; | ||||||
|   std::cout << "res cb "<<res1o.Checkerboard()<<std::endl; |   std::cout << "res cb "<<res1o.Checkerboard()<<std::endl; | ||||||
|  |  | ||||||
|  |   //poke odd onto non-cb field | ||||||
|   setCheckerboard(res0,res0o);  |   setCheckerboard(res0,res0o);  | ||||||
|   setCheckerboard(res1,res1o);  |   setCheckerboard(res1,res1o);  | ||||||
|  |  | ||||||
| @@ -296,12 +311,13 @@ int main (int argc, char ** argv) | |||||||
|   Replicate(res0,replica0); |   Replicate(res0,replica0); | ||||||
|   Replicate(res1,replica1); |   Replicate(res1,replica1); | ||||||
|  |  | ||||||
|  |   //2nd half of doubled lattice has f=1 | ||||||
|   replica = where( xcoor_1f5 >= Integer(L), replica1,replica0 ); |   replica = where( xcoor_1f5 >= Integer(L), replica1,replica0 ); | ||||||
|  |  | ||||||
|   replica0 = Zero(); |   replica0 = Zero(); | ||||||
|   setCheckerboard(replica0,result_o_1f); |   setCheckerboard(replica0,result_o_1f); | ||||||
|  |  | ||||||
|   std::cout << "Norm2 solutions is " <<norm2(replica)<<" "<< norm2(replica0)<<std::endl; |   std::cout << "Norm2 solutions 1f reconstructed from 2f: " <<norm2(replica)<<" Actual 1f: "<< norm2(replica0)<<std::endl; | ||||||
|  |  | ||||||
|   replica = replica - replica0; |   replica = replica - replica0; | ||||||
|    |    | ||||||
|   | |||||||
							
								
								
									
										177
									
								
								tests/core/Test_gparity_flavour.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								tests/core/Test_gparity_flavour.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  | Source file: ./tests/Test_gparity_flavour.cc | ||||||
|  |  | ||||||
|  | Copyright (C) 2015-2017 | ||||||
|  |  | ||||||
|  | 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 */ | ||||||
|  | #include <Grid/Grid.h> | ||||||
|  |  | ||||||
|  | using namespace Grid; | ||||||
|  |  | ||||||
|  | static constexpr double                      tolerance = 1.0e-6; | ||||||
|  | static std::array<GparityFlavourMatrix, GparityFlavour::nSigma> testAlgebra; | ||||||
|  |  | ||||||
|  | void print(const GparityFlavourMatrix &g) | ||||||
|  | { | ||||||
|  |   for(int i = 0; i < Ngp; i++) | ||||||
|  |   { | ||||||
|  |     std::cout << GridLogMessage << "("; | ||||||
|  |     for(int j=0;j<Ngp;j++){ | ||||||
|  |       if ( abs( g(i,j)()() ) == 0 ) { | ||||||
|  |         std::cout<< " 0"; | ||||||
|  |       } else if ( abs(g(i,j)()() - Complex(0,1)) == 0){ | ||||||
|  |         std::cout<< " i"; | ||||||
|  |       } else if ( abs(g(i,j)()() + Complex(0,1)) == 0){ | ||||||
|  |         std::cout<< "-i"; | ||||||
|  |       } else if ( abs(g(i,j)()() - Complex(1,0)) == 0){ | ||||||
|  |         std::cout<< " 1"; | ||||||
|  |       } else if ( abs(g(i,j)()() + Complex(1,0)) == 0){ | ||||||
|  |         std::cout<< "-1"; | ||||||
|  |       } | ||||||
|  |       std::cout<<((j == Ngp-1) ? ")" : "," ); | ||||||
|  |     } | ||||||
|  |     std::cout << std::endl; | ||||||
|  |   } | ||||||
|  |   std::cout << GridLogMessage << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void createTestAlgebra(void) | ||||||
|  | { | ||||||
|  |   std::array<GparityFlavourMatrix, 3> testg; | ||||||
|  |   const Complex             I(0., 1.), mI(0., -1.); | ||||||
|  |  | ||||||
|  |   // 0 1 | ||||||
|  |   // 1 0 | ||||||
|  |   testg[0] = Zero(); | ||||||
|  |   testg[0](0, 1)()() = 1.; | ||||||
|  |   testg[0](1, 0)()() = 1.; | ||||||
|  |   std::cout << GridLogMessage << "test SigmaX= " << std::endl; | ||||||
|  |   print(testg[0]); | ||||||
|  |  | ||||||
|  |   // 0 -i | ||||||
|  |   // i  0 | ||||||
|  |   testg[1] = Zero(); | ||||||
|  |   testg[1](0, 1)()() = mI; | ||||||
|  |   testg[1](1, 0)()() = I; | ||||||
|  |   std::cout << GridLogMessage << "test SigmaY= " << std::endl; | ||||||
|  |   print(testg[1]); | ||||||
|  |  | ||||||
|  |   // 1  0 | ||||||
|  |   // 0 -1 | ||||||
|  |   testg[2] = Zero(); | ||||||
|  |   testg[2](0, 0)()() = 1.0; | ||||||
|  |   testg[2](1, 1)()() = -1.0; | ||||||
|  |   std::cout << GridLogMessage << "test SigmaZ= " << std::endl; | ||||||
|  |   print(testg[2]); | ||||||
|  |  | ||||||
|  |    | ||||||
|  | #define DEFINE_TEST_G(g, exp)\ | ||||||
|  | testAlgebra[GparityFlavour::Algebra::g]        = exp; \ | ||||||
|  | testAlgebra[GparityFlavour::Algebra::Minus##g] = -exp; | ||||||
|  |    | ||||||
|  |   DEFINE_TEST_G(SigmaX      , testg[0]); | ||||||
|  |   DEFINE_TEST_G(SigmaY      , testg[1]); | ||||||
|  |   DEFINE_TEST_G(SigmaZ      , testg[2]); | ||||||
|  |   DEFINE_TEST_G(Identity    , 1.); | ||||||
|  |  | ||||||
|  |   GparityFlavourMatrix pplus; | ||||||
|  |   pplus = 1.0; | ||||||
|  |   pplus = pplus + testg[1]; | ||||||
|  |   pplus = pplus * 0.5; | ||||||
|  |  | ||||||
|  |   DEFINE_TEST_G(ProjPlus    , pplus); | ||||||
|  |    | ||||||
|  |   GparityFlavourMatrix pminus; | ||||||
|  |   pminus = 1.0; | ||||||
|  |   pminus = pminus - testg[1]; | ||||||
|  |   pminus = pminus * 0.5; | ||||||
|  |  | ||||||
|  |   DEFINE_TEST_G(ProjMinus    , pminus); | ||||||
|  |  | ||||||
|  | #undef DEFINE_TEST_G | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Expr> | ||||||
|  | void test(const Expr &a, const Expr &b) | ||||||
|  | { | ||||||
|  |   if (norm2(a - b) < tolerance) | ||||||
|  |   { | ||||||
|  |     std::cout << "[OK] "; | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     std::cout << "[fail]" << std::endl; | ||||||
|  |     std::cout << GridLogError << "a= " << a << std::endl; | ||||||
|  |     std::cout << GridLogError << "is different (tolerance= " << tolerance << ") from " << std::endl; | ||||||
|  |     std::cout << GridLogError << "b= " << b << std::endl; | ||||||
|  |     exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void checkSigma(const GparityFlavour::Algebra a, GridSerialRNG &rng) | ||||||
|  | { | ||||||
|  |   GparityFlavourVector v; | ||||||
|  |   GparityFlavourMatrix m, &testg = testAlgebra[a]; | ||||||
|  |   GparityFlavour      g(a); | ||||||
|  |    | ||||||
|  |   random(rng, v); | ||||||
|  |   random(rng, m); | ||||||
|  |    | ||||||
|  |   std::cout << GridLogMessage << "Checking " << GparityFlavour::name[a] << ": "; | ||||||
|  |   std::cout << "vecmul "; | ||||||
|  |   test(g*v, testg*v); | ||||||
|  |   std::cout << "matlmul "; | ||||||
|  |   test(g*m, testg*m); | ||||||
|  |   std::cout << "matrmul "; | ||||||
|  |   test(m*g, m*testg); | ||||||
|  |   std::cout << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  |   Grid_init(&argc,&argv); | ||||||
|  |    | ||||||
|  |   Coordinate latt_size   = GridDefaultLatt(); | ||||||
|  |   Coordinate simd_layout = GridDefaultSimd(4,vComplex::Nsimd()); | ||||||
|  |   Coordinate mpi_layout  = GridDefaultMpi(); | ||||||
|  |    | ||||||
|  |   GridCartesian Grid(latt_size,simd_layout,mpi_layout); | ||||||
|  |   GridSerialRNG sRNG; | ||||||
|  |    | ||||||
|  |   sRNG.SeedFixedIntegers(std::vector<int>({45,12,81,9})); | ||||||
|  |    | ||||||
|  |   std::cout << GridLogMessage << "======== Test algebra" << std::endl; | ||||||
|  |   createTestAlgebra(); | ||||||
|  |   std::cout << GridLogMessage << "======== Multiplication operators check" << std::endl; | ||||||
|  |   for (int i = 0; i < GparityFlavour::nSigma; ++i) | ||||||
|  |   { | ||||||
|  |     checkSigma(i, sRNG); | ||||||
|  |   } | ||||||
|  |   std::cout << GridLogMessage << std::endl; | ||||||
|  |    | ||||||
|  |   Grid_finalize(); | ||||||
|  |    | ||||||
|  |   return EXIT_SUCCESS; | ||||||
|  | } | ||||||
							
								
								
									
										114
									
								
								tests/core/Test_precision_change.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								tests/core/Test_precision_change.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/core/Test_precision_change.cc | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  |  | ||||||
|  |     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; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main (int argc, char ** argv){ | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |   int Ls = 16; | ||||||
|  |   std::cout << GridLogMessage << "Lattice dimensions: " << GridDefaultLatt() << " and Ls=" << Ls << std::endl; | ||||||
|  |   GridCartesian* UGrid_d = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexD::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridCartesian* FGrid_d = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid_d); | ||||||
|  |   GridRedBlackCartesian* FrbGrid_d = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid_d); | ||||||
|  |  | ||||||
|  |   GridCartesian* UGrid_f = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridCartesian* FGrid_f = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid_f); | ||||||
|  |   GridRedBlackCartesian* FrbGrid_f = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid_f); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   std::vector<int> seeds4({1, 2, 3, 4}); | ||||||
|  |   std::vector<int> seeds5({5, 6, 7, 8}); | ||||||
|  |   GridParallelRNG RNG5(FGrid_d); | ||||||
|  |   RNG5.SeedFixedIntegers(seeds5); | ||||||
|  |   GridParallelRNG RNG4(UGrid_d); | ||||||
|  |   RNG4.SeedFixedIntegers(seeds4); | ||||||
|  |  | ||||||
|  |   //Gauge fields | ||||||
|  |   LatticeGaugeFieldD Umu_d(UGrid_d); | ||||||
|  |   LatticeGaugeFieldF Umu_f(UGrid_f); | ||||||
|  |   LatticeGaugeFieldD Umu_d_r(UGrid_d); | ||||||
|  |   LatticeGaugeFieldD Utmp_d(UGrid_d); | ||||||
|  |  | ||||||
|  |   for(int i=0;i<5;i++){ | ||||||
|  |     random(RNG4, Umu_d); | ||||||
|  |  | ||||||
|  |     precisionChange(Umu_f, Umu_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of double-prec and single-prec gauge fields (should be ~equal): " << norm2(Umu_d) << " " << norm2(Umu_f) << std::endl; | ||||||
|  |     precisionChange(Umu_d_r, Umu_f); | ||||||
|  |     RealD normdiff = axpy_norm(Utmp_d, -1.0, Umu_d_r, Umu_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of difference of back-converted double-prec gauge fields (should be ~0) = " << normdiff << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Fermion fields | ||||||
|  |   LatticeFermionD psi_d(FGrid_d); | ||||||
|  |   LatticeFermionF psi_f(FGrid_f); | ||||||
|  |   LatticeFermionD psi_d_r(FGrid_d); | ||||||
|  |   LatticeFermionD psi_tmp_d(FGrid_d); | ||||||
|  |  | ||||||
|  |   for(int i=0;i<5;i++){ | ||||||
|  |     random(RNG5, psi_d); | ||||||
|  |  | ||||||
|  |     precisionChange(psi_f, psi_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of double-prec and single-prec fermion fields (should be ~equal): " << norm2(psi_d) << " " << norm2(psi_f) << std::endl; | ||||||
|  |     precisionChange(psi_d_r, psi_f); | ||||||
|  |     RealD normdiff = axpy_norm(psi_tmp_d, -1.0, psi_d_r, psi_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of difference of back-converted double-prec fermion fields (should be ~0)= " << normdiff << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Checkerboarded fermion fields | ||||||
|  |   LatticeFermionD psi_cb_d(FrbGrid_d); | ||||||
|  |   LatticeFermionF psi_cb_f(FrbGrid_f); | ||||||
|  |   LatticeFermionD psi_cb_d_r(FrbGrid_d); | ||||||
|  |   LatticeFermionD psi_cb_tmp_d(FrbGrid_d); | ||||||
|  |  | ||||||
|  |   for(int i=0;i<5;i++){ | ||||||
|  |     random(RNG5, psi_d); | ||||||
|  |     pickCheckerboard(Odd, psi_cb_d, psi_d); | ||||||
|  |       | ||||||
|  |     precisionChange(psi_cb_f, psi_cb_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of odd-cb double-prec and single-prec fermion fields (should be ~equal): " << norm2(psi_cb_d) << " " << norm2(psi_cb_f) << std::endl; | ||||||
|  |     precisionChange(psi_cb_d_r, psi_cb_f); | ||||||
|  |     RealD normdiff = axpy_norm(psi_cb_tmp_d, -1.0, psi_cb_d_r, psi_cb_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of difference of back-converted odd-cb double-prec fermion fields (should be ~0)= " << normdiff << std::endl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     pickCheckerboard(Even, psi_cb_d, psi_d); | ||||||
|  |       | ||||||
|  |     precisionChange(psi_cb_f, psi_cb_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of even-cb double-prec and single-prec fermion fields (should be ~equal): " << norm2(psi_cb_d) << " " << norm2(psi_cb_f) << std::endl; | ||||||
|  |     precisionChange(psi_cb_d_r, psi_cb_f); | ||||||
|  |     normdiff = axpy_norm(psi_cb_tmp_d, -1.0, psi_cb_d_r, psi_cb_d); | ||||||
|  |     std::cout << GridLogMessage << "Norm of difference of back-converted even-cb double-prec fermion fields (should be ~0)= " << normdiff << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  | } | ||||||
| @@ -71,26 +71,14 @@ int main (int argc, char ** argv) | |||||||
|   //////////////////////////////////// |   //////////////////////////////////// | ||||||
|   RealD mass=0.2; //kills the diagonal term |   RealD mass=0.2; //kills the diagonal term | ||||||
|   RealD M5=1.8; |   RealD M5=1.8; | ||||||
|   //  const int nu = 3; |  | ||||||
|   //  std::vector<int> twists(Nd,0); // twists[nu] = 1; |  | ||||||
|   //  GparityDomainWallFermionR::ImplParams params;  params.twists = twists; |  | ||||||
|   //  GparityDomainWallFermionR Ddwf(U,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,params); |  | ||||||
|  |  | ||||||
|   //  DomainWallFermionR Dw     (U,     Grid,RBGrid,mass,M5); |   const int nu = 0; //gparity direction | ||||||
|  |  | ||||||
|   const int nu = 3; |  | ||||||
|   std::vector<int> twists(Nd,0); |   std::vector<int> twists(Nd,0); | ||||||
|   twists[nu] = 1; |   twists[nu] = 1; | ||||||
|  |   twists[Nd-1] = 1; //antiperiodic in time | ||||||
|   GparityDomainWallFermionR::ImplParams params; |   GparityDomainWallFermionR::ImplParams params; | ||||||
|   params.twists = twists; |   params.twists = twists; | ||||||
|   |   | ||||||
|   /* |  | ||||||
|   params.boundary_phases[0] = 1.0; |  | ||||||
|   params.boundary_phases[1] = 1.0; |  | ||||||
|   params.boundary_phases[2] = 1.0; |  | ||||||
|   params.boundary_phases[3] =- 1.0; |  | ||||||
|   */ |  | ||||||
|    |  | ||||||
|   GparityDomainWallFermionR Dw(U,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,params); |   GparityDomainWallFermionR Dw(U,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,params); | ||||||
|  |  | ||||||
|   Dw.M   (phi,Mphi); |   Dw.M   (phi,Mphi); | ||||||
|   | |||||||
| @@ -71,8 +71,10 @@ int main (int argc, char ** argv) | |||||||
|   RealD mass=0.01;  |   RealD mass=0.01;  | ||||||
|   RealD M5=1.8;  |   RealD M5=1.8;  | ||||||
|  |  | ||||||
|   const int nu = 3; |   const int nu = 1; | ||||||
|   std::vector<int> twists(Nd,0);  twists[nu] = 1; |   std::vector<int> twists(Nd,0); | ||||||
|  |   twists[nu] = 1; | ||||||
|  |   twists[3] = 1; | ||||||
|   GparityDomainWallFermionR::ImplParams params;  params.twists = twists; |   GparityDomainWallFermionR::ImplParams params;  params.twists = twists; | ||||||
|   GparityDomainWallFermionR Ddwf(U,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,params); |   GparityDomainWallFermionR Ddwf(U,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,params); | ||||||
|   Ddwf.M   (phi,Mphi); |   Ddwf.M   (phi,Mphi); | ||||||
| @@ -91,16 +93,28 @@ int main (int argc, char ** argv) | |||||||
|   //////////////////////////////////// |   //////////////////////////////////// | ||||||
|   // Modify the gauge field a little  |   // Modify the gauge field a little  | ||||||
|   //////////////////////////////////// |   //////////////////////////////////// | ||||||
|   RealD dt = 0.0001; |   RealD dt = 0.01; | ||||||
|  |  | ||||||
|  |   LatticeColourMatrix zz(UGrid); zz=Zero(); | ||||||
|   LatticeColourMatrix mommu(UGrid);  |   LatticeColourMatrix mommu(UGrid);  | ||||||
|   LatticeColourMatrix forcemu(UGrid);  |   LatticeColourMatrix forcemu(UGrid);  | ||||||
|   LatticeGaugeField mom(UGrid);  |   LatticeGaugeField mom(UGrid);  | ||||||
|   LatticeGaugeField Uprime(UGrid);  |   LatticeGaugeField Uprime(UGrid);  | ||||||
|  |  | ||||||
|  |   const int Lnu=latt_size[nu]; | ||||||
|  |   Lattice<iScalar<vInteger> > coor(UGrid); | ||||||
|  |   LatticeCoordinate(coor,nu); | ||||||
|   for(int mu=0;mu<Nd;mu++){ |   for(int mu=0;mu<Nd;mu++){ | ||||||
|  |  | ||||||
|     SU<Nc>::GaussianFundamentalLieAlgebraMatrix(RNG4, mommu); // Traceless antihermitian momentum; gaussian in lie alg |     // Traceless antihermitian momentum; gaussian in lie alg | ||||||
|  |     SU<Nc>::GaussianFundamentalLieAlgebraMatrix(RNG4, mommu); | ||||||
|  |     if(0){ | ||||||
|  |       if(mu==nu){ | ||||||
|  | 	mommu=where(coor==Lnu-1,mommu,zz); | ||||||
|  |       } else { | ||||||
|  | 	mommu=Zero(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     PokeIndex<LorentzIndex>(mom,mommu,mu); |     PokeIndex<LorentzIndex>(mom,mommu,mu); | ||||||
|  |  | ||||||
| @@ -125,6 +139,12 @@ int main (int argc, char ** argv) | |||||||
|  |  | ||||||
|   ComplexD Sprime    = innerProduct(MphiPrime   ,MphiPrime); |   ComplexD Sprime    = innerProduct(MphiPrime   ,MphiPrime); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   LatticeComplex lip(FGrid); lip=localInnerProduct(Mphi,Mphi); | ||||||
|  |   LatticeComplex lipp(FGrid); lipp=localInnerProduct(MphiPrime,MphiPrime); | ||||||
|  |   LatticeComplex dip(FGrid); dip = lipp - lip; | ||||||
|  |   std::cout << " dip "<<dip<<std::endl; | ||||||
|  |    | ||||||
|   ////////////////////////////////////////////// |   ////////////////////////////////////////////// | ||||||
|   // Use derivative to estimate dS |   // Use derivative to estimate dS | ||||||
|   ////////////////////////////////////////////// |   ////////////////////////////////////////////// | ||||||
|   | |||||||
							
								
								
									
										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); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -64,8 +64,12 @@ int main (int argc, char ** argv) | |||||||
|   //////////////////////////////////// |   //////////////////////////////////// | ||||||
|   RealD mass=0.01;  |   RealD mass=0.01;  | ||||||
|  |  | ||||||
|   const int nu = 3; |   const int nu = 1; | ||||||
|   std::vector<int> twists(Nd,0);  twists[nu] = 1; |   const int Lnu=latt_size[nu]; | ||||||
|  |  | ||||||
|  |   std::vector<int> twists(Nd,0); | ||||||
|  |   twists[nu] = 1; | ||||||
|  |   twists[3]=1; | ||||||
|   GparityWilsonFermionR::ImplParams params;  params.twists = twists; |   GparityWilsonFermionR::ImplParams params;  params.twists = twists; | ||||||
|   GparityWilsonFermionR Wil(U,*UGrid,*UrbGrid,mass,params); |   GparityWilsonFermionR Wil(U,*UGrid,*UrbGrid,mass,params); | ||||||
|   Wil.M   (phi,Mphi); |   Wil.M   (phi,Mphi); | ||||||
| @@ -87,15 +91,26 @@ int main (int argc, char ** argv) | |||||||
|   RealD dt = 0.01; |   RealD dt = 0.01; | ||||||
|  |  | ||||||
|   LatticeColourMatrix mommu(UGrid);  |   LatticeColourMatrix mommu(UGrid);  | ||||||
|  |   LatticeColourMatrix zz(UGrid); | ||||||
|   LatticeColourMatrix forcemu(UGrid);  |   LatticeColourMatrix forcemu(UGrid);  | ||||||
|   LatticeGaugeField mom(UGrid);  |   LatticeGaugeField mom(UGrid);  | ||||||
|   LatticeGaugeField Uprime(UGrid);  |   LatticeGaugeField Uprime(UGrid);  | ||||||
|  |  | ||||||
|  |    | ||||||
|  |   Lattice<iScalar<vInteger> > coor(UGrid); | ||||||
|  |   LatticeCoordinate(coor,nu); | ||||||
|  |   zz=Zero(); | ||||||
|   for(int mu=0;mu<Nd;mu++){ |   for(int mu=0;mu<Nd;mu++){ | ||||||
|  |  | ||||||
|     // Traceless antihermitian momentum; gaussian in lie alg |     // Traceless antihermitian momentum; gaussian in lie alg | ||||||
|     SU<Nc>::GaussianFundamentalLieAlgebraMatrix(RNG4, mommu); |     SU<Nc>::GaussianFundamentalLieAlgebraMatrix(RNG4, mommu); | ||||||
|  |     if(0){ | ||||||
|  |       if(mu==nu){ | ||||||
|  | 	mommu=where(coor==Lnu-1,mommu,zz); | ||||||
|  |       } else { | ||||||
|  | 	mommu=Zero(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|     PokeIndex<LorentzIndex>(mom,mommu,mu); |     PokeIndex<LorentzIndex>(mom,mommu,mu); | ||||||
|      |      | ||||||
|     // fourth order exponential approx |     // fourth order exponential approx | ||||||
| @@ -130,6 +145,10 @@ int main (int argc, char ** argv) | |||||||
|     mommu=Ta(mommu)*2.0; |     mommu=Ta(mommu)*2.0; | ||||||
|     PokeIndex<LorentzIndex>(UdSdU,mommu,mu); |     PokeIndex<LorentzIndex>(UdSdU,mommu,mu); | ||||||
|   } |   } | ||||||
|  |   LatticeComplex lip(UGrid); lip=localInnerProduct(Mphi,Mphi); | ||||||
|  |   LatticeComplex lipp(UGrid); lipp=localInnerProduct(MphiPrime,MphiPrime); | ||||||
|  |   LatticeComplex dip(UGrid); dip = lipp - lip; | ||||||
|  |   std::cout << " dip "<<dip<<std::endl; | ||||||
|  |  | ||||||
|   LatticeComplex dS(UGrid); dS = Zero(); |   LatticeComplex dS(UGrid); dS = Zero(); | ||||||
|   for(int mu=0;mu<Nd;mu++){ |   for(int mu=0;mu<Nd;mu++){ | ||||||
| @@ -139,12 +158,14 @@ int main (int argc, char ** argv) | |||||||
|     // Update PF action density |     // Update PF action density | ||||||
|     dS = dS+trace(mommu*forcemu)*dt; |     dS = dS+trace(mommu*forcemu)*dt; | ||||||
|   } |   } | ||||||
|  |   std::cout << "mommu"<<mommu<<std::endl; | ||||||
|  |   std::cout << "dS" << dS<<std::endl; | ||||||
|    |    | ||||||
|   ComplexD dSpred    = sum(dS); |   ComplexD dSpred    = sum(dS); | ||||||
|  |  | ||||||
|   std::cout << GridLogMessage << " S      "<<S<<std::endl; |   std::cout << GridLogMessage << " S      "<<S<<std::endl; | ||||||
|   std::cout << GridLogMessage << " Sprime "<<Sprime<<std::endl; |   std::cout << GridLogMessage << " Sprime "<<Sprime<<std::endl; | ||||||
|   std::cout << GridLogMessage << "dS      "<<Sprime-S<<std::endl; |   std::cout << GridLogMessage << "Delta S "<<Sprime-S<<std::endl; | ||||||
|   std::cout << GridLogMessage << "predict dS    "<< dSpred <<std::endl; |   std::cout << GridLogMessage << "predict dS    "<< dSpred <<std::endl; | ||||||
|  |  | ||||||
|   assert( fabs(real(Sprime-S-dSpred)) < 2.0 ) ; |   assert( fabs(real(Sprime-S-dSpred)) < 2.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" | ||||||
|   | |||||||
							
								
								
									
										260
									
								
								tests/forces/Test_mobius_gparity_eofa_mixed.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								tests/forces/Test_mobius_gparity_eofa_mixed.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,260 @@ | |||||||
|  | /************************************************************************************* | ||||||
|  |  | ||||||
|  | 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)); | ||||||
|  |  | ||||||
|  |       //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |       // Must snarf a single precision copy of the gauge field in Linop_d argument | ||||||
|  |       //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |       //typedef typename FermionOperatorF::GaugeField GaugeFieldF; | ||||||
|  |       //typedef typename FermionOperatorF::GaugeLinkField GaugeLinkFieldF; | ||||||
|  |       //typedef typename FermionOperatorD::GaugeField GaugeFieldD; | ||||||
|  |       //typedef typename FermionOperatorD::GaugeLinkField GaugeLinkFieldD; | ||||||
|  |  | ||||||
|  |       //GridBase * GridPtrF = SinglePrecGrid4; | ||||||
|  |       //GridBase * GridPtrD = FermOpD.Umu.Grid(); | ||||||
|  |       //GaugeFieldF     U_f  (GridPtrF); | ||||||
|  |       //GaugeLinkFieldF Umu_f(GridPtrF); | ||||||
|  |  | ||||||
|  |       //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |       // Moving this to a Clone method of fermion operator would allow to duplicate the  | ||||||
|  |       // physics parameters and decrease gauge field copies | ||||||
|  |       //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |       //typedef typename std::decay<decltype(PeekIndex<LorentzIndex>(FermOpD.Umu, 0))>::type DoubleS | ||||||
|  |  | ||||||
|  |       //GaugeLinkFieldD Umu_d(GridPtrD); | ||||||
|  |       //for(int mu=0;mu<Nd*2;mu++){  | ||||||
|  |       //Umu_d = PeekIndex<LorentzIndex>(FermOpD.Umu, mu); | ||||||
|  |       //precisionChange(Umu_f,Umu_d); | ||||||
|  |       //PokeIndex<LorentzIndex>(FermOpF.Umu, Umu_f, mu); | ||||||
|  |       //} | ||||||
|  |  | ||||||
|  |       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); | ||||||
|   | |||||||
							
								
								
									
										139
									
								
								tests/hmc/Test_rhmc_EOWilsonRatioPowQuarter.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								tests/hmc/Test_rhmc_EOWilsonRatioPowQuarter.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/Test_rhmc_EOWilsonRatio.cc | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | 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> | ||||||
|  |  | ||||||
|  | //This test is for the Wilson action with the determinant det( M^dag M)^1/4 | ||||||
|  | //testing the generic RHMC  | ||||||
|  |  | ||||||
|  | int main(int argc, char **argv) { | ||||||
|  |   using namespace Grid; | ||||||
|  |    ; | ||||||
|  |  | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |   int threads = GridThread::GetThreads(); | ||||||
|  |   // here make a routine to print all the relevant information on the run | ||||||
|  |   std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||||
|  |  | ||||||
|  |    // Typedefs to simplify notation | ||||||
|  |   typedef GenericHMCRunner<MinimumNorm2> HMCWrapper;  // Uses the default minimum norm | ||||||
|  |   typedef WilsonImplR FermionImplPolicy; | ||||||
|  |   typedef WilsonFermionR FermionAction; | ||||||
|  |   typedef typename FermionAction::FermionField FermionField; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   HMCWrapper TheHMC; | ||||||
|  |  | ||||||
|  |   // Grid from the command line | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); | ||||||
|  |  | ||||||
|  |   // Checkpointer definition | ||||||
|  |   CheckpointerParameters CPparams;   | ||||||
|  |   CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   CPparams.rng_prefix = "ckpoint_rng"; | ||||||
|  |   CPparams.saveInterval = 5; | ||||||
|  |   CPparams.format = "IEEE64BIG"; | ||||||
|  |    | ||||||
|  |   TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   // Construct observables | ||||||
|  |   typedef PlaquetteMod<HMCWrapper::ImplPolicy> PlaqObs; | ||||||
|  |   TheHMC.Resources.AddObservable<PlaqObs>(); | ||||||
|  |   ////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |   // Collect actions, here use more encapsulation | ||||||
|  |   // need wrappers of the fermionic classes  | ||||||
|  |   // that have a complex construction | ||||||
|  |   // standard | ||||||
|  |   RealD beta = 5.6 ; | ||||||
|  |   WilsonGaugeActionR Waction(beta); | ||||||
|  |      | ||||||
|  |   auto GridPtr = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto GridRBPtr = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeField U(GridPtr); | ||||||
|  |  | ||||||
|  |   Real mass = -0.77; | ||||||
|  |   Real pv   = 0.0; | ||||||
|  |  | ||||||
|  |   // Can we define an overloaded operator that does not need U and initialises | ||||||
|  |   // it with zeroes? | ||||||
|  |   FermionAction DenOp(U, *GridPtr, *GridRBPtr, mass); | ||||||
|  |   FermionAction NumOp(U, *GridPtr, *GridRBPtr, pv); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // 1/2+1/2 flavour | ||||||
|  |   // RationalActionParams(int _inv_pow = 2, | ||||||
|  |   // 		       RealD _lo      = 0.0,  | ||||||
|  |   // 		       RealD _hi      = 1.0,  | ||||||
|  |   // 		       int _maxit     = 1000, | ||||||
|  |   // 		       RealD tol      = 1.0e-8,  | ||||||
|  |   // 		       int _degree    = 10, | ||||||
|  |   // 		       int _precision = 64, | ||||||
|  |   // 		       int _BoundsCheckFreq=20) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   int inv_pow = 4; | ||||||
|  |   RationalActionParams Params(inv_pow,1.0e-2,64.0,1000,1.0e-6,14,64,1); | ||||||
|  |  | ||||||
|  |   GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicy> RHMC(NumOp,DenOp,Params); | ||||||
|  |  | ||||||
|  |     // Collect actions | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level1(1); | ||||||
|  |   Level1.push_back(&RHMC); | ||||||
|  |  | ||||||
|  |   ActionLevel<HMCWrapper::Field> Level2(4); | ||||||
|  |   Level2.push_back(&Waction); | ||||||
|  |  | ||||||
|  |   TheHMC.TheAction.push_back(Level1); | ||||||
|  |   TheHMC.TheAction.push_back(Level2); | ||||||
|  |   ///////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  |   // HMC parameters are serialisable  | ||||||
|  |   TheHMC.Parameters.MD.MDsteps = 20; | ||||||
|  |   TheHMC.Parameters.MD.trajL   = 1.0; | ||||||
|  |  | ||||||
|  |   TheHMC.ReadCommandLine(argc, argv); // these can be parameters from file | ||||||
|  |   TheHMC.Run(); | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  |  | ||||||
|  | } // main | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										119
									
								
								tests/hmc/Test_rhmc_EOWilsonRatio_doubleVsMixedPrec.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								tests/hmc/Test_rhmc_EOWilsonRatio_doubleVsMixedPrec.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/Test_rhmc_EOWilsonRatio_doubleVsMixedPrec.cc | ||||||
|  |  | ||||||
|  |     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 */ | ||||||
|  | #include <Grid/Grid.h> | ||||||
|  |  | ||||||
|  | //This test ensures the mixed precision RHMC gives the same result as the regular double precision | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  |   typedef GenericHMCRunner<MinimumNorm2> HMCWrapper;  // Uses the default minimum norm | ||||||
|  |  | ||||||
|  |   typedef WilsonImplD FermionImplPolicyD; | ||||||
|  |   typedef WilsonFermionD FermionActionD; | ||||||
|  |   typedef typename FermionActionD::FermionField FermionFieldD; | ||||||
|  |  | ||||||
|  |   typedef WilsonImplF FermionImplPolicyF; | ||||||
|  |   typedef WilsonFermionF FermionActionF; | ||||||
|  |   typedef typename FermionActionF::FermionField FermionFieldF; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   HMCWrapper TheHMC; | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); | ||||||
|  |  | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   auto GridPtrD = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto GridRBPtrD = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |  | ||||||
|  |   GridCartesian* GridPtrF = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* GridRBPtrF = SpaceTimeGrid::makeFourDimRedBlackGrid(GridPtrF); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeFieldD Ud(GridPtrD); | ||||||
|  |   LatticeGaugeFieldF Uf(GridPtrF); | ||||||
|  |  | ||||||
|  |   Real mass = -0.77; | ||||||
|  |   Real pv   = 0.0; | ||||||
|  |  | ||||||
|  |   FermionActionD DenOpD(Ud, *GridPtrD, *GridRBPtrD, mass); | ||||||
|  |   FermionActionD NumOpD(Ud, *GridPtrD, *GridRBPtrD, pv); | ||||||
|  |  | ||||||
|  |   FermionActionF DenOpF(Uf, *GridPtrF, *GridRBPtrF, mass); | ||||||
|  |   FermionActionF NumOpF(Uf, *GridPtrF, *GridRBPtrF, pv); | ||||||
|  |  | ||||||
|  |   TheHMC.Resources.AddRNGs(); | ||||||
|  |   PeriodicGimplR::HotConfiguration(TheHMC.Resources.GetParallelRNG(), Ud); | ||||||
|  |  | ||||||
|  |   std::string seed_string = "the_seed"; | ||||||
|  |  | ||||||
|  |   //Setup the pseudofermion actions | ||||||
|  |   RationalActionParams GenParams; | ||||||
|  |   GenParams.inv_pow = 2; | ||||||
|  |   GenParams.lo = 1e-2; | ||||||
|  |   GenParams.hi = 64.0; | ||||||
|  |   GenParams.MaxIter = 1000; | ||||||
|  |   GenParams.action_tolerance = GenParams.md_tolerance = 1e-6; | ||||||
|  |   GenParams.action_degree = GenParams.md_degree = 6; | ||||||
|  |   GenParams.precision = 64; | ||||||
|  |   GenParams.BoundsCheckFreq = 20; | ||||||
|  |  | ||||||
|  |   GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicyD> GenD(NumOpD,DenOpD,GenParams); | ||||||
|  |   GeneralEvenOddRatioRationalMixedPrecPseudoFermionAction<FermionImplPolicyD, FermionImplPolicyF> GenFD(NumOpD, DenOpD,  | ||||||
|  | 													NumOpF, DenOpF,  | ||||||
|  | 													GenParams, 50); | ||||||
|  |   TheHMC.Resources.GetParallelRNG().SeedUniqueString(seed_string); | ||||||
|  |   GenD.refresh(Ud, TheHMC.Resources.GetSerialRNG(), TheHMC.Resources.GetParallelRNG());     | ||||||
|  |   RealD Sd = GenD.S(Ud); | ||||||
|  |   LatticeGaugeField derivD(Ud); | ||||||
|  |   GenD.deriv(Ud,derivD);    | ||||||
|  |  | ||||||
|  |   TheHMC.Resources.GetParallelRNG().SeedUniqueString(seed_string); | ||||||
|  |   GenFD.refresh(Ud, TheHMC.Resources.GetSerialRNG(), TheHMC.Resources.GetParallelRNG());     | ||||||
|  |   RealD Sfd = GenFD.S(Ud); | ||||||
|  |   LatticeGaugeField derivFD(Ud); | ||||||
|  |   GenFD.deriv(Ud,derivFD);    | ||||||
|  |  | ||||||
|  |   //Compare | ||||||
|  |   std::cout << "Action : " << Sd << " " << Sfd << " reldiff " << (Sd - Sfd)/Sd << std::endl; | ||||||
|  |    | ||||||
|  |   LatticeGaugeField diff(Ud); | ||||||
|  |   axpy(diff, -1.0, derivD, derivFD); | ||||||
|  |   std::cout << "Norm of difference in deriv " << sqrt(norm2(diff)) << std::endl; | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										122
									
								
								tests/hmc/Test_rhmc_EOWilsonRatio_genericVsOneFlavor.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								tests/hmc/Test_rhmc_EOWilsonRatio_genericVsOneFlavor.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/Test_rhmc_EOWilsonRatio_genericVsOneFlavor.cc | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: paboyle <paboyle@ph.ed.ac.uk> | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  |  | ||||||
|  |     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> | ||||||
|  |  | ||||||
|  | //This test ensures that the OneFlavourEvenOddRatioRationalPseudoFermionAction and GeneralEvenOddRatioRationalPseudoFermionAction action (with parameters set appropriately0 | ||||||
|  | //give the same results | ||||||
|  |  | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  |   typedef GenericHMCRunner<MinimumNorm2> HMCWrapper;  // Uses the default minimum norm | ||||||
|  |   typedef WilsonImplR FermionImplPolicy; | ||||||
|  |   typedef WilsonFermionR FermionAction; | ||||||
|  |   typedef typename FermionAction::FermionField FermionField; | ||||||
|  |  | ||||||
|  |   //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||||||
|  |   HMCWrapper TheHMC; | ||||||
|  |   TheHMC.Resources.AddFourDimGrid("gauge"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // // Checkpointer definition | ||||||
|  |   // CheckpointerParameters CPparams;   | ||||||
|  |   // CPparams.config_prefix = "ckpoint_lat"; | ||||||
|  |   // CPparams.rng_prefix = "ckpoint_rng"; | ||||||
|  |   // CPparams.saveInterval = 5; | ||||||
|  |   // CPparams.format = "IEEE64BIG"; | ||||||
|  |    | ||||||
|  |   // TheHMC.Resources.LoadNerscCheckpointer(CPparams); | ||||||
|  |  | ||||||
|  |   RNGModuleParameters RNGpar; | ||||||
|  |   RNGpar.serial_seeds = "1 2 3 4 5"; | ||||||
|  |   RNGpar.parallel_seeds = "6 7 8 9 10"; | ||||||
|  |   TheHMC.Resources.SetRNGSeeds(RNGpar); | ||||||
|  |  | ||||||
|  |   auto GridPtr = TheHMC.Resources.GetCartesian(); | ||||||
|  |   auto GridRBPtr = TheHMC.Resources.GetRBCartesian(); | ||||||
|  |  | ||||||
|  |   // temporarily need a gauge field | ||||||
|  |   LatticeGaugeField U(GridPtr); | ||||||
|  |  | ||||||
|  |   Real mass = -0.77; | ||||||
|  |   Real pv   = 0.0; | ||||||
|  |  | ||||||
|  |   FermionAction DenOp(U, *GridPtr, *GridRBPtr, mass); | ||||||
|  |   FermionAction NumOp(U, *GridPtr, *GridRBPtr, pv); | ||||||
|  |  | ||||||
|  |   TheHMC.Resources.AddRNGs(); | ||||||
|  |   PeriodicGimplR::HotConfiguration(TheHMC.Resources.GetParallelRNG(), U); | ||||||
|  |  | ||||||
|  |   std::string seed_string = "the_seed"; | ||||||
|  |  | ||||||
|  |   //1f action | ||||||
|  |   OneFlavourRationalParams OneFParams(1.0e-2,64.0,1000,1.0e-6,6);  | ||||||
|  |  | ||||||
|  |   OneFlavourEvenOddRatioRationalPseudoFermionAction<FermionImplPolicy> OneF(NumOp,DenOp,OneFParams); | ||||||
|  |   TheHMC.Resources.GetParallelRNG().SeedUniqueString(seed_string); | ||||||
|  |   OneF.refresh(U, TheHMC.Resources.GetParallelRNG());     | ||||||
|  |   RealD OneFS = OneF.S(U); | ||||||
|  |   LatticeGaugeField OneFderiv(U); | ||||||
|  |   OneF.deriv(U,OneFderiv);     | ||||||
|  |    | ||||||
|  |   //general action | ||||||
|  |   RationalActionParams GenParams; | ||||||
|  |   GenParams.inv_pow = 2; | ||||||
|  |   GenParams.lo = OneFParams.lo; | ||||||
|  |   GenParams.hi = OneFParams.hi; | ||||||
|  |   GenParams.MaxIter = OneFParams.MaxIter; | ||||||
|  |   GenParams.action_tolerance = GenParams.md_tolerance = OneFParams.tolerance; | ||||||
|  |   GenParams.action_degree = GenParams.md_degree = OneFParams.degree; | ||||||
|  |   GenParams.precision = OneFParams.precision; | ||||||
|  |   GenParams.BoundsCheckFreq = OneFParams.BoundsCheckFreq; | ||||||
|  |  | ||||||
|  |   GeneralEvenOddRatioRationalPseudoFermionAction<FermionImplPolicy> Gen(NumOp,DenOp,GenParams); | ||||||
|  |   TheHMC.Resources.GetParallelRNG().SeedUniqueString(seed_string); | ||||||
|  |   Gen.refresh(U, TheHMC.Resources.GetParallelRNG());     | ||||||
|  |   RealD GenS = Gen.S(U); | ||||||
|  |   LatticeGaugeField Genderiv(U); | ||||||
|  |   Gen.deriv(U,Genderiv);    | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   //Compare | ||||||
|  |   std::cout << "Action : " << OneFS << " " << GenS << " reldiff " << (OneFS - GenS)/OneFS << std::endl; | ||||||
|  |    | ||||||
|  |   LatticeGaugeField diff(U); | ||||||
|  |   axpy(diff, -1.0, Genderiv, OneFderiv); | ||||||
|  |   std::cout << "Norm of difference in deriv " << sqrt(norm2(diff)) << std::endl; | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										425
									
								
								tests/lanczos/Test_compressed_lanczos_gparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								tests/lanczos/Test_compressed_lanczos_gparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,425 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/Test_compressed_lanczos_gparity.cc | ||||||
|  |  | ||||||
|  |     Copyright (C) 2017 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  | Author: Leans heavily on Christoph Lehner's code | ||||||
|  | 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 */ | ||||||
|  | /* | ||||||
|  |  *  Reimplement the badly named "multigrid" lanczos as compressed Lanczos using the features  | ||||||
|  |  *  in Grid that were intended to be used to support blocked Aggregates, from | ||||||
|  |  */ | ||||||
|  | #include <Grid/Grid.h> | ||||||
|  | #include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h> | ||||||
|  | #include <Grid/algorithms/iterative/LocalCoherenceLanczos.h> | ||||||
|  |  | ||||||
|  | using namespace std; | ||||||
|  | using namespace Grid; | ||||||
|  |  | ||||||
|  | // template<class VectorInt> | ||||||
|  | // void GridCmdOptionIntVector(const std::string &str, VectorInt & vec) | ||||||
|  | // { | ||||||
|  | //   vec.resize(0); | ||||||
|  | //   std::stringstream ss(str); | ||||||
|  | //   int i; | ||||||
|  | //   while (ss >> i){ | ||||||
|  | //     vec.push_back(i); | ||||||
|  | //     if(std::ispunct(ss.peek())) | ||||||
|  | //       ss.ignore(); | ||||||
|  | //   } | ||||||
|  | //   return; | ||||||
|  | // } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //For the CPS configurations we have to manually seed the RNG and deal with an incorrect factor of 2 in the plaquette metadata | ||||||
|  | void readConfiguration(LatticeGaugeFieldD &U, | ||||||
|  | 		       const std::string &config, | ||||||
|  | 		       bool is_cps_cfg = false){ | ||||||
|  |  | ||||||
|  |   if(is_cps_cfg) NerscIO::exitOnReadPlaquetteMismatch() = false; | ||||||
|  |  | ||||||
|  |   typedef GaugeStatistics<ConjugateGimplD> GaugeStats; | ||||||
|  |       | ||||||
|  |   FieldMetaData header; | ||||||
|  |   NerscIO::readConfiguration<GaugeStats>(U, header, config); | ||||||
|  |  | ||||||
|  |   if(is_cps_cfg) NerscIO::exitOnReadPlaquetteMismatch() = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Lanczos parameters in CPS conventions | ||||||
|  | struct CPSLanczosParams : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(CPSLanczosParams, | ||||||
|  | 				  RealD, alpha, | ||||||
|  | 				  RealD, beta, | ||||||
|  | 				  int, ch_ord, | ||||||
|  | 				  int, N_use, | ||||||
|  | 				  int, N_get, | ||||||
|  | 				  int, N_true_get, | ||||||
|  | 				  RealD, stop_rsd, | ||||||
|  | 				  int, maxits); | ||||||
|  |  | ||||||
|  |   //Translations | ||||||
|  |   ChebyParams getChebyParams() const{ | ||||||
|  |     ChebyParams out; | ||||||
|  |     out.alpha = beta*beta; //aka lo | ||||||
|  |     out.beta = alpha*alpha; //aka hi | ||||||
|  |     out.Npoly = ch_ord+1; | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |   int Nstop() const{ return N_true_get; } | ||||||
|  |   int Nm() const{ return N_use; } | ||||||
|  |   int Nk() const{ return N_get; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //Maybe this class should be in the main library? | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class LocalCoherenceLanczosScidac : public LocalCoherenceLanczos<Fobj,CComplex,nbasis> | ||||||
|  | {  | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<CComplex>   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<Fobj>          FineField; | ||||||
|  |  | ||||||
|  |   LocalCoherenceLanczosScidac(GridBase *FineGrid,GridBase *CoarseGrid, | ||||||
|  | 			      LinearOperatorBase<FineField> &FineOp, | ||||||
|  | 			      int checkerboard)  | ||||||
|  |     // Base constructor | ||||||
|  |     : LocalCoherenceLanczos<Fobj,CComplex,nbasis>(FineGrid,CoarseGrid,FineOp,checkerboard)  | ||||||
|  |   {}; | ||||||
|  |  | ||||||
|  |   void checkpointFine(std::string evecs_file,std::string evals_file) | ||||||
|  |   { | ||||||
|  |     assert(this->subspace.size()==nbasis); | ||||||
|  |     emptyUserRecord record; | ||||||
|  |     Grid::ScidacWriter WR(this->_FineGrid->IsBoss()); | ||||||
|  |     WR.open(evecs_file); | ||||||
|  |     for(int k=0;k<nbasis;k++) { | ||||||
|  |       WR.writeScidacFieldRecord(this->subspace[k],record); | ||||||
|  |     } | ||||||
|  |     WR.close(); | ||||||
|  |      | ||||||
|  |     XmlWriter WRx(evals_file); | ||||||
|  |     write(WRx,"evals",this->evals_fine); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void checkpointFineRestore(std::string evecs_file,std::string evals_file) | ||||||
|  |   { | ||||||
|  |     this->evals_fine.resize(nbasis); | ||||||
|  |     this->subspace.resize(nbasis,this->_FineGrid); | ||||||
|  |      | ||||||
|  |     std::cout << GridLogIRL<< "checkpointFineRestore:  Reading evals from "<<evals_file<<std::endl; | ||||||
|  |     XmlReader RDx(evals_file); | ||||||
|  |     read(RDx,"evals",this->evals_fine); | ||||||
|  |      | ||||||
|  |     assert(this->evals_fine.size()==nbasis); | ||||||
|  |      | ||||||
|  |     std::cout << GridLogIRL<< "checkpointFineRestore:  Reading evecs from "<<evecs_file<<std::endl; | ||||||
|  |     emptyUserRecord record; | ||||||
|  |     Grid::ScidacReader RD ; | ||||||
|  |     RD.open(evecs_file); | ||||||
|  |     for(int k=0;k<nbasis;k++) { | ||||||
|  |       this->subspace[k].Checkerboard()=this->_checkerboard; | ||||||
|  |       RD.readScidacFieldRecord(this->subspace[k],record); | ||||||
|  |        | ||||||
|  |     } | ||||||
|  |     RD.close(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void checkpointCoarse(std::string evecs_file,std::string evals_file) | ||||||
|  |   { | ||||||
|  |     int n = this->evec_coarse.size(); | ||||||
|  |     emptyUserRecord record; | ||||||
|  |     Grid::ScidacWriter WR(this->_CoarseGrid->IsBoss()); | ||||||
|  |     WR.open(evecs_file); | ||||||
|  |     for(int k=0;k<n;k++) { | ||||||
|  |       WR.writeScidacFieldRecord(this->evec_coarse[k],record); | ||||||
|  |     } | ||||||
|  |     WR.close(); | ||||||
|  |      | ||||||
|  |     XmlWriter WRx(evals_file); | ||||||
|  |     write(WRx,"evals",this->evals_coarse); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void checkpointCoarseRestore(std::string evecs_file,std::string evals_file,int nvec) | ||||||
|  |   { | ||||||
|  |     std::cout << "resizing coarse vecs to " << nvec<< std::endl; | ||||||
|  |     this->evals_coarse.resize(nvec); | ||||||
|  |     this->evec_coarse.resize(nvec,this->_CoarseGrid); | ||||||
|  |     std::cout << GridLogIRL<< "checkpointCoarseRestore:  Reading evals from "<<evals_file<<std::endl; | ||||||
|  |     XmlReader RDx(evals_file); | ||||||
|  |     read(RDx,"evals",this->evals_coarse); | ||||||
|  |  | ||||||
|  |     assert(this->evals_coarse.size()==nvec); | ||||||
|  |     emptyUserRecord record; | ||||||
|  |     std::cout << GridLogIRL<< "checkpointCoarseRestore:  Reading evecs from "<<evecs_file<<std::endl; | ||||||
|  |     Grid::ScidacReader RD ; | ||||||
|  |     RD.open(evecs_file); | ||||||
|  |     for(int k=0;k<nvec;k++) { | ||||||
|  |       RD.readScidacFieldRecord(this->evec_coarse[k],record); | ||||||
|  |     } | ||||||
|  |     RD.close(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Note:  because we rely upon physical properties we must use a "real" gauge configuration | ||||||
|  | int main (int argc, char ** argv) { | ||||||
|  |   Grid_init(&argc,&argv); | ||||||
|  |   GridLogIRL.TimingMode(1); | ||||||
|  |  | ||||||
|  |   std::vector<int> blockSize = {2,2,2,2,2}; | ||||||
|  |   std::vector<int> GparityDirs = {1,1,1}; //1 for each GP direction | ||||||
|  |  | ||||||
|  |   int Ls = 12; | ||||||
|  |   RealD mass = 0.01; | ||||||
|  |   RealD M5 = 1.8; | ||||||
|  |   bool is_cps_cfg = false; | ||||||
|  |  | ||||||
|  |   CPSLanczosParams fine, coarse; | ||||||
|  |  | ||||||
|  |   fine.alpha = 2; | ||||||
|  |   fine.beta = 0.1; | ||||||
|  |   fine.ch_ord = 100; | ||||||
|  |   fine.N_use = 70; | ||||||
|  |   fine.N_get = 60; | ||||||
|  |   fine.N_true_get = 60; | ||||||
|  |   fine.stop_rsd = 1e-8; | ||||||
|  |   fine.maxits = 10000; | ||||||
|  |  | ||||||
|  |   coarse.alpha = 2; | ||||||
|  |   coarse.beta = 0.1; | ||||||
|  |   coarse.ch_ord = 100; | ||||||
|  |   coarse.N_use = 200; | ||||||
|  |   coarse.N_get = 190; | ||||||
|  |   coarse.N_true_get = 190; | ||||||
|  |   coarse.stop_rsd = 1e-8; | ||||||
|  |   coarse.maxits = 10000; | ||||||
|  |  | ||||||
|  |   double coarse_relax_tol = 1e5; | ||||||
|  |   int smoother_ord = 20; | ||||||
|  |    | ||||||
|  |   if(argc < 3){ | ||||||
|  |     std::cout << GridLogMessage << "Usage: <exe> <config> <gparity dirs> <options>" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "<gparity dirs> should have the format a.b.c where a,b,c are 0,1 depending on whether there are G-parity BCs in that direction" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "Options:" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--Ls <value> : Set Ls (default 12)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--mass <value> : Set the mass (default 0.01)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--block <value> : Set the block size. Format should be a.b.c.d.e where a-e are the block extents  (default 2.2.2.2.2)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--is_cps_cfg : Indicate that the configuration was generated with CPS where until recently the stored plaquette was wrong by a factor of 2" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--write_irl_templ: Write a template for the parameters file of the Lanczos to \"irl_templ.xml\"" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--read_irl_fine <filename>: Real the parameters file for the fine Lanczos" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--read_irl_coarse <filename>: Real the parameters file for the coarse Lanczos" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--write_fine <filename stub>: Write fine evecs/evals to filename starting with the stub" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--read_fine <filename stub>: Read fine evecs/evals from filename starting with the stub" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--write_coarse <filename stub>: Write coarse evecs/evals to filename starting with the stub" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--read_coarse <filename stub>: Read coarse evecs/evals from filename starting with the stub" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--smoother_ord :  Set the Chebyshev order of the smoother (default 20)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--coarse_relax_tol : Set the relaxation parameter for evaluating the residual of the reconstructed eigenvectors outside of the basis (default 1e5)" << std::endl; | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 1; | ||||||
|  |   } | ||||||
|  |   std::string config = argv[1]; | ||||||
|  |   GridCmdOptionIntVector(argv[2], GparityDirs); | ||||||
|  |   assert(GparityDirs.size() == 3); | ||||||
|  |  | ||||||
|  |   bool write_fine = false; | ||||||
|  |   std::string write_fine_file; | ||||||
|  |  | ||||||
|  |   bool read_fine = false; | ||||||
|  |   std::string read_fine_file; | ||||||
|  |  | ||||||
|  |   bool write_coarse = false; | ||||||
|  |   std::string write_coarse_file; | ||||||
|  |  | ||||||
|  |   bool read_coarse = false; | ||||||
|  |   std::string read_coarse_file; | ||||||
|  |   | ||||||
|  |   for(int i=3;i<argc;i++){ | ||||||
|  |     std::string sarg = argv[i]; | ||||||
|  |     if(sarg == "--Ls"){ | ||||||
|  |       Ls = std::stoi(argv[i+1]); | ||||||
|  |       std::cout << GridLogMessage << "Set Ls to " << Ls << std::endl; | ||||||
|  |     }else if(sarg == "--mass"){ | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> mass; | ||||||
|  |       std::cout << GridLogMessage << "Set quark mass to " << mass << std::endl; | ||||||
|  |     }else if(sarg == "--block"){ | ||||||
|  |       GridCmdOptionIntVector(argv[i+1], blockSize); | ||||||
|  |       assert(blockSize.size() == 5); | ||||||
|  |       std::cout << GridLogMessage << "Set block size to "; | ||||||
|  |       for(int q=0;q<5;q++) std::cout << blockSize[q] << " "; | ||||||
|  |       std::cout << std::endl;       | ||||||
|  |     }else if(sarg == "--is_cps_cfg"){ | ||||||
|  |       is_cps_cfg = true; | ||||||
|  |     }else if(sarg == "--write_irl_templ"){ | ||||||
|  |       XmlWriter writer("irl_templ.xml"); | ||||||
|  |       write(writer,"Params",fine); | ||||||
|  |       Grid_finalize(); | ||||||
|  |       return 0; | ||||||
|  |     }else if(sarg == "--read_irl_fine"){ | ||||||
|  |       std::cout << GridLogMessage << "Reading fine IRL params from " << argv[i+1] << std::endl; | ||||||
|  |       XmlReader reader(argv[i+1]); | ||||||
|  |       read(reader, "Params", fine); | ||||||
|  |     }else if(sarg == "--read_irl_coarse"){ | ||||||
|  |       std::cout << GridLogMessage << "Reading coarse IRL params from " << argv[i+1] << std::endl; | ||||||
|  |       XmlReader reader(argv[i+1]); | ||||||
|  |       read(reader, "Params", coarse); | ||||||
|  |     }else if(sarg == "--write_fine"){ | ||||||
|  |       write_fine = true; | ||||||
|  |       write_fine_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_fine"){ | ||||||
|  |       read_fine = true; | ||||||
|  |       read_fine_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--write_coarse"){ | ||||||
|  |       write_coarse = true; | ||||||
|  |       write_coarse_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_coarse"){ | ||||||
|  |       read_coarse = true; | ||||||
|  |       read_coarse_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--smoother_ord"){ | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> smoother_ord; | ||||||
|  |       std::cout << GridLogMessage << "Set smoother order to " << smoother_ord << std::endl; | ||||||
|  |     }else if(sarg == "--coarse_relax_tol"){ | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> coarse_relax_tol; | ||||||
|  |       std::cout << GridLogMessage << "Set coarse IRL relaxation parameter to " << coarse_relax_tol << std::endl; | ||||||
|  |     }       | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   //Fine grids | ||||||
|  |   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); | ||||||
|  |  | ||||||
|  |   //Setup G-parity BCs | ||||||
|  |   assert(Nd == 4); | ||||||
|  |   std::vector<int> dirs4(4); | ||||||
|  |   for(int i=0;i<3;i++) dirs4[i] = GparityDirs[i]; | ||||||
|  |   dirs4[3] = 0; //periodic gauge BC in time | ||||||
|  |    | ||||||
|  |   std::cout << GridLogMessage << "Gauge BCs: " << dirs4 << std::endl; | ||||||
|  |   ConjugateGimplD::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   GparityWilsonImplD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |   std::cout << GridLogMessage << "Fermion BCs: " << Params.twists << std::endl; | ||||||
|  |    | ||||||
|  |   //Read the gauge field | ||||||
|  |   LatticeGaugeField Umu(UGrid);   | ||||||
|  |   readConfiguration(Umu, config, is_cps_cfg); | ||||||
|  |  | ||||||
|  |   //Setup the coarse grids   | ||||||
|  |   auto fineLatt     = GridDefaultLatt(); | ||||||
|  |   Coordinate coarseLatt(4); | ||||||
|  |   for (int d=0;d<4;d++){ | ||||||
|  |     coarseLatt[d] = fineLatt[d]/blockSize[d];    assert(coarseLatt[d]*blockSize[d]==fineLatt[d]); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage<< " 5d coarse lattice is "; | ||||||
|  |   for (int i=0;i<4;i++){ | ||||||
|  |     std::cout << coarseLatt[i]<<"x"; | ||||||
|  |   }  | ||||||
|  |   int cLs = Ls/blockSize[4]; assert(cLs*blockSize[4]==Ls); | ||||||
|  |   std::cout << cLs<<std::endl; | ||||||
|  |    | ||||||
|  |   GridCartesian         * CoarseGrid4    = SpaceTimeGrid::makeFourDimGrid(coarseLatt, GridDefaultSimd(Nd,vComplex::Nsimd()),GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian * CoarseGrid4rb  = SpaceTimeGrid::makeFourDimRedBlackGrid(CoarseGrid4); | ||||||
|  |   GridCartesian         * CoarseGrid5    = SpaceTimeGrid::makeFiveDimGrid(cLs,CoarseGrid4); | ||||||
|  |  | ||||||
|  |   //Dirac operator | ||||||
|  |   GparityDomainWallFermionD action(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mass, M5, Params); | ||||||
|  |   typedef GparityDomainWallFermionD::FermionField FermionField; | ||||||
|  |    | ||||||
|  |   SchurDiagTwoOperator<GparityDomainWallFermionD,FermionField> SchurOp(action); | ||||||
|  |  | ||||||
|  |   typedef GparityWilsonImplD::SiteSpinor SiteSpinor; | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << "Keep " << fine.N_true_get   << " fine   vectors" << std::endl; | ||||||
|  |   std::cout << GridLogMessage << "Keep " << coarse.N_true_get << " coarse vectors" << std::endl; | ||||||
|  |   assert(coarse.N_true_get >= fine.N_true_get); | ||||||
|  |  | ||||||
|  |   const int nbasis= 60; | ||||||
|  |   assert(nbasis<=fine.N_true_get); | ||||||
|  |   LocalCoherenceLanczosScidac<SiteSpinor,vTComplex,nbasis> _LocalCoherenceLanczos(FrbGrid,CoarseGrid5,SchurOp,Odd); | ||||||
|  |   std::cout << GridLogMessage << "Constructed LocalCoherenceLanczos" << std::endl; | ||||||
|  |  | ||||||
|  |   //Compute and/or read fine evecs | ||||||
|  |   if(read_fine){ | ||||||
|  |     _LocalCoherenceLanczos.checkpointFineRestore(read_fine_file + "_evecs.scidac", read_fine_file + "_evals.xml"); | ||||||
|  |   }else{ | ||||||
|  |     std::cout << GridLogMessage << "Performing fine grid IRL" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "Using Chebyshev alpha=" << fine.alpha << " beta=" << fine.beta << " ord=" << fine.ch_ord << std::endl; | ||||||
|  |     _LocalCoherenceLanczos.calcFine(fine.getChebyParams(), | ||||||
|  | 				    fine.Nstop(),fine.Nk(),fine.Nm(), | ||||||
|  | 				    fine.stop_rsd,fine.maxits,0,0); | ||||||
|  |     if(write_fine){ | ||||||
|  |       std::cout << GridLogIRL<<"Checkpointing Fine evecs"<<std::endl; | ||||||
|  |       _LocalCoherenceLanczos.checkpointFine(write_fine_file + "_evecs.scidac", write_fine_file + "_evals.xml"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   //Block orthonormalise (this should be part of calcFine?) | ||||||
|  |   std::cout << GridLogIRL<<"Orthogonalising"<<std::endl; | ||||||
|  |   _LocalCoherenceLanczos.Orthogonalise(); | ||||||
|  |   std::cout << GridLogIRL<<"Orthogonaled"<<std::endl; | ||||||
|  |  | ||||||
|  |   ChebyParams smoother = fine.getChebyParams(); | ||||||
|  |   smoother.Npoly = smoother_ord+1; | ||||||
|  |  | ||||||
|  |   if(read_coarse){ | ||||||
|  |     _LocalCoherenceLanczos.checkpointCoarseRestore(read_coarse_file + "_evecs.scidac", read_coarse_file + "_evals.xml",coarse.Nstop()); | ||||||
|  |  | ||||||
|  |   }else{ | ||||||
|  |     std::cout << GridLogMessage << "Performing coarse grid IRL" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "Using Chebyshev alpha=" << coarse.alpha << " beta=" << coarse.beta << " ord=" << coarse.ch_ord << std::endl;	 | ||||||
|  |     _LocalCoherenceLanczos.calcCoarse(coarse.getChebyParams(), smoother, coarse_relax_tol, | ||||||
|  | 				      coarse.Nstop(), coarse.Nk() ,coarse.Nm(), | ||||||
|  | 				      coarse.stop_rsd, coarse.maxits,  | ||||||
|  | 				      0,0); | ||||||
|  |  | ||||||
|  |     if(write_coarse){ | ||||||
|  |       std::cout << GridLogIRL<<"Checkpointing Coarse evecs"<<std::endl; | ||||||
|  |       _LocalCoherenceLanczos.checkpointCoarse(write_coarse_file + "_evecs.scidac", write_coarse_file + "_evals.xml"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Test the eigenvectors | ||||||
|  |   FermionField evec(FrbGrid); | ||||||
|  |   FermionField tmp(FrbGrid); | ||||||
|  |   RealD eval; | ||||||
|  |    | ||||||
|  |   for(int i=0;i<coarse.N_true_get;i++){     | ||||||
|  |     _LocalCoherenceLanczos.getFineEvecEval(evec, eval, i); | ||||||
|  |     SchurOp.HermOp(evec, tmp); | ||||||
|  |     tmp = tmp - eval*evec; | ||||||
|  |     std::cout << GridLogMessage << "Eval " << eval << " resid " << sqrt(norm2(tmp)) << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -31,14 +31,38 @@ using namespace std; | |||||||
| using namespace Grid; | using namespace Grid; | ||||||
|  ; |  ; | ||||||
|  |  | ||||||
| typedef typename GparityDomainWallFermionR::FermionField FermionField; | template<typename Action> | ||||||
|  | struct Setup{}; | ||||||
|  |  | ||||||
| RealD AllZero(RealD x){ return 0.;} | template<> | ||||||
|  | struct Setup<GparityMobiusFermionR>{ | ||||||
|  |   static GparityMobiusFermionR* getAction(LatticeGaugeField &Umu, | ||||||
|  | 					  GridCartesian* FGrid, GridRedBlackCartesian* FrbGrid, GridCartesian* UGrid, GridRedBlackCartesian* UrbGrid){ | ||||||
|  |     RealD mass=0.01; | ||||||
|  |     RealD M5=1.8; | ||||||
|  |     RealD mob_b=1.5; | ||||||
|  |     GparityMobiusFermionD ::ImplParams params; | ||||||
|  |     std::vector<int> twists({1,1,1,0}); | ||||||
|  |     params.twists = twists; | ||||||
|  |     return new GparityMobiusFermionR(Umu,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,mob_b,mob_b-1.,params); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
| int main (int argc, char ** argv) | template<> | ||||||
| { | struct Setup<DomainWallFermionR>{ | ||||||
|   Grid_init(&argc,&argv); |   static DomainWallFermionR* getAction(LatticeGaugeField &Umu, | ||||||
|  | 					  GridCartesian* FGrid, GridRedBlackCartesian* FrbGrid, GridCartesian* UGrid, GridRedBlackCartesian* UrbGrid){ | ||||||
|  |     RealD mass=0.01; | ||||||
|  |     RealD M5=1.8; | ||||||
|  |     return new DomainWallFermionR(Umu,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename Action> | ||||||
|  | void run(){ | ||||||
|  |   typedef typename Action::FermionField FermionField; | ||||||
|   const int Ls=8; |   const int Ls=8; | ||||||
|  |  | ||||||
|   GridCartesian         * UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()),GridDefaultMpi()); |   GridCartesian         * UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()),GridDefaultMpi()); | ||||||
| @@ -56,24 +80,10 @@ int main (int argc, char ** argv) | |||||||
|   LatticeGaugeField Umu(UGrid);  |   LatticeGaugeField Umu(UGrid);  | ||||||
|   SU<Nc>::HotConfiguration(RNG4, Umu); |   SU<Nc>::HotConfiguration(RNG4, Umu); | ||||||
|  |  | ||||||
|   std::vector<LatticeColourMatrix> U(4,UGrid); |   Action *action = Setup<Action>::getAction(Umu,FGrid,FrbGrid,UGrid,UrbGrid); | ||||||
|   for(int mu=0;mu<Nd;mu++){ |  | ||||||
|     U[mu] = PeekIndex<LorentzIndex>(Umu,mu); |  | ||||||
|   } |  | ||||||
|   |   | ||||||
|   RealD mass=0.01; |   //MdagMLinearOperator<Action,FermionField> HermOp(Ddwf); | ||||||
|   RealD M5=1.8; |   SchurDiagTwoOperator<Action,FermionField> HermOp(*action); | ||||||
|   RealD mob_b=1.5; |  | ||||||
| //  DomainWallFermionR Ddwf(Umu,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5); |  | ||||||
|   GparityMobiusFermionD ::ImplParams params; |  | ||||||
|   std::vector<int> twists({1,1,1,0}); |  | ||||||
|   params.twists = twists; |  | ||||||
|   GparityMobiusFermionR  Ddwf(Umu,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5,mob_b,mob_b-1.,params); |  | ||||||
|  |  | ||||||
| //  MdagMLinearOperator<DomainWallFermionR,LatticeFermion> HermOp(Ddwf); |  | ||||||
| //  SchurDiagTwoOperator<DomainWallFermionR,LatticeFermion> HermOp(Ddwf); |  | ||||||
|   SchurDiagTwoOperator<GparityMobiusFermionR,FermionField> HermOp(Ddwf); |  | ||||||
| //  SchurDiagMooeeOperator<DomainWallFermionR,LatticeFermion> HermOp(Ddwf); |  | ||||||
|  |  | ||||||
|   const int Nstop = 30; |   const int Nstop = 30; | ||||||
|   const int Nk = 40; |   const int Nk = 40; | ||||||
| @@ -91,7 +101,6 @@ int main (int argc, char ** argv) | |||||||
|  |  | ||||||
|   ImplicitlyRestartedLanczos<FermionField> IRL(OpCheby,Op,Nstop,Nk,Nm,resid,MaxIt); |   ImplicitlyRestartedLanczos<FermionField> IRL(OpCheby,Op,Nstop,Nk,Nm,resid,MaxIt); | ||||||
|   |   | ||||||
|    |  | ||||||
|   std::vector<RealD>          eval(Nm); |   std::vector<RealD>          eval(Nm); | ||||||
|   FermionField    src(FrbGrid);  |   FermionField    src(FrbGrid);  | ||||||
|   gaussian(RNG5rb,src); |   gaussian(RNG5rb,src); | ||||||
| @@ -103,6 +112,28 @@ int main (int argc, char ** argv) | |||||||
|   int Nconv; |   int Nconv; | ||||||
|   IRL.calc(eval,evec,src,Nconv); |   IRL.calc(eval,evec,src,Nconv); | ||||||
|  |  | ||||||
|  |   delete action; | ||||||
|  | } | ||||||
|  |    | ||||||
|  | int main (int argc, char ** argv) | ||||||
|  | { | ||||||
|  |   Grid_init(&argc,&argv); | ||||||
|  |  | ||||||
|  |   std::string action = "GparityMobius"; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     if(std::string(argv[i]) == "-action"){ | ||||||
|  |       action = argv[i+1]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(action == "GparityMobius"){ | ||||||
|  |     run<GparityMobiusFermionR>(); | ||||||
|  |   }else if(action == "DWF"){ | ||||||
|  |     run<DomainWallFermionR>(); | ||||||
|  |   }else{ | ||||||
|  |     std::cout << "Unknown action" << std::endl; | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|    |    | ||||||
|   Grid_finalize(); |   Grid_finalize(); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										576
									
								
								tests/lanczos/Test_evec_compression.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										576
									
								
								tests/lanczos/Test_evec_compression.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,576 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/Test_evec_compression.cc | ||||||
|  |  | ||||||
|  |     Copyright (C) 2017 | ||||||
|  |  | ||||||
|  | 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 */ | ||||||
|  | /* | ||||||
|  |  * | ||||||
|  |  * This test generates eigenvectors using the Lanczos algorithm then attempts to use local coherence compression | ||||||
|  |  * to express those vectors in terms of a basis formed from a subset. This test is useful for finding the optimal | ||||||
|  |  * blocking and basis size for performing a Local Coherence Lanczos | ||||||
|  |  */ | ||||||
|  | #include <Grid/Grid.h> | ||||||
|  | #include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h> | ||||||
|  | #include <Grid/algorithms/iterative/LocalCoherenceLanczos.h> | ||||||
|  |  | ||||||
|  | using namespace std; | ||||||
|  | using namespace Grid; | ||||||
|  |  | ||||||
|  | //For the CPS configurations we have to manually seed the RNG and deal with an incorrect factor of 2 in the plaquette metadata | ||||||
|  | template<typename Gimpl> | ||||||
|  | void readConfiguration(LatticeGaugeFieldD &U, | ||||||
|  | 		       const std::string &config, | ||||||
|  | 		       bool is_cps_cfg = false){ | ||||||
|  |  | ||||||
|  |   if(is_cps_cfg) NerscIO::exitOnReadPlaquetteMismatch() = false; | ||||||
|  |  | ||||||
|  |   typedef GaugeStatistics<Gimpl> GaugeStats; | ||||||
|  |       | ||||||
|  |   FieldMetaData header; | ||||||
|  |   NerscIO::readConfiguration<GaugeStats>(U, header, config); | ||||||
|  |  | ||||||
|  |   if(is_cps_cfg) NerscIO::exitOnReadPlaquetteMismatch() = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Lanczos parameters in CPS conventions | ||||||
|  | struct CPSLanczosParams : Serializable { | ||||||
|  | public: | ||||||
|  |   GRID_SERIALIZABLE_CLASS_MEMBERS(CPSLanczosParams, | ||||||
|  | 				  RealD, alpha, | ||||||
|  | 				  RealD, beta, | ||||||
|  | 				  int, ch_ord, | ||||||
|  | 				  int, N_use, | ||||||
|  | 				  int, N_get, | ||||||
|  | 				  int, N_true_get, | ||||||
|  | 				  RealD, stop_rsd, | ||||||
|  | 				  int, maxits); | ||||||
|  |  | ||||||
|  |   //Translations | ||||||
|  |   ChebyParams getChebyParams() const{ | ||||||
|  |     ChebyParams out; | ||||||
|  |     out.alpha = beta*beta; //aka lo | ||||||
|  |     out.beta = alpha*alpha; //aka hi | ||||||
|  |     out.Npoly = ch_ord+1; | ||||||
|  |     return out; | ||||||
|  |   } | ||||||
|  |   int Nstop() const{ return N_true_get; } | ||||||
|  |   int Nm() const{ return N_use; } | ||||||
|  |   int Nk() const{ return N_get; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | class LocalCoherenceCompressor{ | ||||||
|  | public: | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CComplex>                   CoarseScalar; // used for inner products on fine field | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<Fobj>                       FineField; | ||||||
|  |    | ||||||
|  |   void compress(std::vector<FineField> &basis, | ||||||
|  | 		std::vector<CoarseField> &compressed_evecs, | ||||||
|  | 		const std::vector<FineField> &evecs_in, | ||||||
|  | 		GridBase *FineGrid, | ||||||
|  | 		GridBase *CoarseGrid){ | ||||||
|  |     int nevecs = evecs_in.size(); | ||||||
|  |     assert(nevecs > nbasis); | ||||||
|  |      | ||||||
|  |     //Construct the basis | ||||||
|  |     basis.resize(nbasis, FineGrid); | ||||||
|  |     for(int b=0;b<nbasis;b++) basis[b] = evecs_in[b]; | ||||||
|  |  | ||||||
|  |     //Block othornormalize basis | ||||||
|  |     CoarseScalar InnerProd(CoarseGrid); | ||||||
|  |     std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl; | ||||||
|  |     blockOrthogonalise(InnerProd,basis); | ||||||
|  |     std::cout << GridLogMessage <<" Gramm-Schmidt pass 2"<<std::endl; | ||||||
|  |     blockOrthogonalise(InnerProd,basis); | ||||||
|  |  | ||||||
|  |     //The coarse grid representation is the field of vectors of block inner products | ||||||
|  |     std::cout << GridLogMessage << "Compressing eigevectors" << std::endl; | ||||||
|  |     compressed_evecs.resize(nevecs, CoarseGrid); | ||||||
|  |     for(int i=0;i<nevecs;i++) blockProject(compressed_evecs[i], evecs_in[i], basis); | ||||||
|  |     std::cout << GridLogMessage << "Compression complete" << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void uncompress(FineField &evec, const int i, const std::vector<FineField> &basis, const std::vector<CoarseField> &compressed_evecs) const{ | ||||||
|  |     blockPromote(compressed_evecs[i],evec,basis);   | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Test uncompressed eigenvectors of Linop.HermOp to precision 'base_tolerance' for i<nbasis and 'base_tolerance*relax' for i>=nbasis | ||||||
|  |   //Because the uncompressed evec has a lot of high mode noise (unimportant for deflation) we apply a smoother before testing. | ||||||
|  |   //The Chebyshev used by the Lanczos should be sufficient as a smoother | ||||||
|  |   bool testCompression(LinearOperatorBase<FineField> &Linop, OperatorFunction<FineField>   &smoother, | ||||||
|  | 		       const std::vector<FineField> &basis, const std::vector<CoarseField> &compressed_evecs, const std::vector<RealD> &evals, | ||||||
|  | 		       const RealD base_tolerance, const RealD relax){ | ||||||
|  |     std::cout << GridLogMessage << "Testing quality of uncompressed evecs (after smoothing)" << std::endl; | ||||||
|  |     | ||||||
|  |     GridBase* FineGrid = basis[0].Grid(); | ||||||
|  |     GridBase* CoarseGrid = compressed_evecs[0].Grid(); | ||||||
|  |  | ||||||
|  |     bool fail = false; | ||||||
|  |     FineField evec(FineGrid), Mevec(FineGrid), evec_sm(FineGrid); | ||||||
|  |     for(int i=0;i<compressed_evecs.size();i++){ | ||||||
|  |       std::cout << GridLogMessage << "Uncompressing evec " << i << std::endl; | ||||||
|  |       uncompress(evec, i, basis, compressed_evecs); | ||||||
|  |  | ||||||
|  |       std::cout << GridLogMessage << "Smoothing evec " << i << std::endl; | ||||||
|  |       smoother(Linop, evec, evec_sm); | ||||||
|  |        | ||||||
|  |       std::cout << GridLogMessage << "Computing residual for evec " << i << std::endl; | ||||||
|  |       std::cout << GridLogMessage << "Linop" << std::endl; | ||||||
|  |       Linop.HermOp(evec_sm, Mevec); | ||||||
|  |       std::cout << GridLogMessage << "Linalg" << std::endl; | ||||||
|  |       Mevec = Mevec - evals[i]*evec_sm; | ||||||
|  |  | ||||||
|  |       std::cout << GridLogMessage << "Resid" << std::endl; | ||||||
|  |       RealD tol = base_tolerance * (i<nbasis ? 1. : relax); | ||||||
|  |       RealD res = sqrt(norm2(Mevec)); | ||||||
|  |       std::cout << GridLogMessage << "Evec idx " << i << " res " << res << " tol " << tol << std::endl; | ||||||
|  |       if(res > tol) fail = true; | ||||||
|  |     } | ||||||
|  |     return fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Compare uncompressed evecs to original evecs | ||||||
|  |   void compareEvecs(const std::vector<FineField> &basis, const std::vector<CoarseField> &compressed_evecs, const std::vector<FineField> &orig_evecs){ | ||||||
|  |     std::cout << GridLogMessage << "Comparing uncompressed evecs to original evecs" << std::endl; | ||||||
|  |      | ||||||
|  |     GridBase* FineGrid = basis[0].Grid(); | ||||||
|  |     GridBase* CoarseGrid = compressed_evecs[0].Grid(); | ||||||
|  |  | ||||||
|  |     FineField evec(FineGrid), diff(FineGrid); | ||||||
|  |     for(int i=0;i<compressed_evecs.size();i++){ | ||||||
|  |       std::cout << GridLogMessage << "Uncompressing evec " << i << std::endl; | ||||||
|  |       uncompress(evec, i, basis, compressed_evecs); | ||||||
|  |       diff = orig_evecs[i] - evec; | ||||||
|  |       RealD res = sqrt(norm2(diff)); | ||||||
|  |       std::cout << GridLogMessage << "Evec idx " << i << " res " << res << std::endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<class Fobj,class CComplex,int nbasis> | ||||||
|  | void compareBlockPromoteTimings(const std::vector<Lattice<Fobj> > &basis, const std::vector<Lattice<iVector<CComplex,nbasis > > > &compressed_evecs){ | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CComplex>                   CoarseScalar;  | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |   typedef Lattice<Fobj>                       FineField; | ||||||
|  |  | ||||||
|  |   GridStopWatch timer; | ||||||
|  |    | ||||||
|  |   GridBase* FineGrid = basis[0].Grid(); | ||||||
|  |   GridBase* CoarseGrid = compressed_evecs[0].Grid(); | ||||||
|  |  | ||||||
|  |   FineField v1(FineGrid), v2(FineGrid); | ||||||
|  |  | ||||||
|  |   //Start with a cold start | ||||||
|  |   for(int i=0;i<basis.size();i++){ | ||||||
|  |     autoView( b_ , basis[i], CpuWrite); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<compressed_evecs.size();i++){ | ||||||
|  |     autoView( b_ , compressed_evecs[i], CpuWrite); | ||||||
|  |   } | ||||||
|  |   { | ||||||
|  |     autoView( b_, v1, CpuWrite ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   timer.Start(); | ||||||
|  |   blockPromote(compressed_evecs[0],v1,basis);   | ||||||
|  |   timer.Stop(); | ||||||
|  |   std::cout << GridLogMessage << "Time for cold blockPromote v1 " << timer.Elapsed() << std::endl; | ||||||
|  |  | ||||||
|  |   //Test to ensure it is actually doing a cold start by repeating | ||||||
|  |   for(int i=0;i<basis.size();i++){ | ||||||
|  |     autoView( b_ , basis[i], CpuWrite); | ||||||
|  |   } | ||||||
|  |   for(int i=0;i<compressed_evecs.size();i++){ | ||||||
|  |     autoView( b_ , compressed_evecs[i], CpuWrite); | ||||||
|  |   } | ||||||
|  |   { | ||||||
|  |     autoView( b_, v1, CpuWrite ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   timer.Reset(); | ||||||
|  |   timer.Start(); | ||||||
|  |   blockPromote(compressed_evecs[0],v1,basis);   | ||||||
|  |   timer.Stop(); | ||||||
|  |   std::cout << GridLogMessage << "Time for cold blockPromote v1 repeat (should be the same as above) " << timer.Elapsed() << std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct Args{ | ||||||
|  |   int Ls; | ||||||
|  |   RealD mass; | ||||||
|  |   RealD M5; | ||||||
|  |   bool is_cps_cfg; | ||||||
|  |   RealD mobius_scale; //b+c | ||||||
|  |    | ||||||
|  |   CPSLanczosParams fine; | ||||||
|  |   double coarse_relax_tol; | ||||||
|  |  | ||||||
|  |   std::vector<int> blockSize; | ||||||
|  |   std::vector<int> GparityDirs; | ||||||
|  |  | ||||||
|  |   bool write_fine; | ||||||
|  |   std::string write_fine_file; | ||||||
|  |   bool read_fine; | ||||||
|  |   std::string read_fine_file; | ||||||
|  |  | ||||||
|  |   int basis_size; | ||||||
|  |    | ||||||
|  |   Args(){ | ||||||
|  |     blockSize = {2,2,2,2,2}; | ||||||
|  |     GparityDirs = {1,1,1}; //1 for each GP direction | ||||||
|  |      | ||||||
|  |     Ls = 12; | ||||||
|  |     mass = 0.01; | ||||||
|  |     M5 = 1.8; | ||||||
|  |     is_cps_cfg = false; | ||||||
|  |     mobius_scale = 2; | ||||||
|  |      | ||||||
|  |     fine.alpha = 2; | ||||||
|  |     fine.beta = 0.1; | ||||||
|  |     fine.ch_ord = 100; | ||||||
|  |     fine.N_use = 70; | ||||||
|  |     fine.N_get = 60; | ||||||
|  |     fine.N_true_get = 60; | ||||||
|  |     fine.stop_rsd = 1e-8; | ||||||
|  |     fine.maxits = 10000; | ||||||
|  |  | ||||||
|  |     coarse_relax_tol = 1e5; | ||||||
|  |  | ||||||
|  |     write_fine = false; | ||||||
|  |     read_fine = false; | ||||||
|  |  | ||||||
|  |     basis_size = 100; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |      | ||||||
|  |  | ||||||
|  | GparityWilsonImplD::ImplParams setupGparityParams(const std::vector<int> &GparityDirs){ | ||||||
|  |   //Setup G-parity BCs | ||||||
|  |   assert(Nd == 4); | ||||||
|  |   std::vector<int> dirs4(4); | ||||||
|  |   for(int i=0;i<3;i++) dirs4[i] = GparityDirs[i]; | ||||||
|  |   dirs4[3] = 0; //periodic gauge BC in time | ||||||
|  |    | ||||||
|  |   std::cout << GridLogMessage << "Gauge BCs: " << dirs4 << std::endl; | ||||||
|  |   ConjugateGimplD::setDirections(dirs4); //gauge BC | ||||||
|  |  | ||||||
|  |   GparityWilsonImplD::ImplParams Params; | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.twists[i] = GparityDirs[i]; //G-parity directions | ||||||
|  |   Params.twists[Nd-1] = 1; //APBC in time direction | ||||||
|  |   std::cout << GridLogMessage << "Fermion BCs: " << Params.twists << std::endl; | ||||||
|  |   return Params; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | WilsonImplD::ImplParams setupParams(){ | ||||||
|  |   WilsonImplD::ImplParams Params; | ||||||
|  |   Complex one(1.0); | ||||||
|  |   Complex mone(-1.0); | ||||||
|  |   for(int i=0;i<Nd-1;i++) Params.boundary_phases[i] = one; | ||||||
|  |   Params.boundary_phases[Nd-1] = mone; | ||||||
|  |   return Params; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<int nbasis, typename ActionType> | ||||||
|  | void run_b(ActionType &action, const std::string &config, const Args &args){ | ||||||
|  |   //Fine grids | ||||||
|  |   GridCartesian         * UGrid     = (GridCartesian*)action.GaugeGrid(); | ||||||
|  |   GridRedBlackCartesian * UrbGrid   = (GridRedBlackCartesian*)action.GaugeRedBlackGrid(); | ||||||
|  |   GridCartesian         * FGrid     = (GridCartesian*)action.FermionGrid(); | ||||||
|  |   GridRedBlackCartesian * FrbGrid   = (GridRedBlackCartesian*)action.FermionRedBlackGrid(); | ||||||
|  |  | ||||||
|  |   //Setup the coarse grids   | ||||||
|  |   auto fineLatt     = GridDefaultLatt(); | ||||||
|  |   Coordinate coarseLatt(4); | ||||||
|  |   for (int d=0;d<4;d++){ | ||||||
|  |     coarseLatt[d] = fineLatt[d]/args.blockSize[d];    assert(coarseLatt[d]*args.blockSize[d]==fineLatt[d]); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage<< " 5d coarse lattice is "; | ||||||
|  |   for (int i=0;i<4;i++){ | ||||||
|  |     std::cout << coarseLatt[i]<<"x"; | ||||||
|  |   }  | ||||||
|  |   int cLs = args.Ls/args.blockSize[4]; assert(cLs*args.blockSize[4]==args.Ls); | ||||||
|  |   std::cout << cLs<<std::endl; | ||||||
|  |    | ||||||
|  |   GridCartesian         * CoarseGrid4    = SpaceTimeGrid::makeFourDimGrid(coarseLatt, GridDefaultSimd(Nd,vComplex::Nsimd()),GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian * CoarseGrid4rb  = SpaceTimeGrid::makeFourDimRedBlackGrid(CoarseGrid4); | ||||||
|  |   GridCartesian         * CoarseGrid5    = SpaceTimeGrid::makeFiveDimGrid(cLs,CoarseGrid4); | ||||||
|  |   typedef vTComplex CComplex;  | ||||||
|  |   typedef iVector<CComplex,nbasis >           CoarseSiteVector; | ||||||
|  |   typedef Lattice<CComplex>                   CoarseScalar; | ||||||
|  |   typedef Lattice<CoarseSiteVector>           CoarseField; | ||||||
|  |  | ||||||
|  |   typedef typename ActionType::FermionField FermionField;  | ||||||
|  |    | ||||||
|  |   SchurDiagTwoOperator<ActionType,FermionField> SchurOp(action); | ||||||
|  |  | ||||||
|  |   typedef typename ActionType::SiteSpinor SiteSpinor; | ||||||
|  |  | ||||||
|  |   const CPSLanczosParams &fine = args.fine; | ||||||
|  |    | ||||||
|  |   //Do the fine Lanczos | ||||||
|  |   std::vector<RealD> evals; | ||||||
|  |   std::vector<FermionField> evecs; | ||||||
|  |  | ||||||
|  |   if(args.read_fine){ | ||||||
|  |     evals.resize(fine.N_true_get); | ||||||
|  |     evecs.resize(fine.N_true_get, FrbGrid); | ||||||
|  |  | ||||||
|  |     std::string evals_file = args.read_fine_file + "_evals.xml"; | ||||||
|  |     std::string evecs_file = args.read_fine_file + "_evecs.scidac"; | ||||||
|  |      | ||||||
|  |     std::cout << GridLogIRL<< "Reading evals from "<<evals_file<<std::endl; | ||||||
|  |     XmlReader RDx(evals_file); | ||||||
|  |     read(RDx,"evals",evals); | ||||||
|  |      | ||||||
|  |     assert(evals.size()==fine.N_true_get); | ||||||
|  |      | ||||||
|  |     std::cout << GridLogIRL<< "Reading evecs from "<<evecs_file<<std::endl; | ||||||
|  |     emptyUserRecord record; | ||||||
|  |     Grid::ScidacReader RD ; | ||||||
|  |     RD.open(evecs_file); | ||||||
|  |     for(int k=0;k<fine.N_true_get;k++) { | ||||||
|  |       evecs[k].Checkerboard()=Odd; | ||||||
|  |       RD.readScidacFieldRecord(evecs[k],record); | ||||||
|  |        | ||||||
|  |     } | ||||||
|  |     RD.close(); | ||||||
|  |   }else{  | ||||||
|  |     int Nstop = fine.Nstop(); //==N_true_get | ||||||
|  |     int Nm = fine.Nm(); | ||||||
|  |     int Nk = fine.Nk(); | ||||||
|  |     RealD resid = fine.stop_rsd; | ||||||
|  |     int MaxIt = fine.maxits; | ||||||
|  |      | ||||||
|  |     assert(nbasis<=Nm);     | ||||||
|  |     Chebyshev<FermionField>      Cheby(fine.getChebyParams()); | ||||||
|  |     FunctionHermOp<FermionField> ChebyOp(Cheby,SchurOp); | ||||||
|  |     PlainHermOp<FermionField>    Op(SchurOp); | ||||||
|  |  | ||||||
|  |     evals.resize(Nm); | ||||||
|  |     evecs.resize(Nm,FrbGrid); | ||||||
|  |      | ||||||
|  |     ImplicitlyRestartedLanczos<FermionField> IRL(ChebyOp,Op,Nstop,Nk,Nm,resid,MaxIt,0,0); | ||||||
|  |  | ||||||
|  |     FermionField src(FrbGrid);  | ||||||
|  |     typedef typename FermionField::scalar_type Scalar; | ||||||
|  |     src=Scalar(1.0);  | ||||||
|  |     src.Checkerboard() = Odd; | ||||||
|  |  | ||||||
|  |     int Nconv; | ||||||
|  |     IRL.calc(evals, evecs,src,Nconv,false); | ||||||
|  |     if(Nconv < Nstop) assert(0 && "Fine lanczos failed to converge the required number of evecs"); //algorithm doesn't consider this a failure | ||||||
|  |     if(Nconv > Nstop){ | ||||||
|  |       //Yes this potentially throws away some evecs but it is better than having a random number of evecs between Nstop and Nm! | ||||||
|  |       evals.resize(Nstop); | ||||||
|  |       evecs.resize(Nstop, FrbGrid); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if(args.write_fine){ | ||||||
|  |       std::string evals_file = args.write_fine_file + "_evals.xml"; | ||||||
|  |       std::string evecs_file = args.write_fine_file + "_evecs.scidac"; | ||||||
|  |  | ||||||
|  |       std::cout << GridLogIRL<< "Writing evecs to "<<evecs_file<<std::endl; | ||||||
|  |  | ||||||
|  |       emptyUserRecord record; | ||||||
|  |       Grid::ScidacWriter WR(FrbGrid->IsBoss()); | ||||||
|  |       WR.open(evecs_file); | ||||||
|  |       for(int k=0;k<evecs.size();k++) { | ||||||
|  | 	WR.writeScidacFieldRecord(evecs[k],record); | ||||||
|  |       } | ||||||
|  |       WR.close(); | ||||||
|  |  | ||||||
|  |       std::cout << GridLogIRL<< "Writing evals to "<<evals_file<<std::endl; | ||||||
|  |        | ||||||
|  |       XmlWriter WRx(evals_file); | ||||||
|  |       write(WRx,"evals",evals); | ||||||
|  |     }     | ||||||
|  |   } | ||||||
|  |      | ||||||
|  |   //Do the compression | ||||||
|  |   LocalCoherenceCompressor<SiteSpinor,vTComplex,nbasis> compressor; | ||||||
|  |   std::vector<FermionField> basis(nbasis,FrbGrid); | ||||||
|  |   std::vector<CoarseField> compressed_evecs(evecs.size(),CoarseGrid5); | ||||||
|  |    | ||||||
|  |   compressor.compress(basis, compressed_evecs, evecs, FrbGrid, CoarseGrid5); | ||||||
|  |  | ||||||
|  |   compareBlockPromoteTimings(basis, compressed_evecs); | ||||||
|  |  | ||||||
|  |   //Compare uncompressed and original evecs | ||||||
|  |   compressor.compareEvecs(basis, compressed_evecs, evecs); | ||||||
|  |    | ||||||
|  |   //Create the smoother | ||||||
|  |   Chebyshev<FermionField> smoother(fine.getChebyParams()); | ||||||
|  |    | ||||||
|  |   //Test the quality of the uncompressed evecs | ||||||
|  |   assert( compressor.testCompression(SchurOp, smoother, basis, compressed_evecs, evals, fine.stop_rsd, args.coarse_relax_tol) );    | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ActionType> | ||||||
|  | void run(ActionType &action, const std::string &config, const Args &args){ | ||||||
|  |   switch(args.basis_size){ | ||||||
|  |   case 50: | ||||||
|  |     return run_b<50>(action,config,args); | ||||||
|  |   case 100: | ||||||
|  |     return run_b<100>(action,config,args); | ||||||
|  |   case 150: | ||||||
|  |     return run_b<150>(action,config,args); | ||||||
|  |   case 200: | ||||||
|  |     return run_b<200>(action,config,args); | ||||||
|  |   case 250: | ||||||
|  |     return run_b<250>(action,config,args); | ||||||
|  |   default: | ||||||
|  |     assert(0 && "Unsupported basis size: allowed values are 50,100,200"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //Note:  because we rely upon physical properties we must use a "real" gauge configuration | ||||||
|  | int main (int argc, char ** argv) { | ||||||
|  |   Grid_init(&argc,&argv); | ||||||
|  |   GridLogIRL.TimingMode(1); | ||||||
|  |  | ||||||
|  |   if(argc < 3){ | ||||||
|  |     std::cout << GridLogMessage << "Usage: <exe> <config file> <gparity dirs> <options>" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "<gparity dirs> should have the format a.b.c where a,b,c are 0,1 depending on whether there are G-parity BCs in that direction" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "Options:" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--Ls <value> : Set Ls (default 12)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--mass <value> : Set the mass (default 0.01)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--block <value> : Set the block size. Format should be a.b.c.d.e where a-e are the block extents  (default 2.2.2.2.2)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--is_cps_cfg : Indicate that the configuration was generated with CPS where until recently the stored plaquette was wrong by a factor of 2" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--write_irl_templ: Write a template for the parameters file of the Lanczos to \"irl_templ.xml\"" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--read_irl_fine <filename>: Real the parameters file for the fine Lanczos" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--write_fine <filename stub>: Write fine evecs/evals to filename starting with the stub" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--read_fine <filename stub>: Read fine evecs/evals from filename starting with the stub" << std::endl;     | ||||||
|  |     std::cout << GridLogMessage << "--coarse_relax_tol : Set the relaxation parameter for evaluating the residual of the reconstructed eigenvectors outside of the basis (default 1e5)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--action : Set the action from 'DWF', 'Mobius'  (default Mobius)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--mobius_scale : Set the Mobius scale b+c (default 2)" << std::endl; | ||||||
|  |     std::cout << GridLogMessage << "--basis_size : Set the basis size from 50,100,150,200,250 (default 100)" << std::endl; | ||||||
|  |  | ||||||
|  |     Grid_finalize(); | ||||||
|  |     return 1; | ||||||
|  |   } | ||||||
|  |   std::string config = argv[1]; | ||||||
|  |  | ||||||
|  |   Args args; | ||||||
|  |   GridCmdOptionIntVector(argv[2], args.GparityDirs); | ||||||
|  |   assert(args.GparityDirs.size() == 3); | ||||||
|  |  | ||||||
|  |   std::string action_s = "Mobius";  | ||||||
|  |    | ||||||
|  |   for(int i=3;i<argc;i++){ | ||||||
|  |     std::string sarg = argv[i]; | ||||||
|  |     if(sarg == "--Ls"){ | ||||||
|  |       args.Ls = std::stoi(argv[i+1]); | ||||||
|  |       std::cout << GridLogMessage << "Set Ls to " << args.Ls << std::endl; | ||||||
|  |     }else if(sarg == "--mass"){ | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> args.mass; | ||||||
|  |       std::cout << GridLogMessage << "Set quark mass to " << args.mass << std::endl; | ||||||
|  |     }else if(sarg == "--block"){ | ||||||
|  |       GridCmdOptionIntVector(argv[i+1], args.blockSize); | ||||||
|  |       assert(args.blockSize.size() == 5); | ||||||
|  |       std::cout << GridLogMessage << "Set block size to "; | ||||||
|  |       for(int q=0;q<5;q++) std::cout << args.blockSize[q] << " "; | ||||||
|  |       std::cout << std::endl;       | ||||||
|  |     }else if(sarg == "--is_cps_cfg"){ | ||||||
|  |       args.is_cps_cfg = true; | ||||||
|  |     }else if(sarg == "--write_irl_templ"){ | ||||||
|  |       XmlWriter writer("irl_templ.xml"); | ||||||
|  |       write(writer,"Params",args.fine); | ||||||
|  |       Grid_finalize(); | ||||||
|  |       return 0; | ||||||
|  |     }else if(sarg == "--read_irl_fine"){ | ||||||
|  |       std::cout << GridLogMessage << "Reading fine IRL params from " << argv[i+1] << std::endl; | ||||||
|  |       XmlReader reader(argv[i+1]); | ||||||
|  |       read(reader, "Params", args.fine); | ||||||
|  |     }else if(sarg == "--write_fine"){ | ||||||
|  |       args.write_fine = true; | ||||||
|  |       args.write_fine_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--read_fine"){ | ||||||
|  |       args.read_fine = true; | ||||||
|  |       args.read_fine_file = argv[i+1]; | ||||||
|  |     }else if(sarg == "--coarse_relax_tol"){ | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> args.coarse_relax_tol; | ||||||
|  |       std::cout << GridLogMessage << "Set coarse IRL relaxation parameter to " << args.coarse_relax_tol << std::endl; | ||||||
|  |     }else if(sarg == "--action"){ | ||||||
|  |       action_s = argv[i+1]; | ||||||
|  |       std::cout << "Action set to " << action_s << std::endl; | ||||||
|  |     }else if(sarg == "--mobius_scale"){ | ||||||
|  |       std::istringstream ss(argv[i+1]); ss >> args.mobius_scale; | ||||||
|  |       std::cout << GridLogMessage << "Set Mobius scale to " << args.mobius_scale << std::endl; | ||||||
|  |     }else if(sarg == "--basis_size"){ | ||||||
|  |       args.basis_size = std::stoi(argv[i+1]); | ||||||
|  |       std::cout << GridLogMessage << "Set basis size to " << args.basis_size << std::endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   //Fine grids | ||||||
|  |   GridCartesian         * UGrid     = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(),  GridDefaultSimd(Nd,vComplex::Nsimd()),   GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian * UrbGrid   = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||||
|  |   GridCartesian         * FGrid     = SpaceTimeGrid::makeFiveDimGrid(args.Ls,UGrid); | ||||||
|  |   GridRedBlackCartesian * FrbGrid   = SpaceTimeGrid::makeFiveDimRedBlackGrid(args.Ls,UGrid); | ||||||
|  |  | ||||||
|  |   LatticeGaugeField Umu(UGrid);   | ||||||
|  |    | ||||||
|  |   bool is_gparity = false; | ||||||
|  |   for(auto g : args.GparityDirs) if(g) is_gparity = true; | ||||||
|  |  | ||||||
|  |   double bmc =  1.;       | ||||||
|  |   double b = (args.mobius_scale + bmc)/2.;  // b = 1/2 [ (b+c) + (b-c) ] | ||||||
|  |   double c = (args.mobius_scale - bmc)/2.;  // c = 1/2 [ (b+c) - (b-c) ] | ||||||
|  |      | ||||||
|  |   if(is_gparity){ | ||||||
|  |     GparityWilsonImplD::ImplParams Params = setupGparityParams(args.GparityDirs); | ||||||
|  |     readConfiguration<ConjugateGimplD>(Umu, config, args.is_cps_cfg);   //Read the gauge field | ||||||
|  |      | ||||||
|  |     if(action_s == "DWF"){     | ||||||
|  |       GparityDomainWallFermionD action(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, args.mass, args.M5, Params); | ||||||
|  |       run(action, config, args); | ||||||
|  |     }else if(action_s == "Mobius"){ | ||||||
|  |       GparityMobiusFermionD action(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, args.mass, args.M5, b, c, Params); | ||||||
|  |       run(action, config, args);	     | ||||||
|  |     }       | ||||||
|  |   }else{ | ||||||
|  |     WilsonImplD::ImplParams Params = setupParams(); | ||||||
|  |     readConfiguration<PeriodicGimplD>(Umu, config, args.is_cps_cfg);   //Read the gauge field | ||||||
|  |      | ||||||
|  |     if(action_s == "DWF"){     | ||||||
|  |       DomainWallFermionD action(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, args.mass, args.M5, Params); | ||||||
|  |       run(action, config, args); | ||||||
|  |     }else if(action_s == "Mobius"){ | ||||||
|  |       MobiusFermionD action(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, args.mass, args.M5, b, c, Params); | ||||||
|  |       run(action, config, args);	     | ||||||
|  |     } | ||||||
|  |   }  | ||||||
|  |    | ||||||
|  |   Grid_finalize(); | ||||||
|  | } | ||||||
							
								
								
									
										184
									
								
								tests/solver/Test_dwf_multishift_mixedprec.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								tests/solver/Test_dwf_multishift_mixedprec.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | |||||||
|  |     /************************************************************************************* | ||||||
|  |  | ||||||
|  |     Grid physics library, www.github.com/paboyle/Grid  | ||||||
|  |  | ||||||
|  |     Source file: ./tests/Test_dwf_multishift_mixedprec.cc | ||||||
|  |  | ||||||
|  |     Copyright (C) 2015 | ||||||
|  |  | ||||||
|  | Author: Christopher Kelly <ckelly@bnl.gov> | ||||||
|  |  | ||||||
|  |     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 SpeciesD, typename SpeciesF, typename GaugeStatisticsType> | ||||||
|  | void run_test(int argc, char ** argv, const typename SpeciesD::ImplParams ¶ms){ | ||||||
|  |   const int Ls = 16; | ||||||
|  |   GridCartesian* UGrid_d = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexD::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* UrbGrid_d = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid_d); | ||||||
|  |   GridCartesian* FGrid_d = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid_d); | ||||||
|  |   GridRedBlackCartesian* FrbGrid_d = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid_d); | ||||||
|  |  | ||||||
|  |   GridCartesian* UGrid_f = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi()); | ||||||
|  |   GridRedBlackCartesian* UrbGrid_f = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid_f); | ||||||
|  |   GridCartesian* FGrid_f = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid_f); | ||||||
|  |   GridRedBlackCartesian* FrbGrid_f = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid_f); | ||||||
|  |  | ||||||
|  |   typedef typename SpeciesD::FermionField FermionFieldD; | ||||||
|  |   typedef typename SpeciesF::FermionField FermionFieldF; | ||||||
|  |    | ||||||
|  |   std::vector<int> seeds4({1, 2, 3, 4}); | ||||||
|  |   std::vector<int> seeds5({5, 6, 7, 8}); | ||||||
|  |   GridParallelRNG RNG5(FGrid_d); | ||||||
|  |   RNG5.SeedFixedIntegers(seeds5); | ||||||
|  |   GridParallelRNG RNG4(UGrid_d); | ||||||
|  |   RNG4.SeedFixedIntegers(seeds4); | ||||||
|  |  | ||||||
|  |   FermionFieldD src_d(FGrid_d); | ||||||
|  |   random(RNG5, src_d); | ||||||
|  |  | ||||||
|  |   LatticeGaugeFieldD Umu_d(UGrid_d); | ||||||
|  |  | ||||||
|  |   //CPS-created G-parity ensembles have a factor of 2 error in the plaquette that causes the read to fail unless we workaround it | ||||||
|  |   bool gparity_plaquette_fix = false; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     if(std::string(argv[i]) == "--gparity_plaquette_fix"){ | ||||||
|  |       gparity_plaquette_fix=true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool cfg_loaded=false; | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     if(std::string(argv[i]) == "--load_config"){ | ||||||
|  |       assert(i != argc-1); | ||||||
|  |       std::string file = argv[i+1]; | ||||||
|  |       NerscIO io; | ||||||
|  |       FieldMetaData metadata; | ||||||
|  |  | ||||||
|  |       if(gparity_plaquette_fix) NerscIO::exitOnReadPlaquetteMismatch() = false; | ||||||
|  |  | ||||||
|  |       io.readConfiguration<GaugeStatisticsType>(Umu_d, metadata, file); | ||||||
|  |  | ||||||
|  |       if(gparity_plaquette_fix){ | ||||||
|  | 	metadata.plaquette *= 2.; //correct header value | ||||||
|  |  | ||||||
|  | 	//Get the true plaquette | ||||||
|  | 	FieldMetaData tmp; | ||||||
|  | 	GaugeStatisticsType gs; gs(Umu_d, tmp); | ||||||
|  | 	 | ||||||
|  | 	std::cout << "After correction: plaqs " << tmp.plaquette << " " << metadata.plaquette << std::endl; | ||||||
|  | 	assert(fabs(tmp.plaquette -metadata.plaquette ) < 1.0e-5 ); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       cfg_loaded=true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(!cfg_loaded) | ||||||
|  |     SU<Nc>::HotConfiguration(RNG4, Umu_d); | ||||||
|  |  | ||||||
|  |   LatticeGaugeFieldF Umu_f(UGrid_f); | ||||||
|  |   precisionChange(Umu_f, Umu_d); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << "Lattice dimensions: " << GridDefaultLatt() << "   Ls: " << Ls << std::endl; | ||||||
|  |  | ||||||
|  |   RealD mass = 0.01; | ||||||
|  |   RealD M5 = 1.8; | ||||||
|  |   SpeciesD Ddwf_d(Umu_d, *FGrid_d, *FrbGrid_d, *UGrid_d, *UrbGrid_d, mass, M5, params); | ||||||
|  |   SpeciesF Ddwf_f(Umu_f, *FGrid_f, *FrbGrid_f, *UGrid_f, *UrbGrid_f, mass, M5, params); | ||||||
|  |  | ||||||
|  |   FermionFieldD src_o_d(FrbGrid_d); | ||||||
|  |   pickCheckerboard(Odd, src_o_d, src_d); | ||||||
|  |  | ||||||
|  |   SchurDiagMooeeOperator<SpeciesD, FermionFieldD> HermOpEO_d(Ddwf_d); | ||||||
|  |   SchurDiagMooeeOperator<SpeciesF, FermionFieldF> HermOpEO_f(Ddwf_f); | ||||||
|  |  | ||||||
|  |   AlgRemez remez(1e-4, 64, 50); | ||||||
|  |   int order = 15; | ||||||
|  |   remez.generateApprox(order, 1, 2); //sqrt | ||||||
|  |  | ||||||
|  |   MultiShiftFunction shifts(remez, 1e-10, false); | ||||||
|  |  | ||||||
|  |   int relup_freq = 50; | ||||||
|  |   double t1=usecond(); | ||||||
|  |   ConjugateGradientMultiShiftMixedPrec<FermionFieldD,FermionFieldF> mcg(10000, shifts, FrbGrid_f, HermOpEO_f, relup_freq); | ||||||
|  |  | ||||||
|  |   std::vector<FermionFieldD> results_o_d(order, FrbGrid_d); | ||||||
|  |   mcg(HermOpEO_d, src_o_d, results_o_d); | ||||||
|  |   double t2=usecond(); | ||||||
|  |  | ||||||
|  |   //Crosscheck double and mixed prec results | ||||||
|  |   ConjugateGradientMultiShift<FermionFieldD> dmcg(10000, shifts); | ||||||
|  |   std::vector<FermionFieldD> results_o_d_2(order, FrbGrid_d); | ||||||
|  |   dmcg(HermOpEO_d, src_o_d, results_o_d_2); | ||||||
|  |   double t3=usecond(); | ||||||
|  |  | ||||||
|  |   std::cout << GridLogMessage << "Comparison of mixed prec results to double prec results |mixed - double|^2 :" << std::endl; | ||||||
|  |   FermionFieldD tmp(FrbGrid_d); | ||||||
|  |   for(int i=0;i<order;i++){ | ||||||
|  |     RealD ndiff = axpy_norm(tmp, -1., results_o_d[i], results_o_d_2[i]); | ||||||
|  |     std::cout << i << " " << ndiff << std::endl; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::cout<<GridLogMessage << "Mixed precision algorithm: Total usec    =   "<< (t2-t1)<<std::endl; | ||||||
|  |   std::cout<<GridLogMessage << "Double precision algorithm: Total usec    =   "<< (t3-t2)<<std::endl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int main (int argc, char ** argv) | ||||||
|  | { | ||||||
|  |   Grid_init(&argc, &argv); | ||||||
|  |  | ||||||
|  |   bool gparity = false; | ||||||
|  |   int gpdir; | ||||||
|  |  | ||||||
|  |   for(int i=1;i<argc;i++){ | ||||||
|  |     std::string arg(argv[i]); | ||||||
|  |     if(arg == "--Gparity"){ | ||||||
|  |       assert(i!=argc-1); | ||||||
|  |       gpdir = std::stoi(argv[i+1]); | ||||||
|  |       assert(gpdir >= 0 && gpdir <= 2); //spatial! | ||||||
|  |       gparity = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if(gparity){ | ||||||
|  |     std::cout << "Running test with G-parity BCs in " << gpdir << " direction" << std::endl; | ||||||
|  |     GparityWilsonImplParams params; | ||||||
|  |     params.twists[gpdir] = 1; | ||||||
|  |      | ||||||
|  |     std::vector<int> conj_dirs(Nd,0); | ||||||
|  |     conj_dirs[gpdir] = 1; | ||||||
|  |     ConjugateGimplD::setDirections(conj_dirs); | ||||||
|  |  | ||||||
|  |     run_test<GparityDomainWallFermionD, GparityDomainWallFermionF, ConjugateGaugeStatistics>(argc,argv,params); | ||||||
|  |   }else{ | ||||||
|  |     std::cout << "Running test with periodic BCs" << std::endl; | ||||||
|  |     WilsonImplParams params; | ||||||
|  |     run_test<DomainWallFermionD, DomainWallFermionF, PeriodicGaugeStatistics>(argc,argv,params); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Grid_finalize(); | ||||||
|  | } | ||||||
							
								
								
									
										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(); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user