mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-10-31 03:54:33 +00:00 
			
		
		
		
	Compare commits
	
		
			161 Commits
		
	
	
		
			dirac-ITT
			...
			feature/la
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 27ea2afe86 | ||
|  | 78e8704eac | ||
|  | 67131d82f2 | ||
|  | 615a9448b9 | ||
|  | 00164f5ce5 | ||
|  | a7f72eb994 | ||
|  | 501fa1614a | ||
|  | 5bf42e1e15 | ||
|  | fe4d9b003c | ||
|  | 4a699b4da3 | ||
|  | 689323f4ee | ||
|  | 84b441800f | ||
|  | 1ef424b139 | ||
|  | aa66f41c69 | ||
|  | f96c800d25 | ||
|  | 32a52d7583 | ||
|  | fa04b6d3c2 | ||
|  | 7fab183c0e | ||
|  | 9ec9850bdb | ||
|  | 0c4ddaea0b | ||
|  | 00ebc150ad | ||
|  | 0f3e9ae57d | ||
|  | 034de160bf | ||
|  | 14507fd6e4 | ||
|  | 2db05ac214 | ||
|  | 31f99574fa | ||
|  | a34c8a2961 | ||
|  | ccd20df827 | ||
|  | e9be293444 | ||
|  | d577211cc3 | ||
|  | f4336e480a | ||
|  | e4d461cb03 | ||
|  | 3d63b4894e | ||
|  | 08583afaff | ||
|  | b395a312af | ||
|  | 66295b99aa | ||
|  | b8654be0ef | ||
|  | a479325349 | ||
|  | f6c3f6bf2d | ||
|  | d83868fdbb | ||
|  | 303e0b927d | ||
|  | 28ba8a0f48 | ||
|  | f9e28577f3 | ||
|  | 8a3aae98f6 | ||
|  | 8309f2364b | ||
|  | cac1750078 | ||
|  | 27936900e6 | ||
|  | e325929851 | ||
|  | 47af3565f4 | ||
|  | 4b4d187935 | ||
|  | 9aff354ab5 | ||
|  | cb9ff20249 | ||
|  | 9fe6ac71ea | ||
|  | f1fa00b71b | ||
|  | bf58557fb1 | ||
|  | 10cb37f504 | ||
|  | 1374c943d4 | ||
|  | a1d80282ec | ||
|  | 4eb8bbbebe | ||
|  | d1c6288c5f | ||
|  | dd949bc428 | ||
|  | bb7378cfc3 | ||
|  | f0e084a88c | ||
|  | 153672d8ec | ||
|  | 08ca338875 | ||
|  | f7cbf82c04 | ||
|  | 07009c569a | ||
|  | 09f4cdb11e | ||
|  | 1e54882f71 | ||
|  | d54807b8c0 | ||
|  | 5625b47c7d | ||
|  | 1edcf902b7 | ||
|  | e5c19e1fd7 | ||
|  | a11d0a33d1 | ||
|  | 4f8b6f26b4 | ||
|  | 073525c5b3 | ||
|  | eb6153080a | ||
|  | f7072d1ac2 | ||
|  | fddeb29d6b | ||
|  | a9ec5cf564 | ||
|  | 946a8671b9 | ||
|  | a6eeea777b | ||
|  | 771a1b8e79 | ||
|  | bfb68e6f02 | ||
|  | 77f7737ccc | ||
|  | 18c335198a | ||
|  | f9df685cde | ||
|  | 17c5b0f152 | ||
|  | 5918769f97 | ||
|  | bbaf1ada91 | ||
|  | 1950ac9294 | ||
|  | 13fa70ac1a | ||
|  | 7cb2b11f26 | ||
|  | 1184ed29ae | ||
|  | 203c7bf6fa | ||
|  | c709883f3f | ||
|  | aed5de4d50 | ||
|  | ba27cc6571 | ||
|  | d856327250 | ||
|  | a5fe07c077 | ||
|  | b83b2b1415 | ||
|  | 59bd1fe21b | ||
|  | 4e907fef2c | ||
|  | 67888b657f | ||
|  | 74af885d4e | ||
|  | d36d2fb40d | ||
|  | 4b4c2a715b | ||
|  | 54a5e6c1d0 | ||
|  | f365a83fae | ||
|  | 34a9aeb331 | ||
|  | edabb3577f | ||
|  | ce5df177ee | ||
|  | a0bb8e5b46 | ||
|  | 46f88e6d72 | ||
|  | dd8f1ea189 | ||
|  | b61835c1a5 | ||
|  | 459f70e8d4 | ||
|  | 061e48fd73 | ||
|  | ab50145001 | ||
|  | 9d45fca8bc | ||
|  | ac9e6b63c0 | ||
|  | e140b3f802 | ||
|  | d9d3d30cc7 | ||
|  | 47a12ec7b5 | ||
|  | ec1e2f7a40 | ||
|  | 41f73ec083 | ||
|  | 6d0786ff9d | ||
|  | b7f93aeb4d | ||
|  | 202a7fe900 | ||
|  | 7d867a8134 | ||
|  | 9939b267d2 | ||
|  | 8f4b3049cd | ||
|  | 2a6e673a91 | ||
|  | 9b6cde173f | ||
|  | 9f280b82c4 | ||
|  | 7a53dc3715 | ||
|  | 9fa07eecde | ||
|  | f64fb7bd77 | ||
|  | 2a35449b91 | ||
|  | 184af5bd05 | ||
|  | 097c9637ee | ||
|  | d9593c4b81 | ||
|  | ac740f73ce | ||
|  | 75dc7794b9 | ||
|  | dee68fc728 | ||
|  | a2d3643634 | ||
|  | 57002924bc | ||
|  | 4a29ab0d0a | ||
|  | 0165bcb58e | ||
|  | 349d75e483 | ||
|  | e51475703a | ||
|  | 1feddf4ba6 | ||
|  | 600d7ddc2e | ||
|  | e504260f3d | ||
|  | 5e4bea8f20 | ||
|  | 6ebf9f15b7 | ||
|  | 1d7aa673a4 | ||
|  | b9104f3072 | ||
| b672717096 | |||
| 284ee194b1 | |||
|  | 0cd6b1858c | 
							
								
								
									
										12
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								TODO
									
									
									
									
									
								
							| @@ -3,19 +3,19 @@ TODO: | ||||
|  | ||||
| Large item work list: | ||||
|  | ||||
| 1)- BG/Q port and check | ||||
| 1)- BG/Q port and check ; Andrew says ok. | ||||
| 2)- Christoph's local basis expansion Lanczos | ||||
| 3)- Precision conversion and sort out localConvert      <-- partial | ||||
|  | ||||
|   - Consistent linear solver flop count/rate -- PARTIAL, time but no flop/s yet | ||||
| -- | ||||
| 3a)- RNG I/O in ILDG/SciDAC (minor) | ||||
| 3b)- Precision conversion and sort out localConvert      <-- partial/easy | ||||
| 3c)- Consistent linear solver flop count/rate -- PARTIAL, time but no flop/s yet | ||||
| 4)- Physical propagator interface | ||||
| 5)- Conserved currents | ||||
| 6)- Multigrid Wilson and DWF, compare to other Multigrid implementations | ||||
| 7)- HDCR resume | ||||
|  | ||||
| Recent DONE  | ||||
|  | ||||
| -- MultiRHS with spread out extra dim -- Go through filesystem with SciDAC I/O.  <--- DONE | ||||
| -- MultiRHS with spread out extra dim -- Go through filesystem with SciDAC I/O ; <-- DONE ; bmark cori | ||||
| -- Lanczos Remove DenseVector, DenseMatrix; Use Eigen instead. <-- DONE | ||||
| -- GaugeFix into central location                      <-- DONE | ||||
| -- Scidac and Ildg metadata handling                   <-- DONE | ||||
|   | ||||
| @@ -701,12 +701,14 @@ int main (int argc, char ** argv) | ||||
|   if ( do_su3 ) { | ||||
|     // empty for now | ||||
|   } | ||||
|  | ||||
| #if 1 | ||||
|   int sel=2; | ||||
|   std::vector<int> L_list({8,12,16,24}); | ||||
|  | ||||
|   //int sel=1; | ||||
|   //  std::vector<int> L_list({8,12}); | ||||
| #else | ||||
|   int sel=1; | ||||
|   std::vector<int> L_list({8,12}); | ||||
| #endif | ||||
|   int selm1=sel-1; | ||||
|   std::vector<double> robust_list; | ||||
|  | ||||
|   std::vector<double> wilson; | ||||
| @@ -785,7 +787,8 @@ int main (int argc, char ** argv) | ||||
|   std::cout<<GridLogMessage << "=================================================================================="<<std::endl; | ||||
|  | ||||
|   std::cout<<GridLogMessage << "=================================================================================="<<std::endl; | ||||
|   std::cout<<GridLogMessage << " Comparison point     result: "  << dwf4[sel]/NN << " Mflop/s per node"<<std::endl; | ||||
|   std::cout<<GridLogMessage << " Comparison point     result: "  << 0.5*(dwf4[sel]+dwf4[selm1])/NN << " Mflop/s per node"<<std::endl; | ||||
|   std::cout<<GridLogMessage << " Comparison point is 0.5*("<<dwf4[sel]/NN<<"+"<<dwf4[selm1]/NN << ") "<<std::endl; | ||||
|   std::cout<<std::setprecision(3); | ||||
|   std::cout<<GridLogMessage << " Comparison point robustness: "  << robust_list[sel] <<std::endl; | ||||
|   std::cout<<GridLogMessage << "=================================================================================="<<std::endl; | ||||
|   | ||||
| @@ -51,7 +51,13 @@ int main (int argc, char ** argv) | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|  | ||||
|   std::vector<int> latt4 = GridDefaultLatt(); | ||||
|   const int Ls=16; | ||||
|   int Ls=16; | ||||
|   for(int i=0;i<argc;i++) | ||||
|     if(std::string(argv[i]) == "-Ls"){ | ||||
|       std::stringstream ss(argv[i+1]); ss >> Ls; | ||||
|     } | ||||
|  | ||||
|  | ||||
|   GridCartesian         * UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()),GridDefaultMpi()); | ||||
|   GridRedBlackCartesian * UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian         * FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid); | ||||
|   | ||||
							
								
								
									
										190
									
								
								benchmarks/Benchmark_gparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								benchmarks/Benchmark_gparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| #include <Grid/Grid.h> | ||||
| #include <sstream> | ||||
| using namespace std; | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| template<class d> | ||||
| struct scal { | ||||
|   d internal; | ||||
| }; | ||||
|  | ||||
|   Gamma::Algebra Gmu [] = { | ||||
|     Gamma::Algebra::GammaX, | ||||
|     Gamma::Algebra::GammaY, | ||||
|     Gamma::Algebra::GammaZ, | ||||
|     Gamma::Algebra::GammaT | ||||
|   }; | ||||
|  | ||||
| typedef typename GparityDomainWallFermionF::FermionField GparityLatticeFermionF; | ||||
| typedef typename GparityDomainWallFermionD::FermionField GparityLatticeFermionD; | ||||
|  | ||||
|  | ||||
|  | ||||
| int main (int argc, char ** argv) | ||||
| { | ||||
|   Grid_init(&argc,&argv); | ||||
|  | ||||
|   int Ls=16; | ||||
|   for(int i=0;i<argc;i++) | ||||
|     if(std::string(argv[i]) == "-Ls"){ | ||||
|       std::stringstream ss(argv[i+1]); ss >> Ls; | ||||
|     } | ||||
|  | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   std::cout<<GridLogMessage << "Ls = " << Ls << std::endl; | ||||
|  | ||||
|   std::vector<int> latt4 = GridDefaultLatt(); | ||||
|  | ||||
|   GridCartesian         * UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplexF::Nsimd()),GridDefaultMpi()); | ||||
|   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}); | ||||
|    | ||||
|   std::cout << GridLogMessage << "Initialising 4d RNG" << std::endl; | ||||
|   GridParallelRNG          RNG4(UGrid);  RNG4.SeedFixedIntegers(seeds4); | ||||
|   std::cout << GridLogMessage << "Initialising 5d RNG" << std::endl; | ||||
|   GridParallelRNG          RNG5(FGrid);  RNG5.SeedFixedIntegers(seeds5); | ||||
|   std::cout << GridLogMessage << "Initialised RNGs" << std::endl; | ||||
|  | ||||
|   GparityLatticeFermionF src   (FGrid); random(RNG5,src); | ||||
|   RealD N2 = 1.0/::sqrt(norm2(src)); | ||||
|   src = src*N2; | ||||
|  | ||||
|   GparityLatticeFermionF result(FGrid); result=zero; | ||||
|   GparityLatticeFermionF    ref(FGrid);    ref=zero; | ||||
|   GparityLatticeFermionF    tmp(FGrid); | ||||
|   GparityLatticeFermionF    err(FGrid); | ||||
|  | ||||
|   std::cout << GridLogMessage << "Drawing gauge field" << std::endl; | ||||
|   LatticeGaugeFieldF Umu(UGrid);  | ||||
|   SU3::HotConfiguration(RNG4,Umu);  | ||||
|   std::cout << GridLogMessage << "Random gauge initialised " << std::endl; | ||||
|  | ||||
|   RealD mass=0.1; | ||||
|   RealD M5  =1.8; | ||||
|  | ||||
|   RealD NP = UGrid->_Nprocessors; | ||||
|   RealD NN = UGrid->NodeCount(); | ||||
|  | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "* Kernel options --dslash-generic, --dslash-unroll, --dslash-asm" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "* Benchmarking DomainWallFermion::Dhop                  "<<std::endl; | ||||
|   std::cout << GridLogMessage<< "* Vectorising space-time by "<<vComplexF::Nsimd()<<std::endl; | ||||
| #ifdef GRID_OMP | ||||
|   if ( WilsonKernelsStatic::Comms == WilsonKernelsStatic::CommsAndCompute ) std::cout << GridLogMessage<< "* Using Overlapped Comms/Compute" <<std::endl; | ||||
|   if ( WilsonKernelsStatic::Comms == WilsonKernelsStatic::CommsThenCompute) std::cout << GridLogMessage<< "* Using sequential comms compute" <<std::endl; | ||||
| #endif | ||||
|   if ( WilsonKernelsStatic::Opt == WilsonKernelsStatic::OptGeneric   ) std::cout << GridLogMessage<< "* Using GENERIC Nc WilsonKernels" <<std::endl; | ||||
|   if ( WilsonKernelsStatic::Opt == WilsonKernelsStatic::OptHandUnroll) std::cout << GridLogMessage<< "* Using Nc=3       WilsonKernels" <<std::endl; | ||||
|   if ( WilsonKernelsStatic::Opt == WilsonKernelsStatic::OptInlineAsm ) std::cout << GridLogMessage<< "* Using Asm Nc=3   WilsonKernels" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|  | ||||
|  | ||||
|  | ||||
|   std::cout << GridLogMessage<< "* SINGLE/SINGLE"<<std::endl; | ||||
|   GparityDomainWallFermionF Dw(Umu,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5); | ||||
|   int ncall =1000; | ||||
|   if (1) { | ||||
|     FGrid->Barrier(); | ||||
|     Dw.ZeroCounters(); | ||||
|     Dw.Dhop(src,result,0); | ||||
|     std::cout<<GridLogMessage<<"Called warmup"<<std::endl; | ||||
|     double t0=usecond(); | ||||
|     for(int i=0;i<ncall;i++){ | ||||
|       __SSC_START; | ||||
|       Dw.Dhop(src,result,0); | ||||
|       __SSC_STOP; | ||||
|     } | ||||
|     double t1=usecond(); | ||||
|     FGrid->Barrier(); | ||||
|      | ||||
|     double volume=Ls;  for(int mu=0;mu<Nd;mu++) volume=volume*latt4[mu]; | ||||
|     double flops=2*1344*volume*ncall; | ||||
|  | ||||
|     std::cout<<GridLogMessage << "Called Dw "<<ncall<<" times in "<<t1-t0<<" us"<<std::endl; | ||||
|     //    std::cout<<GridLogMessage << "norm result "<< norm2(result)<<std::endl; | ||||
|     //    std::cout<<GridLogMessage << "norm ref    "<< norm2(ref)<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s =   "<< flops/(t1-t0)<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s per rank =  "<< flops/(t1-t0)/NP<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s per node =  "<< flops/(t1-t0)/NN<<std::endl; | ||||
|     Dw.Report(); | ||||
|   } | ||||
|  | ||||
|   std::cout << GridLogMessage<< "* SINGLE/HALF"<<std::endl; | ||||
|   GparityDomainWallFermionFH DwH(Umu,*FGrid,*FrbGrid,*UGrid,*UrbGrid,mass,M5); | ||||
|   if (1) { | ||||
|     FGrid->Barrier(); | ||||
|     DwH.ZeroCounters(); | ||||
|     DwH.Dhop(src,result,0); | ||||
|     double t0=usecond(); | ||||
|     for(int i=0;i<ncall;i++){ | ||||
|       __SSC_START; | ||||
|       DwH.Dhop(src,result,0); | ||||
|       __SSC_STOP; | ||||
|     } | ||||
|     double t1=usecond(); | ||||
|     FGrid->Barrier(); | ||||
|      | ||||
|     double volume=Ls;  for(int mu=0;mu<Nd;mu++) volume=volume*latt4[mu]; | ||||
|     double flops=2*1344*volume*ncall; | ||||
|  | ||||
|     std::cout<<GridLogMessage << "Called half prec comms Dw "<<ncall<<" times in "<<t1-t0<<" us"<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s =   "<< flops/(t1-t0)<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s per rank =  "<< flops/(t1-t0)/NP<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s per node =  "<< flops/(t1-t0)/NN<<std::endl; | ||||
|     DwH.Report(); | ||||
|   } | ||||
|  | ||||
|   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); | ||||
|  | ||||
|    | ||||
|   std::cout << GridLogMessage<< "* DOUBLE/DOUBLE"<<std::endl; | ||||
|   GparityLatticeFermionD src_d(FGrid_d); | ||||
|   precisionChange(src_d,src); | ||||
|  | ||||
|   LatticeGaugeFieldD Umu_d(UGrid_d);  | ||||
|   precisionChange(Umu_d,Umu); | ||||
|  | ||||
|   GparityLatticeFermionD result_d(FGrid_d); | ||||
|  | ||||
|   GparityDomainWallFermionD DwD(Umu_d,*FGrid_d,*FrbGrid_d,*UGrid_d,*UrbGrid_d,mass,M5); | ||||
|   if (1) { | ||||
|     FGrid_d->Barrier(); | ||||
|     DwD.ZeroCounters(); | ||||
|     DwD.Dhop(src_d,result_d,0); | ||||
|     std::cout<<GridLogMessage<<"Called warmup"<<std::endl; | ||||
|     double t0=usecond(); | ||||
|     for(int i=0;i<ncall;i++){ | ||||
|       __SSC_START; | ||||
|       DwD.Dhop(src_d,result_d,0); | ||||
|       __SSC_STOP; | ||||
|     } | ||||
|     double t1=usecond(); | ||||
|     FGrid_d->Barrier(); | ||||
|      | ||||
|     double volume=Ls;  for(int mu=0;mu<Nd;mu++) volume=volume*latt4[mu]; | ||||
|     double flops=2*1344*volume*ncall; | ||||
|  | ||||
|     std::cout<<GridLogMessage << "Called Dw "<<ncall<<" times in "<<t1-t0<<" us"<<std::endl; | ||||
|     //    std::cout<<GridLogMessage << "norm result "<< norm2(result)<<std::endl; | ||||
|     //    std::cout<<GridLogMessage << "norm ref    "<< norm2(ref)<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s =   "<< flops/(t1-t0)<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s per rank =  "<< flops/(t1-t0)/NP<<std::endl; | ||||
|     std::cout<<GridLogMessage << "mflop/s per node =  "<< flops/(t1-t0)/NN<<std::endl; | ||||
|     DwD.Report(); | ||||
|   } | ||||
|  | ||||
|   Grid_finalize(); | ||||
| } | ||||
|  | ||||
| @@ -40,7 +40,7 @@ int main (int argc, char ** argv) | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); | ||||
|   GridCartesian               Grid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(&Grid); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   | ||||
| @@ -58,7 +58,7 @@ int main (int argc, char ** argv) | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); | ||||
|   GridCartesian               Grid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(&Grid); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   | ||||
| @@ -93,7 +93,7 @@ int main (int argc, char ** argv) | ||||
| 	  std::cout << latt_size.back() << "\t\t"; | ||||
|  | ||||
| 	  GridCartesian           Grid(latt_size,simd_layout,mpi_layout); | ||||
| 	  GridRedBlackCartesian RBGrid(latt_size,simd_layout,mpi_layout); | ||||
| 	  GridRedBlackCartesian RBGrid(&Grid); | ||||
|  | ||||
| 	  GridParallelRNG  pRNG(&Grid); pRNG.SeedFixedIntegers(seeds); | ||||
| 	  LatticeGaugeField Umu(&Grid); random(pRNG,Umu); | ||||
|   | ||||
| @@ -550,6 +550,7 @@ AC_CONFIG_FILES(tests/forces/Makefile) | ||||
| AC_CONFIG_FILES(tests/hadrons/Makefile) | ||||
| AC_CONFIG_FILES(tests/hmc/Makefile) | ||||
| AC_CONFIG_FILES(tests/solver/Makefile) | ||||
| AC_CONFIG_FILES(tests/lanczos/Makefile) | ||||
| AC_CONFIG_FILES(tests/smearing/Makefile) | ||||
| AC_CONFIG_FILES(tests/qdpxx/Makefile) | ||||
| AC_CONFIG_FILES(tests/testu01/Makefile) | ||||
|   | ||||
| @@ -37,6 +37,7 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #include <Grid/algorithms/approx/Chebyshev.h> | ||||
| #include <Grid/algorithms/approx/Remez.h> | ||||
| #include <Grid/algorithms/approx/MultiShiftFunction.h> | ||||
| #include <Grid/algorithms/approx/Forecast.h> | ||||
|  | ||||
| #include <Grid/algorithms/iterative/ConjugateGradient.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateResidual.h> | ||||
| @@ -44,30 +45,16 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| #include <Grid/algorithms/iterative/SchurRedBlack.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradientMultiShift.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h> | ||||
|  | ||||
| // Lanczos support | ||||
| //#include <Grid/algorithms/iterative/MatrixUtils.h> | ||||
| #include <Grid/algorithms/iterative/BlockConjugateGradient.h> | ||||
| #include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h> | ||||
| #include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h> | ||||
| #include <Grid/algorithms/CoarsenedMatrix.h> | ||||
| #include <Grid/algorithms/FFT.h> | ||||
|  | ||||
| // Eigen/lanczos | ||||
| // EigCg | ||||
| // MCR | ||||
| // Pcg | ||||
| // Multishift CG | ||||
| // Hdcg | ||||
| // GCR | ||||
| // etc.. | ||||
|  | ||||
| // integrator/Leapfrog | ||||
| // integrator/Omelyan | ||||
| // integrator/ForceGradient | ||||
|  | ||||
| // montecarlo/hmc | ||||
| // montecarlo/rhmc | ||||
| // montecarlo/metropolis | ||||
| // etc... | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -103,29 +103,32 @@ namespace Grid { | ||||
|     GridBase *CoarseGrid; | ||||
|     GridBase *FineGrid; | ||||
|     std::vector<Lattice<Fobj> > subspace; | ||||
|     int checkerboard; | ||||
|  | ||||
|     Aggregation(GridBase *_CoarseGrid,GridBase *_FineGrid) :  | ||||
|       CoarseGrid(_CoarseGrid), | ||||
|   Aggregation(GridBase *_CoarseGrid,GridBase *_FineGrid,int _checkerboard) :  | ||||
|     CoarseGrid(_CoarseGrid), | ||||
|       FineGrid(_FineGrid), | ||||
|       subspace(nbasis,_FineGrid) | ||||
|       subspace(nbasis,_FineGrid), | ||||
|       checkerboard(_checkerboard) | ||||
| 	{ | ||||
| 	}; | ||||
|    | ||||
|     void Orthogonalise(void){ | ||||
|       CoarseScalar InnerProd(CoarseGrid);  | ||||
|       std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl; | ||||
|       blockOrthogonalise(InnerProd,subspace); | ||||
|       std::cout << GridLogMessage <<" Gramm-Schmidt pass 2"<<std::endl; | ||||
|       blockOrthogonalise(InnerProd,subspace); | ||||
|       //      std::cout << GridLogMessage <<" Gramm-Schmidt checking orthogonality"<<std::endl; | ||||
|       //      CheckOrthogonal(); | ||||
|     }  | ||||
|     void CheckOrthogonal(void){ | ||||
|       CoarseVector iProj(CoarseGrid);  | ||||
|       CoarseVector eProj(CoarseGrid);  | ||||
|       Lattice<CComplex> pokey(CoarseGrid); | ||||
|  | ||||
|        | ||||
|       for(int i=0;i<nbasis;i++){ | ||||
| 	blockProject(iProj,subspace[i],subspace); | ||||
|  | ||||
| 	eProj=zero;  | ||||
| 	for(int ss=0;ss<CoarseGrid->oSites();ss++){ | ||||
| 	parallel_for(int ss=0;ss<CoarseGrid->oSites();ss++){ | ||||
| 	  eProj._odata[ss](i)=CComplex(1.0); | ||||
| 	} | ||||
| 	eProj=eProj - iProj; | ||||
| @@ -137,6 +140,7 @@ namespace Grid { | ||||
|       blockProject(CoarseVec,FineVec,subspace); | ||||
|     } | ||||
|     void PromoteFromSubspace(const CoarseVector &CoarseVec,FineField &FineVec){ | ||||
|       FineVec.checkerboard = subspace[0].checkerboard; | ||||
|       blockPromote(CoarseVec,FineVec,subspace); | ||||
|     } | ||||
|     void CreateSubspaceRandom(GridParallelRNG &RNG){ | ||||
| @@ -147,6 +151,7 @@ namespace Grid { | ||||
|       Orthogonalise(); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|     virtual void CreateSubspaceLanczos(GridParallelRNG  &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis)  | ||||
|     { | ||||
|       // Run a Lanczos with sloppy convergence | ||||
| @@ -195,7 +200,7 @@ namespace Grid { | ||||
| 	  std::cout << GridLogMessage <<"subspace["<<b<<"] = "<<norm2(subspace[b])<<std::endl; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     */ | ||||
|     virtual void CreateSubspace(GridParallelRNG  &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis) { | ||||
|  | ||||
|       RealD scale; | ||||
|   | ||||
| @@ -230,6 +230,7 @@ namespace Grid { | ||||
|       // Barrel shift and collect global pencil | ||||
|       std::vector<int> lcoor(Nd), gcoor(Nd); | ||||
|       result = source; | ||||
|       int pc = processor_coor[dim]; | ||||
|       for(int p=0;p<processors[dim];p++) { | ||||
|         PARALLEL_REGION | ||||
|         { | ||||
| @@ -240,7 +241,8 @@ namespace Grid { | ||||
|           for(int idx=0;idx<sgrid->lSites();idx++) { | ||||
|             sgrid->LocalIndexToLocalCoor(idx,cbuf); | ||||
|             peekLocalSite(s,result,cbuf); | ||||
|             cbuf[dim]+=p*L; | ||||
| 	    cbuf[dim]+=((pc+p) % processors[dim])*L; | ||||
| 	    //            cbuf[dim]+=p*L; | ||||
|             pokeLocalSite(s,pgbuf,cbuf); | ||||
|           } | ||||
|         } | ||||
| @@ -278,7 +280,6 @@ namespace Grid { | ||||
|       flops+= flops_call*NN; | ||||
|        | ||||
|       // writing out result | ||||
|       int pc = processor_coor[dim]; | ||||
|       PARALLEL_REGION | ||||
|       { | ||||
|         std::vector<int> clbuf(Nd), cgbuf(Nd); | ||||
|   | ||||
| @@ -162,15 +162,10 @@ namespace Grid { | ||||
| 	_Mat.M(in,out); | ||||
|       } | ||||
|       void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
| 	ComplexD dot; | ||||
|  | ||||
| 	_Mat.M(in,out); | ||||
| 	 | ||||
| 	dot= innerProduct(in,out); | ||||
| 	n1=real(dot); | ||||
|  | ||||
| 	dot = innerProduct(out,out); | ||||
| 	n2=real(dot); | ||||
| 	ComplexD dot= innerProduct(in,out); n1=real(dot); | ||||
| 	n2=norm2(out); | ||||
|       } | ||||
|       void HermOp(const Field &in, Field &out){ | ||||
| 	_Mat.M(in,out); | ||||
| @@ -192,10 +187,10 @@ namespace Grid { | ||||
| 	ni=Mpc(in,tmp); | ||||
| 	no=MpcDag(tmp,out); | ||||
|       } | ||||
|       void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
|       virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
| 	MpcDagMpc(in,out,n1,n2); | ||||
|       } | ||||
|       void HermOp(const Field &in, Field &out){ | ||||
|       virtual void HermOp(const Field &in, Field &out){ | ||||
| 	RealD n1,n2; | ||||
| 	HermOpAndNorm(in,out,n1,n2); | ||||
|       } | ||||
| @@ -212,7 +207,6 @@ namespace Grid { | ||||
|       void OpDir  (const Field &in, Field &out,int dir,int disp) { | ||||
| 	assert(0); | ||||
|       } | ||||
|  | ||||
|     }; | ||||
|     template<class Matrix,class Field> | ||||
|       class SchurDiagMooeeOperator :  public SchurOperatorBase<Field> { | ||||
| @@ -270,7 +264,6 @@ namespace Grid { | ||||
| 	return axpy_norm(out,-1.0,tmp,in); | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|     template<class Matrix,class Field> | ||||
|       class SchurDiagTwoOperator :  public SchurOperatorBase<Field> { | ||||
|     protected: | ||||
| @@ -299,6 +292,45 @@ namespace Grid { | ||||
| 	return axpy_norm(out,-1.0,tmp,in); | ||||
|       } | ||||
|     }; | ||||
|     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     // Left  handed Moo^-1 ; (Moo - Moe Mee^-1 Meo) psi = eta  -->  ( 1 - Moo^-1 Moe Mee^-1 Meo ) psi = Moo^-1 eta | ||||
|     // Right handed Moo^-1 ; (Moo - Moe Mee^-1 Meo) Moo^-1 Moo psi = eta  -->  ( 1 - Moe Mee^-1 Meo ) Moo^-1 phi=eta ; psi = Moo^-1 phi | ||||
|     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     template<class Matrix,class Field> using SchurDiagOneRH = SchurDiagTwoOperator<Matrix,Field> ; | ||||
|     template<class Matrix,class Field> using SchurDiagOneLH = SchurDiagOneOperator<Matrix,Field> ; | ||||
|     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     //  Staggered use | ||||
|     /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     template<class Matrix,class Field> | ||||
|       class SchurStaggeredOperator :  public SchurOperatorBase<Field> { | ||||
|     protected: | ||||
|       Matrix &_Mat; | ||||
|     public: | ||||
|       SchurStaggeredOperator (Matrix &Mat): _Mat(Mat){}; | ||||
|       virtual void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2){ | ||||
| 	n2 = Mpc(in,out); | ||||
| 	ComplexD dot= innerProduct(in,out); | ||||
| 	n1 = real(dot); | ||||
|       } | ||||
|       virtual void HermOp(const Field &in, Field &out){ | ||||
| 	Mpc(in,out); | ||||
|       } | ||||
|       virtual  RealD Mpc      (const Field &in, Field &out) { | ||||
| 	Field tmp(in._grid); | ||||
| 	_Mat.Meooe(in,tmp); | ||||
| 	_Mat.MooeeInv(tmp,out); | ||||
| 	_Mat.Meooe(out,tmp); | ||||
| 	_Mat.Mooee(in,out); | ||||
|         return axpy_norm(out,-1.0,tmp,out); | ||||
|       } | ||||
|       virtual  RealD MpcDag   (const Field &in, Field &out){ | ||||
| 	return Mpc(in,out); | ||||
|       } | ||||
|       virtual void MpcDagMpc(const Field &in, Field &out,RealD &ni,RealD &no) { | ||||
| 	assert(0);// Never need with staggered | ||||
|       } | ||||
|     }; | ||||
|     template<class Matrix,class Field> using SchurStagOperator = SchurStaggeredOperator<Matrix,Field>; | ||||
|  | ||||
|  | ||||
|     ///////////////////////////////////////////////////////////// | ||||
| @@ -314,6 +346,14 @@ namespace Grid { | ||||
|       virtual void operator() (const Field &in, Field &out) = 0; | ||||
|     }; | ||||
|  | ||||
|     template<class Field> class IdentityLinearFunction : public LinearFunction<Field> { | ||||
|     public: | ||||
|       void operator() (const Field &in, Field &out){ | ||||
| 	out = in; | ||||
|       }; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     ///////////////////////////////////////////////////////////// | ||||
|     // Base classes for Multishift solvers for operators | ||||
|     ///////////////////////////////////////////////////////////// | ||||
| @@ -336,6 +376,64 @@ namespace Grid { | ||||
|      }; | ||||
|     */ | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Hermitian operator Linear function and operator function | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     template<class Field> | ||||
|       class HermOpOperatorFunction : public OperatorFunction<Field> { | ||||
|       void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||
| 	Linop.HermOp(in,out); | ||||
|       }; | ||||
|     }; | ||||
|  | ||||
|     template<typename Field> | ||||
|       class PlainHermOp : public LinearFunction<Field> { | ||||
|     public: | ||||
|       LinearOperatorBase<Field> &_Linop; | ||||
|        | ||||
|       PlainHermOp(LinearOperatorBase<Field>& linop) : _Linop(linop)  | ||||
|       {} | ||||
|        | ||||
|       void operator()(const Field& in, Field& out) { | ||||
| 	_Linop.HermOp(in,out); | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|     template<typename Field> | ||||
|     class FunctionHermOp : public LinearFunction<Field> { | ||||
|     public: | ||||
|       OperatorFunction<Field>   & _poly; | ||||
|       LinearOperatorBase<Field> &_Linop; | ||||
|        | ||||
|       FunctionHermOp(OperatorFunction<Field> & poly,LinearOperatorBase<Field>& linop)  | ||||
| 	: _poly(poly), _Linop(linop) {}; | ||||
|        | ||||
|       void operator()(const Field& in, Field& out) { | ||||
| 	_poly(_Linop,in,out); | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|   template<class Field> | ||||
|   class Polynomial : public OperatorFunction<Field> { | ||||
|   private: | ||||
|     std::vector<RealD> Coeffs; | ||||
|   public: | ||||
|     Polynomial(std::vector<RealD> &_Coeffs) : Coeffs(_Coeffs) { }; | ||||
|  | ||||
|     // Implement the required interface | ||||
|     void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||
|  | ||||
|       Field AtoN(in._grid); | ||||
|       Field Mtmp(in._grid); | ||||
|       AtoN = in; | ||||
|       out = AtoN*Coeffs[0]; | ||||
|       for(int n=1;n<Coeffs.size();n++){ | ||||
| 	Mtmp = AtoN; | ||||
| 	Linop.HermOp(Mtmp,AtoN); | ||||
| 	out=out+AtoN*Coeffs[n]; | ||||
|       } | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Christoph Lehner <clehner@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 | ||||
| @@ -33,41 +34,12 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Simple general polynomial with user supplied coefficients | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   template<class Field> | ||||
|   class HermOpOperatorFunction : public OperatorFunction<Field> { | ||||
|     void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||
|       Linop.HermOp(in,out); | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
|   template<class Field> | ||||
|   class Polynomial : public OperatorFunction<Field> { | ||||
|   private: | ||||
|     std::vector<RealD> Coeffs; | ||||
|   public: | ||||
|     Polynomial(std::vector<RealD> &_Coeffs) : Coeffs(_Coeffs) { }; | ||||
|  | ||||
|     // Implement the required interface | ||||
|     void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||
|  | ||||
|       Field AtoN(in._grid); | ||||
|       Field Mtmp(in._grid); | ||||
|       AtoN = in; | ||||
|       out = AtoN*Coeffs[0]; | ||||
| //            std::cout <<"Poly in " <<norm2(in)<<" size "<< Coeffs.size()<<std::endl; | ||||
| //            std::cout <<"Coeffs[0]= "<<Coeffs[0]<< " 0 " <<norm2(out)<<std::endl; | ||||
|       for(int n=1;n<Coeffs.size();n++){ | ||||
| 	Mtmp = AtoN; | ||||
| 	Linop.HermOp(Mtmp,AtoN); | ||||
| 	out=out+AtoN*Coeffs[n]; | ||||
| //            std::cout <<"Coeffs "<<n<<"= "<< Coeffs[n]<< " 0 " <<std::endl; | ||||
| //		std::cout << n<<" " <<norm2(out)<<std::endl; | ||||
|       } | ||||
|     }; | ||||
|   }; | ||||
| struct ChebyParams : Serializable { | ||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(ChebyParams, | ||||
| 				  RealD, alpha,   | ||||
| 				  RealD, beta,    | ||||
| 				  int, Npoly); | ||||
| }; | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Generic Chebyshev approximations | ||||
| @@ -82,8 +54,10 @@ namespace Grid { | ||||
|  | ||||
|   public: | ||||
|     void csv(std::ostream &out){ | ||||
| 	RealD diff = hi-lo; | ||||
|       for (RealD x=lo-0.2*diff; x<hi+0.2*diff; x+=(hi-lo)/1000) { | ||||
|       RealD diff = hi-lo; | ||||
|       RealD delta = (hi-lo)*1.0e-9; | ||||
|       for (RealD x=lo; x<hi; x+=delta) { | ||||
| 	delta*=1.1; | ||||
| 	RealD f = approx(x); | ||||
| 	out<< x<<" "<<f<<std::endl; | ||||
|       } | ||||
| @@ -99,6 +73,7 @@ namespace Grid { | ||||
|     }; | ||||
|  | ||||
|     Chebyshev(){}; | ||||
|     Chebyshev(ChebyParams p){ Init(p.alpha,p.beta,p.Npoly);}; | ||||
|     Chebyshev(RealD _lo,RealD _hi,int _order, RealD (* func)(RealD) ) {Init(_lo,_hi,_order,func);}; | ||||
|     Chebyshev(RealD _lo,RealD _hi,int _order) {Init(_lo,_hi,_order);}; | ||||
|  | ||||
| @@ -193,6 +168,47 @@ namespace Grid { | ||||
|       return sum; | ||||
|     }; | ||||
|  | ||||
|     RealD approxD(RealD x) | ||||
|     { | ||||
|       RealD Un; | ||||
|       RealD Unm; | ||||
|       RealD Unp; | ||||
|        | ||||
|       RealD y=( x-0.5*(hi+lo))/(0.5*(hi-lo)); | ||||
|        | ||||
|       RealD U0=1; | ||||
|       RealD U1=2*y; | ||||
|        | ||||
|       RealD sum; | ||||
|       sum = Coeffs[1]*U0; | ||||
|       sum+= Coeffs[2]*U1*2.0; | ||||
|        | ||||
|       Un =U1; | ||||
|       Unm=U0; | ||||
|       for(int i=2;i<order-1;i++){ | ||||
| 	Unp=2*y*Un-Unm; | ||||
| 	Unm=Un; | ||||
| 	Un =Unp; | ||||
| 	sum+= Un*Coeffs[i+1]*(i+1.0); | ||||
|       } | ||||
|       return sum/(0.5*(hi-lo)); | ||||
|     }; | ||||
|      | ||||
|     RealD approxInv(RealD z, RealD x0, int maxiter, RealD resid) { | ||||
|       RealD x = x0; | ||||
|       RealD eps; | ||||
|        | ||||
|       int i; | ||||
|       for (i=0;i<maxiter;i++) { | ||||
| 	eps = approx(x) - z; | ||||
| 	if (fabs(eps / z) < resid) | ||||
| 	  return x; | ||||
| 	x = x - eps / approxD(x); | ||||
|       } | ||||
|        | ||||
|       return std::numeric_limits<double>::quiet_NaN(); | ||||
|     } | ||||
|      | ||||
|     // Implement the required interface | ||||
|     void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) { | ||||
|  | ||||
|   | ||||
							
								
								
									
										152
									
								
								lib/algorithms/approx/Forecast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								lib/algorithms/approx/Forecast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/algorithms/approx/Forecast.h | ||||
|  | ||||
| Copyright (C) 2015 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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 */ | ||||
|  | ||||
| #ifndef INCLUDED_FORECAST_H | ||||
| #define INCLUDED_FORECAST_H | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
|   // Abstract base class. | ||||
|   // Takes a matrix (Mat), a source (phi), and a vector of Fields (chi) | ||||
|   // and returns a forecasted solution to the system D*psi = phi (psi). | ||||
|   template<class Matrix, class Field> | ||||
|   class Forecast | ||||
|   { | ||||
|     public: | ||||
|       virtual Field operator()(Matrix &Mat, const Field& phi, const std::vector<Field>& chi) = 0; | ||||
|   }; | ||||
|  | ||||
|   // Implementation of Brower et al.'s chronological inverter (arXiv:hep-lat/9509012), | ||||
|   // used to forecast solutions across poles of the EOFA heatbath. | ||||
|   // | ||||
|   // Modified from CPS (cps_pp/src/util/dirac_op/d_op_base/comsrc/minresext.C) | ||||
|   template<class Matrix, class Field> | ||||
|   class ChronoForecast : public Forecast<Matrix,Field> | ||||
|   { | ||||
|     public: | ||||
|       Field operator()(Matrix &Mat, const Field& phi, const std::vector<Field>& prev_solns) | ||||
|       { | ||||
|         int degree = prev_solns.size(); | ||||
|         Field chi(phi); // forecasted solution | ||||
|  | ||||
|         // Trivial cases | ||||
|         if(degree == 0){ chi = zero; return chi; } | ||||
|         else if(degree == 1){ return prev_solns[0]; } | ||||
|  | ||||
|         RealD dot; | ||||
|         ComplexD xp; | ||||
|         Field r(phi); // residual | ||||
|         Field Mv(phi); | ||||
|         std::vector<Field> v(prev_solns); // orthonormalized previous solutions | ||||
|         std::vector<Field> MdagMv(degree,phi); | ||||
|  | ||||
|         // Array to hold the matrix elements | ||||
|         std::vector<std::vector<ComplexD>> G(degree, std::vector<ComplexD>(degree)); | ||||
|  | ||||
|         // Solution and source vectors | ||||
|         std::vector<ComplexD> a(degree); | ||||
|         std::vector<ComplexD> b(degree); | ||||
|  | ||||
|         // Orthonormalize the vector basis | ||||
|         for(int i=0; i<degree; i++){ | ||||
|           v[i] *= 1.0/std::sqrt(norm2(v[i])); | ||||
|           for(int j=i+1; j<degree; j++){ v[j] -= innerProduct(v[i],v[j]) * v[i]; } | ||||
|         } | ||||
|  | ||||
|         // Perform sparse matrix multiplication and construct rhs | ||||
|         for(int i=0; i<degree; i++){ | ||||
|           b[i] = innerProduct(v[i],phi); | ||||
|           Mat.M(v[i],Mv); | ||||
|           Mat.Mdag(Mv,MdagMv[i]); | ||||
|           G[i][i] = innerProduct(v[i],MdagMv[i]); | ||||
|         } | ||||
|  | ||||
|         // Construct the matrix | ||||
|         for(int j=0; j<degree; j++){ | ||||
|         for(int k=j+1; k<degree; k++){ | ||||
|           G[j][k] = innerProduct(v[j],MdagMv[k]); | ||||
|           G[k][j] = std::conj(G[j][k]); | ||||
|         }} | ||||
|  | ||||
|         // Gauss-Jordan elimination with partial pivoting | ||||
|         for(int i=0; i<degree; i++){ | ||||
|  | ||||
|           // Perform partial pivoting | ||||
|           int k = i; | ||||
|           for(int j=i+1; j<degree; j++){ if(std::abs(G[j][j]) > std::abs(G[k][k])){ k = j; } } | ||||
|           if(k != i){ | ||||
|             xp = b[k]; | ||||
|             b[k] = b[i]; | ||||
|             b[i] = xp; | ||||
|             for(int j=0; j<degree; j++){ | ||||
|               xp = G[k][j]; | ||||
|               G[k][j] = G[i][j]; | ||||
|               G[i][j] = xp; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           // Convert matrix to upper triangular form | ||||
|           for(int j=i+1; j<degree; j++){ | ||||
|             xp = G[j][i]/G[i][i]; | ||||
|             b[j] -= xp * b[i]; | ||||
|             for(int k=0; k<degree; k++){ G[j][k] -= xp*G[i][k]; } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         // Use Gaussian elimination to solve equations and calculate initial guess | ||||
|         chi = zero; | ||||
|         r = phi; | ||||
|         for(int i=degree-1; i>=0; i--){ | ||||
|           a[i] = 0.0; | ||||
|           for(int j=i+1; j<degree; j++){ a[i] += G[i][j] * a[j]; } | ||||
|           a[i] = (b[i]-a[i])/G[i][i]; | ||||
|           chi += a[i]*v[i]; | ||||
|           r -= a[i]*MdagMv[i]; | ||||
|         } | ||||
|  | ||||
|         RealD true_r(0.0); | ||||
|         ComplexD tmp; | ||||
|         for(int i=0; i<degree; i++){ | ||||
|           tmp = -b[i]; | ||||
|           for(int j=0; j<degree; j++){ tmp += G[i][j]*a[j]; } | ||||
|           tmp = std::conj(tmp)*tmp; | ||||
|           true_r += std::sqrt(tmp.real()); | ||||
|         } | ||||
|  | ||||
|         RealD error = std::sqrt(norm2(r)/norm2(phi)); | ||||
|         std::cout << GridLogMessage << "ChronoForecast: |res|/|src| = " << error << std::endl; | ||||
|  | ||||
|         return chi; | ||||
|       }; | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -87,15 +87,22 @@ void ThinQRfact (Eigen::MatrixXcd &m_rr, | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   sliceInnerProductMatrix(m_rr,R,R,Orthog); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Cholesky from Eigen | ||||
|   // There exists a ldlt that is documented as more stable | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   Eigen::MatrixXcd L    = m_rr.llt().matrixL();  | ||||
|   // Force manifest hermitian to avoid rounding related | ||||
|   m_rr = 0.5*(m_rr+m_rr.adjoint()); | ||||
|  | ||||
| #if 0 | ||||
|   std::cout << " Calling Cholesky  ldlt on m_rr "  << m_rr <<std::endl; | ||||
|   Eigen::MatrixXcd L_ldlt = m_rr.ldlt().matrixL();  | ||||
|   std::cout << " Called Cholesky  ldlt on m_rr "  << L_ldlt <<std::endl; | ||||
|   auto  D_ldlt = m_rr.ldlt().vectorD();  | ||||
|   std::cout << " Called Cholesky  ldlt on m_rr "  << D_ldlt <<std::endl; | ||||
| #endif | ||||
|  | ||||
|   //  std::cout << " Calling Cholesky  llt on m_rr "  <<std::endl; | ||||
|   Eigen::MatrixXcd L    = m_rr.llt().matrixL();  | ||||
|   //  std::cout << " Called Cholesky  llt on m_rr "  << L <<std::endl; | ||||
|   C    = L.adjoint(); | ||||
|   Cinv = C.inverse(); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Q = R C^{-1} | ||||
|   // | ||||
| @@ -103,7 +110,6 @@ void ThinQRfact (Eigen::MatrixXcd &m_rr, | ||||
|   // | ||||
|   // NB maddMatrix conventions are Right multiplication X[j] a[j,i] already | ||||
|   //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // FIXME:: make a sliceMulMatrix to avoid zero vector | ||||
|   sliceMulMatrix(Q,Cinv,R,Orthog); | ||||
| } | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   | ||||
| @@ -52,8 +52,8 @@ class ConjugateGradient : public OperatorFunction<Field> { | ||||
|         MaxIterations(maxit), | ||||
|         ErrorOnNoConverge(err_on_no_conv){}; | ||||
|  | ||||
|   void operator()(LinearOperatorBase<Field> &Linop, const Field &src, | ||||
|                   Field &psi) { | ||||
|   void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) { | ||||
|  | ||||
|     psi.checkerboard = src.checkerboard; | ||||
|     conformable(psi, src); | ||||
|  | ||||
| @@ -78,12 +78,12 @@ class ConjugateGradient : public OperatorFunction<Field> { | ||||
|     cp = a; | ||||
|     ssq = norm2(src); | ||||
|  | ||||
|     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradient: guess " << guess << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradient:   src " << ssq << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradient:    mp " << d << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradient:   mmp " << b << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradient:  cp,r " << cp << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradient:     p " << a << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient: guess " << guess << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:   src " << ssq << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:    mp " << d << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:   mmp " << b << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:  cp,r " << cp << std::endl; | ||||
|     std::cout << GridLogIterative << std::setprecision(8) << "ConjugateGradient:     p " << a << std::endl; | ||||
|  | ||||
|     RealD rsq = Tolerance * Tolerance * ssq; | ||||
|  | ||||
| @@ -92,7 +92,7 @@ class ConjugateGradient : public OperatorFunction<Field> { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     std::cout << GridLogIterative << std::setprecision(4) | ||||
|     std::cout << GridLogIterative << std::setprecision(8) | ||||
|               << "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl; | ||||
|  | ||||
|     GridStopWatch LinalgTimer; | ||||
|   | ||||
							
								
								
									
										256
									
								
								lib/algorithms/iterative/ConjugateGradientReliableUpdate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								lib/algorithms/iterative/ConjugateGradientReliableUpdate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,256 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
|  | ||||
|     Source file: ./lib/algorithms/iterative/ConjugateGradientReliableUpdate.h | ||||
|  | ||||
|     Copyright (C) 2015 | ||||
|  | ||||
| Author: Christopher Kelly <ckelly@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 */ | ||||
| #ifndef GRID_CONJUGATE_GRADIENT_RELIABLE_UPDATE_H | ||||
| #define GRID_CONJUGATE_GRADIENT_RELIABLE_UPDATE_H | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
|   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 ConjugateGradientReliableUpdate : public LinearFunction<FieldD> { | ||||
|   public: | ||||
|     bool ErrorOnNoConverge;  // throw an assert when the CG fails to converge. | ||||
|     // Defaults true. | ||||
|     RealD Tolerance; | ||||
|     Integer MaxIterations; | ||||
|     Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion | ||||
|     Integer ReliableUpdatesPerformed; | ||||
|  | ||||
|     bool DoFinalCleanup; //Final DP cleanup, defaults to true | ||||
|     Integer IterationsToCleanup; //Final DP cleanup step iterations | ||||
|      | ||||
|     LinearOperatorBase<FieldF> &Linop_f; | ||||
|     LinearOperatorBase<FieldD> &Linop_d; | ||||
|     GridBase* SinglePrecGrid; | ||||
|     RealD Delta; //reliable update parameter | ||||
|  | ||||
|     //Optional ability to switch to a different linear operator once the tolerance reaches a certain point. Useful for single/half -> single/single | ||||
|     LinearOperatorBase<FieldF> *Linop_fallback; | ||||
|     RealD fallback_transition_tol; | ||||
|  | ||||
|      | ||||
|     ConjugateGradientReliableUpdate(RealD tol, Integer maxit, RealD _delta, GridBase* _sp_grid, LinearOperatorBase<FieldF> &_Linop_f, LinearOperatorBase<FieldD> &_Linop_d, bool err_on_no_conv = true) | ||||
|       : Tolerance(tol), | ||||
|         MaxIterations(maxit), | ||||
| 	Delta(_delta), | ||||
| 	Linop_f(_Linop_f), | ||||
| 	Linop_d(_Linop_d), | ||||
| 	SinglePrecGrid(_sp_grid), | ||||
|         ErrorOnNoConverge(err_on_no_conv), | ||||
| 	DoFinalCleanup(true), | ||||
| 	Linop_fallback(NULL) | ||||
|     {}; | ||||
|  | ||||
|     void setFallbackLinop(LinearOperatorBase<FieldF> &_Linop_fallback, const RealD _fallback_transition_tol){ | ||||
|       Linop_fallback = &_Linop_fallback; | ||||
|       fallback_transition_tol = _fallback_transition_tol;       | ||||
|     } | ||||
|      | ||||
|     void operator()(const FieldD &src, FieldD &psi) { | ||||
|       LinearOperatorBase<FieldF> *Linop_f_use = &Linop_f; | ||||
|       bool using_fallback = false; | ||||
|        | ||||
|       psi.checkerboard = src.checkerboard; | ||||
|       conformable(psi, src); | ||||
|  | ||||
|       RealD cp, c, a, d, b, ssq, qq, b_pred; | ||||
|  | ||||
|       FieldD p(src); | ||||
|       FieldD mmp(src); | ||||
|       FieldD r(src); | ||||
|  | ||||
|       // Initial residual computation & set up | ||||
|       RealD guess = norm2(psi); | ||||
|       assert(std::isnan(guess) == 0); | ||||
|      | ||||
|       Linop_d.HermOpAndNorm(psi, mmp, d, b); | ||||
|      | ||||
|       r = src - mmp; | ||||
|       p = r; | ||||
|  | ||||
|       a = norm2(p); | ||||
|       cp = a; | ||||
|       ssq = norm2(src); | ||||
|  | ||||
|       std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate: guess " << guess << std::endl; | ||||
|       std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:   src " << ssq << std::endl; | ||||
|       std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:    mp " << d << std::endl; | ||||
|       std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:   mmp " << b << std::endl; | ||||
|       std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:  cp,r " << cp << std::endl; | ||||
|       std::cout << GridLogIterative << std::setprecision(4) << "ConjugateGradientReliableUpdate:     p " << a << std::endl; | ||||
|  | ||||
|       RealD rsq = Tolerance * Tolerance * ssq; | ||||
|  | ||||
|       // Check if guess is really REALLY good :) | ||||
|       if (cp <= rsq) { | ||||
| 	std::cout << GridLogMessage << "ConjugateGradientReliableUpdate guess was REALLY good\n"; | ||||
| 	std::cout << GridLogMessage << "\tComputed residual " << sqrt(cp / ssq)<<std::endl; | ||||
| 	return; | ||||
|       } | ||||
|  | ||||
|       //Single prec initialization | ||||
|       FieldF r_f(SinglePrecGrid); | ||||
|       r_f.checkerboard = r.checkerboard; | ||||
|       precisionChange(r_f, r); | ||||
|  | ||||
|       FieldF psi_f(r_f); | ||||
|       psi_f = zero; | ||||
|  | ||||
|       FieldF p_f(r_f); | ||||
|       FieldF mmp_f(r_f); | ||||
|  | ||||
|       RealD MaxResidSinceLastRelUp = cp; //initial residual     | ||||
|      | ||||
|       std::cout << GridLogIterative << std::setprecision(4) | ||||
| 		<< "ConjugateGradient: k=0 residual " << cp << " target " << rsq << std::endl; | ||||
|  | ||||
|       GridStopWatch LinalgTimer; | ||||
|       GridStopWatch MatrixTimer; | ||||
|       GridStopWatch SolverTimer; | ||||
|  | ||||
|       SolverTimer.Start(); | ||||
|       int k = 0; | ||||
|       int l = 0; | ||||
|      | ||||
|       for (k = 1; k <= MaxIterations; k++) { | ||||
| 	c = cp; | ||||
|  | ||||
| 	MatrixTimer.Start(); | ||||
| 	Linop_f_use->HermOpAndNorm(p_f, mmp_f, d, qq); | ||||
| 	MatrixTimer.Stop(); | ||||
|  | ||||
| 	LinalgTimer.Start(); | ||||
|  | ||||
| 	a = c / d; | ||||
| 	b_pred = a * (a * qq - d) / c; | ||||
|  | ||||
| 	cp = axpy_norm(r_f, -a, mmp_f, r_f); | ||||
| 	b = cp / c; | ||||
|  | ||||
| 	// Fuse these loops ; should be really easy | ||||
| 	psi_f = a * p_f + psi_f; | ||||
| 	//p_f = p_f * b + r_f; | ||||
|  | ||||
| 	LinalgTimer.Stop(); | ||||
|  | ||||
| 	std::cout << GridLogIterative << "ConjugateGradientReliableUpdate: Iteration " << k | ||||
| 		  << " residual " << cp << " target " << rsq << std::endl; | ||||
| 	std::cout << GridLogDebug << "a = "<< a << " b_pred = "<< b_pred << "  b = "<< b << std::endl; | ||||
| 	std::cout << GridLogDebug << "qq = "<< qq << " d = "<< d << "  c = "<< c << std::endl; | ||||
|  | ||||
| 	if(cp > MaxResidSinceLastRelUp){ | ||||
| 	  std::cout << GridLogIterative << "ConjugateGradientReliableUpdate: updating MaxResidSinceLastRelUp : " << MaxResidSinceLastRelUp << " -> " << cp << std::endl; | ||||
| 	  MaxResidSinceLastRelUp = cp; | ||||
| 	} | ||||
| 	   | ||||
| 	// Stopping condition | ||||
| 	if (cp <= rsq) { | ||||
| 	  //Although not written in the paper, I assume that I have to add on the final solution | ||||
| 	  precisionChange(mmp, psi_f); | ||||
| 	  psi = psi + mmp; | ||||
| 	 | ||||
| 	 | ||||
| 	  SolverTimer.Stop(); | ||||
| 	  Linop_d.HermOpAndNorm(psi, mmp, d, qq); | ||||
| 	  p = mmp - src; | ||||
|  | ||||
| 	  RealD srcnorm = sqrt(norm2(src)); | ||||
| 	  RealD resnorm = sqrt(norm2(p)); | ||||
| 	  RealD true_residual = resnorm / srcnorm; | ||||
|  | ||||
| 	  std::cout << GridLogMessage << "ConjugateGradientReliableUpdate Converged on iteration " << k << " after " << l << " reliable updates" << std::endl; | ||||
| 	  std::cout << GridLogMessage << "\tComputed residual " << sqrt(cp / ssq)<<std::endl; | ||||
| 	  std::cout << GridLogMessage << "\tTrue residual " << true_residual<<std::endl; | ||||
| 	  std::cout << GridLogMessage << "\tTarget " << Tolerance << std::endl; | ||||
|  | ||||
| 	  std::cout << GridLogMessage << "Time breakdown "<<std::endl; | ||||
| 	  std::cout << GridLogMessage << "\tElapsed    " << SolverTimer.Elapsed() <<std::endl; | ||||
| 	  std::cout << GridLogMessage << "\tMatrix     " << MatrixTimer.Elapsed() <<std::endl; | ||||
| 	  std::cout << GridLogMessage << "\tLinalg     " << LinalgTimer.Elapsed() <<std::endl; | ||||
|  | ||||
| 	  IterationsToComplete = k;	 | ||||
| 	  ReliableUpdatesPerformed = l; | ||||
| 	   | ||||
| 	  if(DoFinalCleanup){ | ||||
| 	    //Do a final CG to cleanup | ||||
| 	    std::cout << GridLogMessage << "ConjugateGradientReliableUpdate performing final cleanup.\n"; | ||||
| 	    ConjugateGradient<FieldD> CG(Tolerance,MaxIterations); | ||||
| 	    CG.ErrorOnNoConverge = ErrorOnNoConverge; | ||||
| 	    CG(Linop_d,src,psi); | ||||
| 	    IterationsToCleanup = CG.IterationsToComplete; | ||||
| 	  } | ||||
| 	  else if (ErrorOnNoConverge) assert(true_residual / Tolerance < 10000.0); | ||||
|  | ||||
| 	  std::cout << GridLogMessage << "ConjugateGradientReliableUpdate complete.\n"; | ||||
| 	  return; | ||||
| 	} | ||||
| 	else if(cp < Delta * MaxResidSinceLastRelUp) { //reliable update | ||||
| 	  std::cout << GridLogMessage << "ConjugateGradientReliableUpdate " | ||||
| 		    << cp << "(residual) < " << Delta << "(Delta) * " << MaxResidSinceLastRelUp << "(MaxResidSinceLastRelUp) on iteration " << k << " : performing reliable update\n"; | ||||
| 	  precisionChange(mmp, psi_f); | ||||
| 	  psi = psi + mmp; | ||||
|  | ||||
| 	  Linop_d.HermOpAndNorm(psi, mmp, d, qq); | ||||
| 	  r = src - mmp; | ||||
|  | ||||
| 	  psi_f = zero; | ||||
| 	  precisionChange(r_f, r); | ||||
| 	  cp = norm2(r); | ||||
| 	  MaxResidSinceLastRelUp = cp; | ||||
|  | ||||
| 	  b = cp/c; | ||||
| 	   | ||||
| 	  std::cout << GridLogMessage << "ConjugateGradientReliableUpdate new residual " << cp << std::endl; | ||||
| 	   | ||||
| 	  l = l+1; | ||||
| 	} | ||||
|  | ||||
| 	p_f = p_f * b + r_f; //update search vector after reliable update appears to help convergence | ||||
|  | ||||
| 	if(!using_fallback && Linop_fallback != NULL && cp < fallback_transition_tol){ | ||||
| 	  std::cout << GridLogMessage << "ConjugateGradientReliableUpdate switching to fallback linear operator on iteration " << k << " at residual " << cp << std::endl; | ||||
| 	  Linop_f_use = Linop_fallback; | ||||
| 	  using_fallback = true; | ||||
| 	} | ||||
|  | ||||
| 	 | ||||
|       } | ||||
|       std::cout << GridLogMessage << "ConjugateGradientReliableUpdate did NOT converge" | ||||
| 		<< std::endl; | ||||
|        | ||||
|       if (ErrorOnNoConverge) assert(0); | ||||
|       IterationsToComplete = k; | ||||
|       ReliableUpdatesPerformed = l;       | ||||
|     }     | ||||
|   }; | ||||
|  | ||||
|  | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -7,8 +7,9 @@ | ||||
|     Copyright (C) 2015 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Chulwoo Jung | ||||
| Author: Guido Cossu | ||||
| Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Chulwoo Jung <chulwoo@bnl.gov> | ||||
| Author: Christoph Lehner <clehner@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 | ||||
| @@ -27,108 +28,269 @@ Author: Guido Cossu | ||||
|     See the full license in the file "LICENSE" in the top level distribution directory | ||||
|     *************************************************************************************/ | ||||
|     /*  END LEGAL */ | ||||
| #ifndef GRID_IRL_H | ||||
| #define GRID_IRL_H | ||||
| #ifndef GRID_BIRL_H | ||||
| #define GRID_BIRL_H | ||||
|  | ||||
| #include <string.h> //memset | ||||
| //#include <zlib.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| namespace Grid {  | ||||
|  | ||||
|   enum IRLdiagonalisation {  | ||||
|     IRLdiagonaliseWithDSTEGR, | ||||
|     IRLdiagonaliseWithQR, | ||||
|     IRLdiagonaliseWithEigen | ||||
|   }; | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Helper class for sorting the evalues AND evectors by Field | ||||
| // Use pointer swizzle on vectors | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|   //////////////////////////////////////////////////////// | ||||
|   // Move following 100 LOC to lattice/Lattice_basis.h | ||||
|   //////////////////////////////////////////////////////// | ||||
| template<class Field> | ||||
| class SortEigen { | ||||
|  private: | ||||
|   static bool less_lmd(RealD left,RealD right){ | ||||
|     return left > right; | ||||
|   }   | ||||
|   static bool less_pair(std::pair<RealD,Field const*>& left, | ||||
|                         std::pair<RealD,Field const*>& right){ | ||||
|     return left.first > (right.first); | ||||
| void basisOrthogonalize(std::vector<Field> &basis,Field &w,int k)  | ||||
| { | ||||
|   for(int j=0; j<k; ++j){ | ||||
|     auto ip = innerProduct(basis[j],w); | ||||
|     w = w - ip*basis[j]; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  public: | ||||
|   void push(std::vector<RealD>& lmd,std::vector<Field>& evec,int N) { | ||||
| template<class Field> | ||||
| void basisRotate(std::vector<Field> &basis,Eigen::MatrixXd& Qt,int j0, int j1, int k0,int k1,int Nm)  | ||||
| { | ||||
|   typedef typename Field::vector_object vobj; | ||||
|   GridBase* grid = basis[0]._grid; | ||||
|        | ||||
|     //////////////////////////////////////////////////////////////////////// | ||||
|     // PAB: FIXME: VERY VERY VERY wasteful: takes a copy of the entire vector set. | ||||
|     //    : The vector reorder should be done by pointer swizzle somehow | ||||
|     //////////////////////////////////////////////////////////////////////// | ||||
|     std::vector<Field> cpy(lmd.size(),evec[0]._grid); | ||||
|     for(int i=0;i<lmd.size();i++) cpy[i] = evec[i]; | ||||
|   parallel_region | ||||
|   { | ||||
|     std::vector < vobj > B(Nm); // Thread private | ||||
|          | ||||
|     std::vector<std::pair<RealD, Field const*> > emod(lmd.size());     | ||||
|     parallel_for_internal(int ss=0;ss < grid->oSites();ss++){ | ||||
|       for(int j=j0; j<j1; ++j) B[j]=0.; | ||||
|        | ||||
|     for(int i=0;i<lmd.size();++i)  emod[i] = std::pair<RealD,Field const*>(lmd[i],&cpy[i]); | ||||
|  | ||||
|     partial_sort(emod.begin(),emod.begin()+N,emod.end(),less_pair); | ||||
|  | ||||
|     typename std::vector<std::pair<RealD, Field const*> >::iterator it = emod.begin(); | ||||
|     for(int i=0;i<N;++i){ | ||||
|       lmd[i]=it->first; | ||||
|       evec[i]=*(it->second); | ||||
|       ++it; | ||||
|       for(int j=j0; j<j1; ++j){ | ||||
| 	for(int k=k0; k<k1; ++k){ | ||||
| 	  B[j] +=Qt(j,k) * basis[k]._odata[ss]; | ||||
| 	} | ||||
|       } | ||||
|       for(int j=j0; j<j1; ++j){ | ||||
| 	  basis[j]._odata[ss] = B[j]; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   void push(std::vector<RealD>& lmd,int N) { | ||||
|     std::partial_sort(lmd.begin(),lmd.begin()+N,lmd.end(),less_lmd); | ||||
| } | ||||
|  | ||||
| // Extract a single rotated vector | ||||
| template<class Field> | ||||
| void basisRotateJ(Field &result,std::vector<Field> &basis,Eigen::MatrixXd& Qt,int j, int k0,int k1,int Nm)  | ||||
| { | ||||
|   typedef typename Field::vector_object vobj; | ||||
|   GridBase* grid = basis[0]._grid; | ||||
|  | ||||
|   result.checkerboard = basis[0].checkerboard; | ||||
|   parallel_for(int ss=0;ss < grid->oSites();ss++){ | ||||
|     vobj B = zero; | ||||
|     for(int k=k0; k<k1; ++k){ | ||||
|       B +=Qt(j,k) * basis[k]._odata[ss]; | ||||
|     } | ||||
|     result._odata[ss] = B; | ||||
|   } | ||||
|   bool saturated(RealD lmd, RealD thrs) { | ||||
|     return fabs(lmd) > fabs(thrs); | ||||
| } | ||||
|  | ||||
| template<class Field> | ||||
| void basisReorderInPlace(std::vector<Field> &_v,std::vector<RealD>& sort_vals, std::vector<int>& idx)  | ||||
| { | ||||
|   int vlen = idx.size(); | ||||
|  | ||||
|   assert(vlen>=1); | ||||
|   assert(vlen<=sort_vals.size()); | ||||
|   assert(vlen<=_v.size()); | ||||
|  | ||||
|   for (size_t i=0;i<vlen;i++) { | ||||
|  | ||||
|     if (idx[i] != i) { | ||||
|  | ||||
|       ////////////////////////////////////// | ||||
|       // idx[i] is a table of desired sources giving a permutation. | ||||
|       // Swap v[i] with v[idx[i]]. | ||||
|       // Find  j>i for which _vnew[j] = _vold[i], | ||||
|       // track the move idx[j] => idx[i] | ||||
|       // track the move idx[i] => i | ||||
|       ////////////////////////////////////// | ||||
|       size_t j; | ||||
|       for (j=i;j<idx.size();j++) | ||||
| 	if (idx[j]==i) | ||||
| 	  break; | ||||
|  | ||||
|       assert(idx[i] > i);     assert(j!=idx.size());      assert(idx[j]==i); | ||||
|  | ||||
|       std::swap(_v[i]._odata,_v[idx[i]]._odata); // should use vector move constructor, no data copy | ||||
|       std::swap(sort_vals[i],sort_vals[idx[i]]); | ||||
|  | ||||
|       idx[j] = idx[i]; | ||||
|       idx[i] = i; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| } | ||||
|  | ||||
| inline std::vector<int> basisSortGetIndex(std::vector<RealD>& sort_vals)  | ||||
| { | ||||
|   std::vector<int> idx(sort_vals.size()); | ||||
|   std::iota(idx.begin(), idx.end(), 0); | ||||
|  | ||||
|   // sort indexes based on comparing values in v | ||||
|   std::sort(idx.begin(), idx.end(), [&sort_vals](int i1, int i2) { | ||||
|     return ::fabs(sort_vals[i1]) < ::fabs(sort_vals[i2]); | ||||
|   }); | ||||
|   return idx; | ||||
| } | ||||
|  | ||||
| template<class Field> | ||||
| void basisSortInPlace(std::vector<Field> & _v,std::vector<RealD>& sort_vals, bool reverse)  | ||||
| { | ||||
|   std::vector<int> idx = basisSortGetIndex(sort_vals); | ||||
|   if (reverse) | ||||
|     std::reverse(idx.begin(), idx.end()); | ||||
|    | ||||
|   basisReorderInPlace(_v,sort_vals,idx); | ||||
| } | ||||
|  | ||||
| // PAB: faster to compute the inner products first then fuse loops. | ||||
| // If performance critical can improve. | ||||
| template<class Field> | ||||
| void basisDeflate(const std::vector<Field> &_v,const std::vector<RealD>& eval,const Field& src_orig,Field& result) { | ||||
|   result = zero; | ||||
|   assert(_v.size()==eval.size()); | ||||
|   int N = (int)_v.size(); | ||||
|   for (int i=0;i<N;i++) { | ||||
|     Field& tmp = _v[i]; | ||||
|     axpy(result,TensorRemove(innerProduct(tmp,src_orig)) / eval[i],tmp,result); | ||||
|   } | ||||
| } | ||||
|  | ||||
| ///////////////////////////////////////////////////////////// | ||||
| // Implicitly restarted lanczos | ||||
| ///////////////////////////////////////////////////////////// | ||||
| template<class Field> class ImplicitlyRestartedLanczosTester  | ||||
| { | ||||
|  public: | ||||
|   virtual int TestConvergence(int j,RealD resid,Field &evec, RealD &eval,RealD evalMaxApprox); | ||||
|   virtual int ReconstructEval(int j,RealD resid,Field &evec, RealD &eval,RealD evalMaxApprox); | ||||
| }; | ||||
|  | ||||
| enum IRLdiagonalisation {  | ||||
|   IRLdiagonaliseWithDSTEGR, | ||||
|   IRLdiagonaliseWithQR, | ||||
|   IRLdiagonaliseWithEigen | ||||
| }; | ||||
|  | ||||
| template<class Field> class ImplicitlyRestartedLanczosHermOpTester  : public ImplicitlyRestartedLanczosTester<Field> | ||||
| { | ||||
|  public: | ||||
|   LinearFunction<Field>       &_HermOpTest; | ||||
|   ImplicitlyRestartedLanczosHermOpTester(LinearFunction<Field> &HermOpTest) : _HermOpTest(HermOpTest)  {  }; | ||||
|   int ReconstructEval(int j,RealD resid,Field &B, RealD &eval,RealD evalMaxApprox) | ||||
|   { | ||||
|     return TestConvergence(j,resid,B,eval,evalMaxApprox); | ||||
|   } | ||||
|   int TestConvergence(int j,RealD eresid,Field &B, RealD &eval,RealD evalMaxApprox) | ||||
|   { | ||||
|     Field v(B); | ||||
|     RealD eval_poly = eval; | ||||
|     // Apply operator | ||||
|     _HermOpTest(B,v); | ||||
|  | ||||
|     RealD vnum = real(innerProduct(B,v)); // HermOp. | ||||
|     RealD vden = norm2(B); | ||||
|     RealD vv0  = norm2(v); | ||||
|     eval   = vnum/vden; | ||||
|     v -= eval*B; | ||||
|  | ||||
|     RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0); | ||||
|  | ||||
|     std::cout.precision(13); | ||||
|     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||
| 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||
| 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | ||||
| 	     <<std::endl; | ||||
|  | ||||
|     int conv=0; | ||||
|     if( (vv<eresid*eresid) ) conv = 1; | ||||
|  | ||||
|     return conv; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template<class Field>  | ||||
| class ImplicitlyRestartedLanczos { | ||||
|  | ||||
| private:        | ||||
|  | ||||
|   int MaxIter;   // Max iterations | ||||
|   int Nstop;     // Number of evecs checked for convergence | ||||
|   int Nk;        // Number of converged sought | ||||
|   int Nm;        // Nm -- total number of vectors | ||||
|   RealD eresid; | ||||
|  private: | ||||
|   const RealD small = 1.0e-8; | ||||
|   int MaxIter; | ||||
|   int MinRestart; // Minimum number of restarts; only check for convergence after | ||||
|   int Nstop;   // Number of evecs checked for convergence | ||||
|   int Nk;      // Number of converged sought | ||||
|   //  int Np;      // Np -- Number of spare vecs in krylov space //  == Nm - Nk | ||||
|   int Nm;      // Nm -- total number of vectors | ||||
|   IRLdiagonalisation diagonalisation; | ||||
|   //////////////////////////////////// | ||||
|   // Embedded objects | ||||
|   //////////////////////////////////// | ||||
|            SortEigen<Field> _sort; | ||||
|   LinearOperatorBase<Field> &_Linop; | ||||
|     OperatorFunction<Field> &_poly; | ||||
|   int orth_period; | ||||
|      | ||||
|   RealD OrthoTime; | ||||
|   RealD eresid, betastp; | ||||
|   //////////////////////////////// | ||||
|   // Embedded objects | ||||
|   //////////////////////////////// | ||||
|   LinearFunction<Field>       &_HermOp; | ||||
|   LinearFunction<Field>       &_HermOpTest; | ||||
|   ImplicitlyRestartedLanczosTester<Field> &_Tester; | ||||
|   // Default tester provided (we need a ref to something in default case) | ||||
|   ImplicitlyRestartedLanczosHermOpTester<Field> SimpleTester; | ||||
|   ///////////////////////// | ||||
|   // Constructor | ||||
|   ///////////////////////// | ||||
|    | ||||
| public:        | ||||
|  ImplicitlyRestartedLanczos(LinearOperatorBase<Field> &Linop, // op | ||||
| 			    OperatorFunction<Field> & poly,   // polynomial | ||||
| 			    int _Nstop, // really sought vecs | ||||
| 			    int _Nk,    // sought vecs | ||||
| 			    int _Nm,    // total vecs | ||||
| 			    RealD _eresid, // resid in lmd deficit  | ||||
| 			    int _MaxIter,  // Max iterations | ||||
| 			    IRLdiagonalisation _diagonalisation= IRLdiagonaliseWithEigen ) : | ||||
|     _Linop(Linop),    _poly(poly), | ||||
|       Nstop(_Nstop), Nk(_Nk), Nm(_Nm), | ||||
|       eresid(_eresid),  MaxIter(_MaxIter), | ||||
|       diagonalisation(_diagonalisation) | ||||
|       { }; | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|   // PAB: | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|   // Too many options  & knobs. Do we really need orth_period | ||||
|   // What is the theoretical basis & guarantees of betastp ? | ||||
|   // Nstop=Nk viable? | ||||
|   // MinRestart avoidable with new convergence test? | ||||
|   // Could cut to HermOp, HermOpTest, Tester, Nk, Nm, resid, maxiter (+diagonalisation) | ||||
|   // HermOpTest could be eliminated if we dropped the Power method for max eval. | ||||
|   // -- also: The eval, eval2, eval2_copy stuff is still unnecessarily unclear | ||||
|   ////////////////////////////////////////////////////////////////// | ||||
|  ImplicitlyRestartedLanczos(LinearFunction<Field> & HermOp, | ||||
| 			    LinearFunction<Field> & HermOpTest, | ||||
| 			    ImplicitlyRestartedLanczosTester<Field> & Tester, | ||||
| 			    int _Nstop, // sought vecs | ||||
| 			    int _Nk, // sought vecs | ||||
| 			    int _Nm, // spare vecs | ||||
| 			    RealD _eresid, // resid in lmdue deficit  | ||||
| 			    int _MaxIter, // Max iterations | ||||
| 			    RealD _betastp=0.0, // if beta(k) < betastp: converged | ||||
| 			    int _MinRestart=1, int _orth_period = 1, | ||||
| 			    IRLdiagonalisation _diagonalisation= IRLdiagonaliseWithEigen) : | ||||
|     SimpleTester(HermOpTest), _HermOp(HermOp),      _HermOpTest(HermOpTest), _Tester(Tester), | ||||
|     Nstop(_Nstop)  ,      Nk(_Nk),      Nm(_Nm), | ||||
|     eresid(_eresid),      betastp(_betastp), | ||||
|     MaxIter(_MaxIter)  ,      MinRestart(_MinRestart), | ||||
|     orth_period(_orth_period), diagonalisation(_diagonalisation)  { }; | ||||
|  | ||||
|     ImplicitlyRestartedLanczos(LinearFunction<Field> & HermOp, | ||||
| 			       LinearFunction<Field> & HermOpTest, | ||||
| 			       int _Nstop, // sought vecs | ||||
| 			       int _Nk, // sought vecs | ||||
| 			       int _Nm, // spare vecs | ||||
| 			       RealD _eresid, // resid in lmdue deficit  | ||||
| 			       int _MaxIter, // Max iterations | ||||
| 			       RealD _betastp=0.0, // if beta(k) < betastp: converged | ||||
| 			       int _MinRestart=1, int _orth_period = 1, | ||||
| 			       IRLdiagonalisation _diagonalisation= IRLdiagonaliseWithEigen) : | ||||
|     SimpleTester(HermOpTest),  _HermOp(HermOp),      _HermOpTest(HermOpTest), _Tester(SimpleTester), | ||||
|     Nstop(_Nstop)  ,      Nk(_Nk),      Nm(_Nm), | ||||
|     eresid(_eresid),      betastp(_betastp), | ||||
|     MaxIter(_MaxIter)  ,      MinRestart(_MinRestart), | ||||
|     orth_period(_orth_period), diagonalisation(_diagonalisation)  { }; | ||||
|  | ||||
|   //////////////////////////////// | ||||
|   // Helpers | ||||
|   //////////////////////////////// | ||||
|   static RealD normalise(Field& v)  | ||||
|   template<typename T>  static RealD normalise(T& v)  | ||||
|   { | ||||
|     RealD nn = norm2(v); | ||||
|     nn = sqrt(nn); | ||||
| @@ -136,16 +298,12 @@ public: | ||||
|     return nn; | ||||
|   } | ||||
|  | ||||
|   void orthogonalize(Field& w, std::vector<Field>& evec, int k) | ||||
|   void orthogonalize(Field& w, std::vector<Field>& evec,int k) | ||||
|   { | ||||
|     typedef typename Field::scalar_type MyComplex; | ||||
|     MyComplex ip; | ||||
|      | ||||
|     for(int j=0; j<k; ++j){ | ||||
|       ip = innerProduct(evec[j],w);  | ||||
|       w = w - ip * evec[j]; | ||||
|     } | ||||
|     OrthoTime-=usecond()/1e6; | ||||
|     basisOrthogonalize(evec,w,k); | ||||
|     normalise(w); | ||||
|     OrthoTime+=usecond()/1e6; | ||||
|   } | ||||
|  | ||||
| /* Rudy Arthur's thesis pp.137 | ||||
| @@ -165,184 +323,234 @@ repeat | ||||
|   →AVK =VKHK +fKe†K † Extend to an M = K + P step factorization AVM = VMHM + fMeM | ||||
| until convergence | ||||
| */ | ||||
|   void calc(std::vector<RealD>& eval,  std::vector<Field>& evec, const Field& src, int& Nconv) | ||||
|   void calc(std::vector<RealD>& eval, std::vector<Field>& evec,  const Field& src, int& Nconv, bool reverse=true) | ||||
|   { | ||||
|     GridBase *grid = src._grid; | ||||
|     assert(grid == evec[0]._grid); | ||||
|      | ||||
|     GridBase *grid = evec[0]._grid; | ||||
|     assert(grid == src._grid); | ||||
|      | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogMessage <<" ImplicitlyRestartedLanczos::calc() starting iteration 0 /  "<< MaxIter<< std::endl; | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogMessage <<" -- seek   Nk    = " << Nk    <<" vectors"<< std::endl; | ||||
|     std::cout << GridLogMessage <<" -- accept Nstop = " << Nstop <<" vectors"<< std::endl; | ||||
|     std::cout << GridLogMessage <<" -- total  Nm    = " << Nm    <<" vectors"<< std::endl; | ||||
|     std::cout << GridLogMessage <<" -- size of eval = " << eval.size() << std::endl; | ||||
|     std::cout << GridLogMessage <<" -- size of evec = " << evec.size() << std::endl; | ||||
|     GridLogIRL.TimingMode(1); | ||||
|     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogIRL <<" ImplicitlyRestartedLanczos::calc() starting iteration 0 /  "<< MaxIter<< std::endl; | ||||
|     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogIRL <<" -- seek   Nk    = " << Nk    <<" vectors"<< std::endl; | ||||
|     std::cout << GridLogIRL <<" -- accept Nstop = " << Nstop <<" vectors"<< std::endl; | ||||
|     std::cout << GridLogIRL <<" -- total  Nm    = " << Nm    <<" vectors"<< std::endl; | ||||
|     std::cout << GridLogIRL <<" -- size of eval = " << eval.size() << std::endl; | ||||
|     std::cout << GridLogIRL <<" -- size of evec = " << evec.size() << std::endl; | ||||
|     if ( diagonalisation == IRLdiagonaliseWithDSTEGR ) { | ||||
|       std::cout << GridLogMessage << "Diagonalisation is DSTEGR "<<std::endl; | ||||
|       std::cout << GridLogIRL << "Diagonalisation is DSTEGR "<<std::endl; | ||||
|     } else if ( diagonalisation == IRLdiagonaliseWithQR ) {  | ||||
|       std::cout << GridLogMessage << "Diagonalisation is QR "<<std::endl; | ||||
|       std::cout << GridLogIRL << "Diagonalisation is QR "<<std::endl; | ||||
|     }  else if ( diagonalisation == IRLdiagonaliseWithEigen ) {  | ||||
|       std::cout << GridLogMessage << "Diagonalisation is Eigen "<<std::endl; | ||||
|       std::cout << GridLogIRL << "Diagonalisation is Eigen "<<std::endl; | ||||
|     } | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||
| 	 | ||||
|     assert(Nm == evec.size() && Nm == eval.size()); | ||||
|     assert(Nm <= evec.size() && Nm <= eval.size()); | ||||
|      | ||||
|     // quickly get an idea of the largest eigenvalue to more properly normalize the residuum | ||||
|     RealD evalMaxApprox = 0.0; | ||||
|     { | ||||
|       auto src_n = src; | ||||
|       auto tmp = src; | ||||
|       const int _MAX_ITER_IRL_MEVAPP_ = 50; | ||||
|       for (int i=0;i<_MAX_ITER_IRL_MEVAPP_;i++) { | ||||
| 	_HermOpTest(src_n,tmp); | ||||
| 	RealD vnum = real(innerProduct(src_n,tmp)); // HermOp. | ||||
| 	RealD vden = norm2(src_n); | ||||
| 	RealD na = vnum/vden; | ||||
| 	if (fabs(evalMaxApprox/na - 1.0) < 0.05) | ||||
| 	  i=_MAX_ITER_IRL_MEVAPP_; | ||||
| 	evalMaxApprox = na; | ||||
| 	std::cout << GridLogIRL << " Approximation of largest eigenvalue: " << evalMaxApprox << std::endl; | ||||
| 	src_n = tmp; | ||||
|       } | ||||
|     } | ||||
| 	 | ||||
|     std::vector<RealD> lme(Nm);   | ||||
|     std::vector<RealD> lme2(Nm); | ||||
|     std::vector<RealD> eval2(Nm); | ||||
|  | ||||
|     Eigen::MatrixXd    Qt = Eigen::MatrixXd::Zero(Nm,Nm); | ||||
|  | ||||
|     std::vector<int>   Iconv(Nm); | ||||
|     std::vector<Field>  B(Nm,grid); // waste of space replicating | ||||
|     std::vector<RealD> eval2_copy(Nm); | ||||
|     Eigen::MatrixXd Qt = Eigen::MatrixXd::Zero(Nm,Nm); | ||||
|  | ||||
|     Field f(grid); | ||||
|     Field v(grid); | ||||
|      | ||||
|     int k1 = 1; | ||||
|     int k2 = Nk; | ||||
|     RealD beta_k; | ||||
|  | ||||
|     Nconv = 0; | ||||
|    | ||||
|     RealD beta_k; | ||||
|    | ||||
|     // Set initial vector | ||||
|     evec[0] = src; | ||||
|     std::cout << GridLogMessage <<"norm2(src)= " << norm2(src)<<std::endl; | ||||
|      | ||||
|     normalise(evec[0]); | ||||
|     std::cout << GridLogMessage <<"norm2(evec[0])= " << norm2(evec[0]) <<std::endl; | ||||
| 	 | ||||
|     // Initial Nk steps | ||||
|     OrthoTime=0.; | ||||
|     for(int k=0; k<Nk; ++k) step(eval,lme,evec,f,Nm,k); | ||||
|     std::cout<<GridLogIRL <<"Initial "<< Nk <<"steps done "<<std::endl; | ||||
|     std::cout<<GridLogIRL <<"Initial steps:OrthoTime "<<OrthoTime<< "seconds"<<std::endl; | ||||
|  | ||||
|     ////////////////////////////////// | ||||
|     // Restarting loop begins | ||||
|     ////////////////////////////////// | ||||
|     int iter; | ||||
|     for(iter = 0; iter<MaxIter; ++iter){ | ||||
|        | ||||
|       OrthoTime=0.; | ||||
|  | ||||
|       std::cout<< GridLogMessage <<" **********************"<< std::endl; | ||||
|       std::cout<< GridLogMessage <<" Restart iteration = "<< iter << std::endl; | ||||
|       std::cout<< GridLogMessage <<" **********************"<< std::endl; | ||||
|  | ||||
|       std::cout<<GridLogIRL <<" running "<<Nm-Nk <<" steps: "<<std::endl; | ||||
|       for(int k=Nk; k<Nm; ++k) step(eval,lme,evec,f,Nm,k); | ||||
|        | ||||
|       f *= lme[Nm-1]; | ||||
|  | ||||
|       std::cout<<GridLogIRL <<" "<<Nm-Nk <<" steps done "<<std::endl; | ||||
|       std::cout<<GridLogIRL <<"Initial steps:OrthoTime "<<OrthoTime<< "seconds"<<std::endl; | ||||
| 	   | ||||
|       ////////////////////////////////// | ||||
|       // getting eigenvalues | ||||
|       ////////////////////////////////// | ||||
|       for(int k=0; k<Nm; ++k){ | ||||
| 	eval2[k] = eval[k+k1-1]; | ||||
| 	lme2[k] = lme[k+k1-1]; | ||||
|       } | ||||
|       Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||
|       diagonalize(eval2,lme2,Nm,Nm,Qt,grid); | ||||
|       std::cout<<GridLogIRL <<" diagonalized "<<std::endl; | ||||
|  | ||||
|       ////////////////////////////////// | ||||
|       // sorting | ||||
|       _sort.push(eval2,Nm); | ||||
|       ////////////////////////////////// | ||||
|       eval2_copy = eval2; | ||||
|       std::partial_sort(eval2.begin(),eval2.begin()+Nm,eval2.end(),std::greater<RealD>()); | ||||
|       std::cout<<GridLogIRL <<" evals sorted "<<std::endl; | ||||
|       const int chunk=8; | ||||
|       for(int io=0; io<k2;io+=chunk){ | ||||
| 	std::cout<<GridLogIRL << "eval "<< std::setw(3) << io ; | ||||
| 	for(int ii=0;ii<chunk;ii++){ | ||||
| 	  if ( (io+ii)<k2 ) | ||||
| 	    std::cout<< " "<< std::setw(12)<< eval2[io+ii]; | ||||
| 	} | ||||
| 	std::cout << std::endl; | ||||
|       } | ||||
|  | ||||
|       ////////////////////////////////// | ||||
|       // Implicitly shifted QR transformations | ||||
|       ////////////////////////////////// | ||||
|       Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||
|       for(int ip=k2; ip<Nm; ++ip){  | ||||
| 	// Eigen replacement for qr_decomp ??? | ||||
| 	qr_decomp(eval,lme,Nm,Nm,Qt,eval2[ip],k1,Nm); | ||||
| 	QR_decomp(eval,lme,Nm,Nm,Qt,eval2[ip],k1,Nm); | ||||
|       } | ||||
|       std::cout<<GridLogIRL <<"QR decomposed "<<std::endl; | ||||
|  | ||||
|       for(int i=0; i<(Nk+1); ++i) B[i] = 0.0; | ||||
|       assert(k2<Nm);      assert(k2<Nm);      assert(k1>0); | ||||
|  | ||||
|       for(int j=k1-1; j<k2+1; ++j){ | ||||
| 	for(int k=0; k<Nm; ++k){ | ||||
| 	  B[j].checkerboard = evec[k].checkerboard; | ||||
| 	  B[j] += Qt(j,k) * evec[k]; | ||||
| 	} | ||||
|       } | ||||
|       for(int j=k1-1; j<k2+1; ++j) evec[j] = B[j]; | ||||
|       basisRotate(evec,Qt,k1-1,k2+1,0,Nm,Nm); /// big constraint on the basis | ||||
|       std::cout<<GridLogIRL <<"basisRotated  by Qt"<<std::endl; | ||||
|        | ||||
|       //////////////////////////////////////////////////// | ||||
|       // Compressed vector f and beta(k2) | ||||
|       //////////////////////////////////////////////////// | ||||
|       f *= Qt(k2-1,Nm-1); | ||||
|       f += lme[k2-1] * evec[k2]; | ||||
|       beta_k = norm2(f); | ||||
|       beta_k = sqrt(beta_k); | ||||
|       std::cout<< GridLogMessage<<" beta(k) = "<<beta_k<<std::endl; | ||||
|       std::cout<<GridLogIRL<<" beta(k) = "<<beta_k<<std::endl; | ||||
| 	   | ||||
|       RealD betar = 1.0/beta_k; | ||||
|       evec[k2] = betar * f; | ||||
|       lme[k2-1] = beta_k; | ||||
| 	   | ||||
|       //////////////////////////////////////////////////// | ||||
|       // Convergence test | ||||
|       //////////////////////////////////////////////////// | ||||
|       for(int k=0; k<Nm; ++k){     | ||||
| 	eval2[k] = eval[k]; | ||||
| 	lme2[k] = lme[k]; | ||||
|       } | ||||
|       Qt = Eigen::MatrixXd::Identity(Nm,Nm); | ||||
|       diagonalize(eval2,lme2,Nk,Nm,Qt,grid); | ||||
|        | ||||
|       for(int k = 0; k<Nk; ++k) B[k]=0.0; | ||||
|        | ||||
|       for(int j = 0; j<Nk; ++j){ | ||||
| 	for(int k = 0; k<Nk; ++k){ | ||||
| 	  B[j].checkerboard = evec[k].checkerboard; | ||||
| 	  B[j] += Qt(j,k) * evec[k]; | ||||
| 	} | ||||
|       } | ||||
|       std::cout<<GridLogIRL <<" Diagonalized "<<std::endl; | ||||
| 	   | ||||
|       Nconv = 0; | ||||
|       for(int i=0; i<Nk; ++i){ | ||||
|       if (iter >= MinRestart) { | ||||
|  | ||||
| 	_Linop.HermOp(B[i],v); | ||||
| 	std::cout << GridLogIRL << "Test convergence: rotate subset of vectors to test convergence " << std::endl; | ||||
|  | ||||
| 	RealD vnum = real(innerProduct(B[i],v)); // HermOp. | ||||
| 	RealD vden = norm2(B[i]); | ||||
| 	eval2[i] = vnum/vden; | ||||
| 	v -= eval2[i]*B[i]; | ||||
| 	RealD vv = norm2(v); | ||||
| 	Field B(grid); B.checkerboard = evec[0].checkerboard; | ||||
|  | ||||
| 	std::cout.precision(13); | ||||
| 	std::cout << GridLogMessage << "[" << std::setw(3)<< std::setiosflags(std::ios_base::right) <<i<<"] "; | ||||
| 	std::cout << "eval = "<<std::setw(25)<< std::setiosflags(std::ios_base::left)<< eval2[i]; | ||||
| 	std::cout << " |H B[i] - eval[i]B[i]|^2 "<< std::setw(25)<< std::setiosflags(std::ios_base::right)<< vv<< std::endl; | ||||
| 	 | ||||
| 	// change the criteria as evals are supposed to be sorted, all evals smaller(larger) than Nstop should have converged | ||||
| 	if((vv<eresid*eresid) && (i == Nconv) ){ | ||||
| 	  Iconv[Nconv] = i; | ||||
| 	  ++Nconv; | ||||
| 	//  power of two search pattern;  not every evalue in eval2 is assessed. | ||||
| 	for(int jj = 1; jj<=Nstop; jj*=2){ | ||||
| 	  int j = Nstop-jj; | ||||
| 	  RealD e = eval2_copy[j]; // Discard the evalue | ||||
| 	  basisRotateJ(B,evec,Qt,j,0,Nk,Nm);	     | ||||
| 	  if( _Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) { | ||||
| 	    if ( j > Nconv ) { | ||||
| 	      Nconv=j+1; | ||||
| 	      jj=Nstop; // Terminate the scan | ||||
| 	    } | ||||
| 	  } | ||||
| 	} | ||||
| 	// Do evec[0] for good measure | ||||
| 	{  | ||||
| 	  int j=0; | ||||
| 	  RealD e = eval2_copy[0];  | ||||
| 	  basisRotateJ(B,evec,Qt,j,0,Nk,Nm);	     | ||||
| 	  _Tester.TestConvergence(j,eresid,B,e,evalMaxApprox); | ||||
| 	} | ||||
| 	// test if we converged, if so, terminate | ||||
| 	std::cout<<GridLogIRL<<" #modes converged: >= "<<Nconv<<"/"<<Nstop<<std::endl; | ||||
| 	//	if( Nconv>=Nstop || beta_k < betastp){ | ||||
| 	if( Nconv>=Nstop){ | ||||
| 	  goto converged; | ||||
| 	} | ||||
| 	   | ||||
|       }  // i-loop end | ||||
|       } else { | ||||
| 	std::cout << GridLogIRL << "iter < MinRestart: do not yet test for convergence\n"; | ||||
|       } // end of iter loop | ||||
|     } | ||||
|  | ||||
|       std::cout<< GridLogMessage <<" #modes converged: "<<Nconv<<std::endl; | ||||
|  | ||||
|       if( Nconv>=Nstop ){ | ||||
| 	goto converged; | ||||
|       } | ||||
|     } // end of iter loop | ||||
|      | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout<< GridLogError    <<" ImplicitlyRestartedLanczos::calc() NOT converged."; | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout<<GridLogError<<"\n NOT converged.\n"; | ||||
|     abort(); | ||||
| 	 | ||||
|   converged: | ||||
|     // Sorting | ||||
|     eval.resize(Nconv); | ||||
|     evec.resize(Nconv,grid); | ||||
|     for(int i=0; i<Nconv; ++i){ | ||||
|       eval[i] = eval2[Iconv[i]]; | ||||
|       evec[i] = B[Iconv[i]]; | ||||
|     } | ||||
|     _sort.push(eval,evec,Nconv); | ||||
|     { | ||||
|       Field B(grid); B.checkerboard = evec[0].checkerboard; | ||||
|       basisRotate(evec,Qt,0,Nk,0,Nk,Nm);	     | ||||
|       std::cout << GridLogIRL << " Rotated basis"<<std::endl; | ||||
|       Nconv=0; | ||||
|       ////////////////////////////////////////////////////////////////////// | ||||
|       // Full final convergence test; unconditionally applied | ||||
|       ////////////////////////////////////////////////////////////////////// | ||||
|       for(int j = 0; j<=Nk; j++){ | ||||
| 	B=evec[j]; | ||||
| 	if( _Tester.ReconstructEval(j,eresid,B,eval2[j],evalMaxApprox) ) { | ||||
| 	  Nconv++; | ||||
| 	} | ||||
|       } | ||||
|  | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogMessage << "ImplicitlyRestartedLanczos CONVERGED ; Summary :\n"; | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogMessage << " -- Iterations  = "<< iter   << "\n"; | ||||
|     std::cout << GridLogMessage << " -- beta(k)     = "<< beta_k << "\n"; | ||||
|     std::cout << GridLogMessage << " -- Nconv       = "<< Nconv  << "\n"; | ||||
|     std::cout << GridLogMessage <<"**************************************************************************"<< std::endl; | ||||
|       if ( Nconv < Nstop ) | ||||
| 	std::cout << GridLogIRL << "Nconv ("<<Nconv<<") < Nstop ("<<Nstop<<")"<<std::endl; | ||||
|  | ||||
|       eval=eval2; | ||||
|  | ||||
|       basisSortInPlace(evec,eval,reverse); | ||||
|        | ||||
|     } | ||||
|         | ||||
|     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogIRL << "ImplicitlyRestartedLanczos CONVERGED ; Summary :\n"; | ||||
|     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||
|     std::cout << GridLogIRL << " -- Iterations  = "<< iter   << "\n"; | ||||
|     std::cout << GridLogIRL << " -- beta(k)     = "<< beta_k << "\n"; | ||||
|     std::cout << GridLogIRL << " -- Nconv       = "<< Nconv  << "\n"; | ||||
|     std::cout << GridLogIRL <<"**************************************************************************"<< std::endl; | ||||
|   } | ||||
|  | ||||
| private: | ||||
|  private: | ||||
| /* Saad PP. 195 | ||||
| 1. Choose an initial vector v1 of 2-norm unity. Set β1 ≡ 0, v0 ≡ 0 | ||||
| 2. For k = 1,2,...,m Do: | ||||
| @@ -361,14 +569,18 @@ private: | ||||
|     const RealD tiny = 1.0e-20; | ||||
|     assert( k< Nm ); | ||||
|  | ||||
|     _poly(_Linop,evec[k],w);      // 3. wk:=Avk−βkv_{k−1} | ||||
|     GridStopWatch gsw_op,gsw_o; | ||||
|  | ||||
|     Field& evec_k = evec[k]; | ||||
|  | ||||
|     _HermOp(evec_k,w);    std::cout<<GridLogIRL << "Poly(HermOp)" <<std::endl; | ||||
|  | ||||
|     if(k>0) w -= lme[k-1] * evec[k-1]; | ||||
|  | ||||
|     ComplexD zalph = innerProduct(evec[k],w); // 4. αk:=(wk,vk) | ||||
|     ComplexD zalph = innerProduct(evec_k,w); // 4. αk:=(wk,vk) | ||||
|     RealD     alph = real(zalph); | ||||
|  | ||||
|     w = w - alph * evec[k];// 5. wk:=wk−αkvk | ||||
|     w = w - alph * evec_k;// 5. wk:=wk−αkvk | ||||
|  | ||||
|     RealD beta = normalise(w); // 6. βk+1 := ∥wk∥2. If βk+1 = 0 then Stop | ||||
|     // 7. vk+1 := wk/βk+1 | ||||
| @@ -376,10 +588,16 @@ private: | ||||
|     lmd[k] = alph; | ||||
|     lme[k] = beta; | ||||
|  | ||||
|     if ( k > 0 ) orthogonalize(w,evec,k); // orthonormalise | ||||
|     if ( k < Nm-1) evec[k+1] = w; | ||||
|     if (k>0 && k % orth_period == 0) { | ||||
|       orthogonalize(w,evec,k); // orthonormalise | ||||
|       std::cout<<GridLogIRL << "Orthogonalised " <<std::endl; | ||||
|     } | ||||
|  | ||||
|     if ( beta < tiny ) std::cout << GridLogMessage << " beta is tiny "<<beta<<std::endl; | ||||
|     if(k < Nm-1) evec[k+1] = w; | ||||
|  | ||||
|     std::cout<<GridLogIRL << "alpha[" << k << "] = " << zalph << " beta[" << k << "] = "<<beta<<std::endl; | ||||
|     if ( beta < tiny )  | ||||
|       std::cout<<GridLogIRL << " beta is tiny "<<beta<<std::endl; | ||||
|   } | ||||
|  | ||||
|   void diagonalize_Eigen(std::vector<RealD>& lmd, std::vector<RealD>& lme,  | ||||
| @@ -404,11 +622,11 @@ private: | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   /////////////////////////////////////////////////////////////////////////// | ||||
|   // File could end here if settle on Eigen ??? | ||||
|   /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   void qr_decomp(std::vector<RealD>& lmd,   // Nm  | ||||
|   /////////////////////////////////////////////////////////////////////////// | ||||
|   // File could end here if settle on Eigen ??? !!! | ||||
|   /////////////////////////////////////////////////////////////////////////// | ||||
|   void QR_decomp(std::vector<RealD>& lmd,   // Nm  | ||||
| 		 std::vector<RealD>& lme,   // Nm  | ||||
| 		 int Nk, int Nm,            // Nk, Nm | ||||
| 		 Eigen::MatrixXd& Qt,       // Nm x Nm matrix | ||||
| @@ -575,51 +793,50 @@ void diagonalize_lapack(std::vector<RealD>& lmd, | ||||
| #endif | ||||
| } | ||||
|  | ||||
|   void diagonalize_QR(std::vector<RealD>& lmd, std::vector<RealD>& lme,  | ||||
| 		      int Nk, int Nm,    | ||||
| 		      Eigen::MatrixXd & Qt, | ||||
| 		      GridBase *grid) | ||||
|   { | ||||
|     int Niter = 100*Nm; | ||||
|     int kmin = 1; | ||||
|     int kmax = Nk; | ||||
| void diagonalize_QR(std::vector<RealD>& lmd, std::vector<RealD>& lme,  | ||||
| 		    int Nk, int Nm,    | ||||
| 		    Eigen::MatrixXd & Qt, | ||||
| 		    GridBase *grid) | ||||
| { | ||||
|   int QRiter = 100*Nm; | ||||
|   int kmin = 1; | ||||
|   int kmax = Nk; | ||||
|    | ||||
|     // (this should be more sophisticated) | ||||
|     for(int iter=0; iter<Niter; ++iter){ | ||||
|   // (this should be more sophisticated) | ||||
|   for(int iter=0; iter<QRiter; ++iter){ | ||||
|      | ||||
|       // determination of 2x2 leading submatrix | ||||
|       RealD dsub = lmd[kmax-1]-lmd[kmax-2]; | ||||
|       RealD dd = sqrt(dsub*dsub + 4.0*lme[kmax-2]*lme[kmax-2]); | ||||
|       RealD Dsh = 0.5*(lmd[kmax-2]+lmd[kmax-1] +dd*(dsub/fabs(dsub))); | ||||
|       // (Dsh: shift) | ||||
|     // determination of 2x2 leading submatrix | ||||
|     RealD dsub = lmd[kmax-1]-lmd[kmax-2]; | ||||
|     RealD dd = sqrt(dsub*dsub + 4.0*lme[kmax-2]*lme[kmax-2]); | ||||
|     RealD Dsh = 0.5*(lmd[kmax-2]+lmd[kmax-1] +dd*(dsub/fabs(dsub))); | ||||
|     // (Dsh: shift) | ||||
|      | ||||
|       // transformation | ||||
|       qr_decomp(lmd,lme,Nk,Nm,Qt,Dsh,kmin,kmax); // Nk, Nm | ||||
|     // transformation | ||||
|     QR_decomp(lmd,lme,Nk,Nm,Qt,Dsh,kmin,kmax); // Nk, Nm | ||||
|      | ||||
|       // Convergence criterion (redef of kmin and kamx) | ||||
|       for(int j=kmax-1; j>= kmin; --j){ | ||||
| 	RealD dds = fabs(lmd[j-1])+fabs(lmd[j]); | ||||
| 	if(fabs(lme[j-1])+dds > dds){ | ||||
| 	  kmax = j+1; | ||||
| 	  goto continued; | ||||
| 	} | ||||
|       } | ||||
|       Niter = iter; | ||||
|       return; | ||||
|  | ||||
|     continued: | ||||
|       for(int j=0; j<kmax-1; ++j){ | ||||
| 	RealD dds = fabs(lmd[j])+fabs(lmd[j+1]); | ||||
| 	if(fabs(lme[j])+dds > dds){ | ||||
| 	  kmin = j+1; | ||||
| 	  break; | ||||
| 	} | ||||
|     // Convergence criterion (redef of kmin and kamx) | ||||
|     for(int j=kmax-1; j>= kmin; --j){ | ||||
|       RealD dds = fabs(lmd[j-1])+fabs(lmd[j]); | ||||
|       if(fabs(lme[j-1])+dds > dds){ | ||||
| 	kmax = j+1; | ||||
| 	goto continued; | ||||
|       } | ||||
|     } | ||||
|     std::cout << GridLogError << "[QL method] Error - Too many iteration: "<<Niter<<"\n"; | ||||
|     abort(); | ||||
|   } | ||||
|     QRiter = iter; | ||||
|     return; | ||||
|      | ||||
|  }; | ||||
|   continued: | ||||
|     for(int j=0; j<kmax-1; ++j){ | ||||
|       RealD dds = fabs(lmd[j])+fabs(lmd[j+1]); | ||||
|       if(fabs(lme[j])+dds > dds){ | ||||
| 	kmin = j+1; | ||||
| 	break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   std::cout << GridLogError << "[QL method] Error - Too many iteration: "<<QRiter<<"\n"; | ||||
|   abort(); | ||||
| } | ||||
| }; | ||||
| } | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										352
									
								
								lib/algorithms/iterative/LocalCoherenceLanczos.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								lib/algorithms/iterative/LocalCoherenceLanczos.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,352 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     Grid physics library, www.github.com/paboyle/Grid  | ||||
|  | ||||
|     Source file: ./lib/algorithms/iterative/LocalCoherenceLanczos.h | ||||
|  | ||||
|     Copyright (C) 2015 | ||||
|  | ||||
| Author: Christoph Lehner <clehner@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 */ | ||||
| #ifndef GRID_LOCAL_COHERENCE_IRL_H | ||||
| #define GRID_LOCAL_COHERENCE_IRL_H | ||||
| namespace Grid {  | ||||
| struct LanczosParams : Serializable { | ||||
|  public: | ||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParams, | ||||
| 				  ChebyParams, Cheby,/*Chebyshev*/ | ||||
| 				  int, Nstop,    /*Vecs in Lanczos must converge Nstop < Nk < Nm*/ | ||||
| 				  int, Nk,       /*Vecs in Lanczos seek converge*/ | ||||
| 				  int, Nm,       /*Total vecs in Lanczos include restart*/ | ||||
| 				  RealD, resid,  /*residual*/ | ||||
|  				  int, MaxIt,  | ||||
| 				  RealD, betastp,  /* ? */ | ||||
| 				  int, MinRes);    // Must restart | ||||
| }; | ||||
|  | ||||
| struct LocalCoherenceLanczosParams : Serializable { | ||||
|  public: | ||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(LocalCoherenceLanczosParams, | ||||
| 				  bool, doFine, | ||||
| 				  bool, doFineRead, | ||||
| 				  bool, doCoarse, | ||||
| 	       			  bool, doCoarseRead, | ||||
| 				  LanczosParams, FineParams, | ||||
| 				  LanczosParams, CoarseParams, | ||||
| 				  ChebyParams,   Smoother, | ||||
| 				  RealD        , coarse_relax_tol, | ||||
| 				  std::vector<int>, blockSize, | ||||
| 				  std::string, config, | ||||
| 				  std::vector < std::complex<double>  >, omega, | ||||
| 				  RealD, mass, | ||||
| 				  RealD, M5); | ||||
| }; | ||||
|  | ||||
| // Duplicate functionality; ProjectedFunctionHermOp could be used with the trivial function | ||||
| template<class Fobj,class CComplex,int nbasis> | ||||
| class ProjectedHermOp : public LinearFunction<Lattice<iVector<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; | ||||
|  | ||||
|   LinearOperatorBase<FineField> &_Linop; | ||||
|   Aggregation<Fobj,CComplex,nbasis> &_Aggregate; | ||||
|  | ||||
|   ProjectedHermOp(LinearOperatorBase<FineField>& linop,  Aggregation<Fobj,CComplex,nbasis> &aggregate) :  | ||||
|     _Linop(linop), | ||||
|     _Aggregate(aggregate)  {  }; | ||||
|  | ||||
|   void operator()(const CoarseField& in, CoarseField& out) { | ||||
|  | ||||
|     GridBase *FineGrid = _Aggregate.FineGrid; | ||||
|     FineField fin(FineGrid); | ||||
|     FineField fout(FineGrid); | ||||
|  | ||||
|     _Aggregate.PromoteFromSubspace(in,fin);    std::cout<<GridLogIRL<<"ProjectedHermop : Promote to fine"<<std::endl; | ||||
|     _Linop.HermOp(fin,fout);                   std::cout<<GridLogIRL<<"ProjectedHermop : HermOp (fine) "<<std::endl; | ||||
|     _Aggregate.ProjectToSubspace(out,fout);    std::cout<<GridLogIRL<<"ProjectedHermop : Project to coarse "<<std::endl; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template<class Fobj,class CComplex,int nbasis> | ||||
| class ProjectedFunctionHermOp : public LinearFunction<Lattice<iVector<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; | ||||
|  | ||||
|  | ||||
|   OperatorFunction<FineField>   & _poly; | ||||
|   LinearOperatorBase<FineField> &_Linop; | ||||
|   Aggregation<Fobj,CComplex,nbasis> &_Aggregate; | ||||
|  | ||||
|   ProjectedFunctionHermOp(OperatorFunction<FineField> & poly,LinearOperatorBase<FineField>& linop,  | ||||
| 			  Aggregation<Fobj,CComplex,nbasis> &aggregate) :  | ||||
|     _poly(poly), | ||||
|     _Linop(linop), | ||||
|     _Aggregate(aggregate)  {  }; | ||||
|  | ||||
|   void operator()(const CoarseField& in, CoarseField& out) { | ||||
|  | ||||
|     GridBase *FineGrid = _Aggregate.FineGrid; | ||||
|  | ||||
|     FineField fin(FineGrid) ;fin.checkerboard  =_Aggregate.checkerboard; | ||||
|     FineField fout(FineGrid);fout.checkerboard =_Aggregate.checkerboard; | ||||
|      | ||||
|     _Aggregate.PromoteFromSubspace(in,fin);    std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Promote to fine"<<std::endl; | ||||
|     _poly(_Linop,fin,fout);                    std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Poly "<<std::endl; | ||||
|     _Aggregate.ProjectToSubspace(out,fout);    std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Project to coarse "<<std::endl; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template<class Fobj,class CComplex,int nbasis> | ||||
| class ImplicitlyRestartedLanczosSmoothedTester  : public ImplicitlyRestartedLanczosTester<Lattice<iVector<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; | ||||
|  | ||||
|   LinearFunction<CoarseField> & _Poly; | ||||
|   OperatorFunction<FineField>   & _smoother; | ||||
|   LinearOperatorBase<FineField> &_Linop; | ||||
|   Aggregation<Fobj,CComplex,nbasis> &_Aggregate; | ||||
|   RealD                             _coarse_relax_tol; | ||||
|   ImplicitlyRestartedLanczosSmoothedTester(LinearFunction<CoarseField>   &Poly, | ||||
| 					   OperatorFunction<FineField>   &smoother, | ||||
| 					   LinearOperatorBase<FineField> &Linop, | ||||
| 					   Aggregation<Fobj,CComplex,nbasis> &Aggregate, | ||||
| 					   RealD coarse_relax_tol=5.0e3)  | ||||
|     : _smoother(smoother), _Linop(Linop),_Aggregate(Aggregate), _Poly(Poly), _coarse_relax_tol(coarse_relax_tol)  {    }; | ||||
|  | ||||
|   int TestConvergence(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) | ||||
|   { | ||||
|     CoarseField v(B); | ||||
|     RealD eval_poly = eval; | ||||
|     // Apply operator | ||||
|     _Poly(B,v); | ||||
|  | ||||
|     RealD vnum = real(innerProduct(B,v)); // HermOp. | ||||
|     RealD vden = norm2(B); | ||||
|     RealD vv0  = norm2(v); | ||||
|     eval   = vnum/vden; | ||||
|     v -= eval*B; | ||||
|  | ||||
|     RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0); | ||||
|  | ||||
|     std::cout.precision(13); | ||||
|     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||
| 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||
| 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | ||||
| 	     <<std::endl; | ||||
|  | ||||
|     int conv=0; | ||||
|     if( (vv<eresid*eresid) ) conv = 1; | ||||
|     return conv; | ||||
|   } | ||||
|   int ReconstructEval(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) | ||||
|   { | ||||
|     GridBase *FineGrid = _Aggregate.FineGrid; | ||||
|  | ||||
|     int checkerboard   = _Aggregate.checkerboard; | ||||
|  | ||||
|     FineField fB(FineGrid);fB.checkerboard =checkerboard; | ||||
|     FineField fv(FineGrid);fv.checkerboard =checkerboard; | ||||
|  | ||||
|     _Aggregate.PromoteFromSubspace(B,fv); | ||||
|     _smoother(_Linop,fv,fB);  | ||||
|  | ||||
|     RealD eval_poly = eval; | ||||
|     _Linop.HermOp(fB,fv); | ||||
|  | ||||
|     RealD vnum = real(innerProduct(fB,fv)); // HermOp. | ||||
|     RealD vden = norm2(fB); | ||||
|     RealD vv0  = norm2(fv); | ||||
|     eval   = vnum/vden; | ||||
|     fv -= eval*fB; | ||||
|     RealD vv = norm2(fv) / ::pow(evalMaxApprox,2.0); | ||||
|  | ||||
|     std::cout.precision(13); | ||||
|     std::cout<<GridLogIRL  << "[" << std::setw(3)<<j<<"] " | ||||
| 	     <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")" | ||||
| 	     <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv | ||||
| 	     <<std::endl; | ||||
|     if ( j > nbasis ) eresid = eresid*_coarse_relax_tol; | ||||
|     if( (vv<eresid*eresid) ) return 1; | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| //////////////////////////////////////////// | ||||
| // Make serializable Lanczos params | ||||
| //////////////////////////////////////////// | ||||
| template<class Fobj,class CComplex,int nbasis> | ||||
| class LocalCoherenceLanczos  | ||||
| { | ||||
| 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; | ||||
|  | ||||
| protected: | ||||
|   GridBase *_CoarseGrid; | ||||
|   GridBase *_FineGrid; | ||||
|   int _checkerboard; | ||||
|   LinearOperatorBase<FineField>                 & _FineOp; | ||||
|    | ||||
|   // FIXME replace Aggregation with vector of fine; the code reuse is too small for | ||||
|   // the hassle and complexity of cross coupling. | ||||
|   Aggregation<Fobj,CComplex,nbasis>               _Aggregate;   | ||||
|   std::vector<RealD>                              evals_fine; | ||||
|   std::vector<RealD>                              evals_coarse;  | ||||
|   std::vector<CoarseField>                        evec_coarse; | ||||
| public: | ||||
|   LocalCoherenceLanczos(GridBase *FineGrid, | ||||
| 		GridBase *CoarseGrid, | ||||
| 		LinearOperatorBase<FineField> &FineOp, | ||||
| 		int checkerboard) : | ||||
|     _CoarseGrid(CoarseGrid), | ||||
|     _FineGrid(FineGrid), | ||||
|     _Aggregate(CoarseGrid,FineGrid,checkerboard), | ||||
|     _FineOp(FineOp), | ||||
|     _checkerboard(checkerboard) | ||||
|   { | ||||
|     evals_fine.resize(0); | ||||
|     evals_coarse.resize(0); | ||||
|   }; | ||||
|   void Orthogonalise(void ) { _Aggregate.Orthogonalise(); } | ||||
|  | ||||
|   template<typename T>  static RealD normalise(T& v)  | ||||
|   { | ||||
|     RealD nn = norm2(v); | ||||
|     nn = ::sqrt(nn); | ||||
|     v = v * (1.0/nn); | ||||
|     return nn; | ||||
|   } | ||||
|  | ||||
|   void fakeFine(void) | ||||
|   { | ||||
|     int Nk = nbasis; | ||||
|     _Aggregate.subspace.resize(Nk,_FineGrid); | ||||
|     _Aggregate.subspace[0]=1.0; | ||||
|     _Aggregate.subspace[0].checkerboard=_checkerboard; | ||||
|     normalise(_Aggregate.subspace[0]); | ||||
|     PlainHermOp<FineField>    Op(_FineOp); | ||||
|     for(int k=1;k<Nk;k++){ | ||||
|       _Aggregate.subspace[k].checkerboard=_checkerboard; | ||||
|       Op(_Aggregate.subspace[k-1],_Aggregate.subspace[k]); | ||||
|       normalise(_Aggregate.subspace[k]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void testFine(RealD resid)  | ||||
|   { | ||||
|     assert(evals_fine.size() == nbasis); | ||||
|     assert(_Aggregate.subspace.size() == nbasis); | ||||
|     PlainHermOp<FineField>    Op(_FineOp); | ||||
|     ImplicitlyRestartedLanczosHermOpTester<FineField> SimpleTester(Op); | ||||
|     for(int k=0;k<nbasis;k++){ | ||||
|       assert(SimpleTester.ReconstructEval(k,resid,_Aggregate.subspace[k],evals_fine[k],1.0)==1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void testCoarse(RealD resid,ChebyParams cheby_smooth,RealD relax)  | ||||
|   { | ||||
|     assert(evals_fine.size() == nbasis); | ||||
|     assert(_Aggregate.subspace.size() == nbasis); | ||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL | ||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     Chebyshev<FineField>                          ChebySmooth(cheby_smooth); | ||||
|     ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (ChebySmooth,_FineOp,_Aggregate); | ||||
|     ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,_Aggregate,relax); | ||||
|  | ||||
|     for(int k=0;k<evec_coarse.size();k++){ | ||||
|       if ( k < nbasis ) {  | ||||
| 	assert(ChebySmoothTester.ReconstructEval(k,resid,evec_coarse[k],evals_coarse[k],1.0)==1); | ||||
|       } else {  | ||||
| 	assert(ChebySmoothTester.ReconstructEval(k,resid*relax,evec_coarse[k],evals_coarse[k],1.0)==1); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void calcFine(ChebyParams cheby_parms,int Nstop,int Nk,int Nm,RealD resid,  | ||||
| 		RealD MaxIt, RealD betastp, int MinRes) | ||||
|   { | ||||
|     assert(nbasis<=Nm); | ||||
|     Chebyshev<FineField>      Cheby(cheby_parms); | ||||
|     FunctionHermOp<FineField> ChebyOp(Cheby,_FineOp); | ||||
|     PlainHermOp<FineField>    Op(_FineOp); | ||||
|  | ||||
|     evals_fine.resize(Nm); | ||||
|     _Aggregate.subspace.resize(Nm,_FineGrid); | ||||
|  | ||||
|     ImplicitlyRestartedLanczos<FineField> IRL(ChebyOp,Op,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); | ||||
|  | ||||
|     FineField src(_FineGrid); src=1.0; src.checkerboard = _checkerboard; | ||||
|  | ||||
|     int Nconv; | ||||
|     IRL.calc(evals_fine,_Aggregate.subspace,src,Nconv,false); | ||||
|      | ||||
|     // Shrink down to number saved | ||||
|     assert(Nstop>=nbasis); | ||||
|     assert(Nconv>=nbasis); | ||||
|     evals_fine.resize(nbasis); | ||||
|     _Aggregate.subspace.resize(nbasis,_FineGrid); | ||||
|   } | ||||
|   void calcCoarse(ChebyParams cheby_op,ChebyParams cheby_smooth,RealD relax, | ||||
| 		  int Nstop, int Nk, int Nm,RealD resid,  | ||||
| 		  RealD MaxIt, RealD betastp, int MinRes) | ||||
|   { | ||||
|     Chebyshev<FineField>                          Cheby(cheby_op); | ||||
|     ProjectedHermOp<Fobj,CComplex,nbasis>         Op(_FineOp,_Aggregate); | ||||
|     ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (Cheby,_FineOp,_Aggregate); | ||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL | ||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     Chebyshev<FineField>                                           ChebySmooth(cheby_smooth); | ||||
|     ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,_Aggregate,relax); | ||||
|  | ||||
|     evals_coarse.resize(Nm); | ||||
|     evec_coarse.resize(Nm,_CoarseGrid); | ||||
|  | ||||
|     CoarseField src(_CoarseGrid);     src=1.0;  | ||||
|  | ||||
|     ImplicitlyRestartedLanczos<CoarseField> IRL(ChebyOp,ChebyOp,ChebySmoothTester,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); | ||||
|     int Nconv=0; | ||||
|     IRL.calc(evals_coarse,evec_coarse,src,Nconv,false); | ||||
|     assert(Nconv>=Nstop); | ||||
|     evals_coarse.resize(Nstop); | ||||
|     evec_coarse.resize (Nstop,_CoarseGrid); | ||||
|     for (int i=0;i<Nstop;i++){ | ||||
|       std::cout << i << " Coarse eval = " << evals_coarse[i]  << std::endl; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| } | ||||
| #endif | ||||
| @@ -53,16 +53,119 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
|    *     M psi = eta | ||||
|    *********************** | ||||
|    *Odd | ||||
|    * i)   (D_oo)^{\dag} D_oo psi_o = (D_oo)^dag L^{-1}  eta_o | ||||
|    * i)                 D_oo psi_o =  L^{-1}  eta_o | ||||
|    *                        eta_o' = (D_oo)^dag (eta_o - Moe Mee^{-1} eta_e) | ||||
|    * | ||||
|    * Wilson: | ||||
|    *      (D_oo)^{\dag} D_oo psi_o = (D_oo)^dag L^{-1}  eta_o | ||||
|    * Stag: | ||||
|    *      D_oo psi_o = L^{-1}  eta =    (eta_o - Moe Mee^{-1} eta_e) | ||||
|    * | ||||
|    * L^-1 eta_o= (1              0 ) (e | ||||
|    *             (-MoeMee^{-1}   1 )    | ||||
|    * | ||||
|    *Even | ||||
|    * ii)  Mee psi_e + Meo psi_o = src_e | ||||
|    * | ||||
|    *   => sol_e = M_ee^-1 * ( src_e - Meo sol_o )... | ||||
|    * | ||||
|    *  | ||||
|    * TODO: Other options: | ||||
|    *  | ||||
|    * a) change checkerboards for Schur e<->o | ||||
|    * | ||||
|    * Left precon by Moo^-1 | ||||
|    * b) Doo^{dag} M_oo^-dag Moo^-1 Doo psi_0 =  (D_oo)^dag M_oo^-dag Moo^-1 L^{-1}  eta_o | ||||
|    *                              eta_o'     = (D_oo)^dag  M_oo^-dag Moo^-1 (eta_o - Moe Mee^{-1} eta_e) | ||||
|    * | ||||
|    * Right precon by Moo^-1 | ||||
|    * c) M_oo^-dag Doo^{dag} Doo Moo^-1 phi_0 = M_oo^-dag (D_oo)^dag L^{-1}  eta_o | ||||
|    *                              eta_o'     = M_oo^-dag (D_oo)^dag (eta_o - Moe Mee^{-1} eta_e) | ||||
|    *                              psi_o = M_oo^-1 phi_o | ||||
|    * TODO: Deflation  | ||||
|    */ | ||||
| namespace Grid { | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Take a matrix and form a Red Black solver calling a Herm solver | ||||
|   // Use of RB info prevents making SchurRedBlackSolve conform to standard interface | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   template<class Field> class SchurRedBlackStaggeredSolve { | ||||
|   private: | ||||
|     OperatorFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackStaggeredSolve(OperatorFunction<Field> &HermitianRBSolver)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise=0; | ||||
|     }; | ||||
|  | ||||
|     template<class Matrix> | ||||
|       void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|  | ||||
|       // FIXME CGdiagonalMee not implemented virtual function | ||||
|       // FIXME use CBfactorise to control schur decomp | ||||
|       GridBase *grid = _Matrix.RedBlackGrid(); | ||||
|       GridBase *fgrid= _Matrix.Grid(); | ||||
|  | ||||
|       SchurStaggeredOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|  | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // src_o = (source_o - Moe MeeInv source_e) | ||||
|       ///////////////////////////////////////////////////// | ||||
|       _Matrix.MooeeInv(src_e,tmp);     assert(  tmp.checkerboard ==Even); | ||||
|       _Matrix.Meooe   (tmp,Mtmp);      assert( Mtmp.checkerboard ==Odd);      | ||||
|       tmp=src_o-Mtmp;                  assert(  tmp.checkerboard ==Odd);      | ||||
|  | ||||
|       src_o = tmp;     assert(src_o.checkerboard ==Odd); | ||||
|       //  _Matrix.Mooee(tmp,src_o); // Extra factor of "m" in source | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackStaggeredSolver calling the Mpc solver" <<std::endl; | ||||
|       _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // sol_e = M_ee^-1 * ( src_e - Meo sol_o )... | ||||
|       /////////////////////////////////////////////////// | ||||
|       _Matrix.Meooe(sol_o,tmp);        assert(  tmp.checkerboard   ==Even); | ||||
|       src_e = src_e-tmp;               assert(  src_e.checkerboard ==Even); | ||||
|       _Matrix.MooeeInv(src_e,sol_e);   assert(  sol_e.checkerboard ==Even); | ||||
|       | ||||
|       setCheckerboard(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       _Matrix.M(out,resid);  | ||||
|       resid = resid-in; | ||||
|       RealD ns = norm2(in); | ||||
|       RealD nr = norm2(resid); | ||||
|  | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackStaggered solver true unprec resid "<< std::sqrt(nr/ns) <<" nr "<< nr <<" ns "<<ns << std::endl; | ||||
|     }      | ||||
|   }; | ||||
|   template<class Field> using SchurRedBlackStagSolve = SchurRedBlackStaggeredSolve<Field>; | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Take a matrix and form a Red Black solver calling a Herm solver | ||||
|   // Use of RB info prevents making SchurRedBlackSolve conform to standard interface | ||||
| @@ -76,12 +179,10 @@ namespace Grid { | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackDiagMooeeSolve(OperatorFunction<Field> &HermitianRBSolver)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise=0; | ||||
|     }; | ||||
|  | ||||
|   SchurRedBlackDiagMooeeSolve(OperatorFunction<Field> &HermitianRBSolver,int cb=0)  :  _HermitianRBSolver(HermitianRBSolver)  | ||||
|   {  | ||||
|     CBfactorise=cb; | ||||
|   }; | ||||
|     template<class Matrix> | ||||
|       void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|  | ||||
| @@ -141,5 +242,166 @@ namespace Grid { | ||||
|     }      | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Take a matrix and form a Red Black solver calling a Herm solver | ||||
|   // Use of RB info prevents making SchurRedBlackSolve conform to standard interface | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   template<class Field> class SchurRedBlackDiagTwoSolve { | ||||
|   private: | ||||
|     OperatorFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackDiagTwoSolve(OperatorFunction<Field> &HermitianRBSolver)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise=0; | ||||
|     }; | ||||
|  | ||||
|     template<class Matrix> | ||||
|       void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|  | ||||
|       // FIXME CGdiagonalMee not implemented virtual function | ||||
|       // FIXME use CBfactorise to control schur decomp | ||||
|       GridBase *grid = _Matrix.RedBlackGrid(); | ||||
|       GridBase *fgrid= _Matrix.Grid(); | ||||
|  | ||||
|       SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|  | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // src_o = Mdag * (source_o - Moe MeeInv source_e) | ||||
|       ///////////////////////////////////////////////////// | ||||
|       _Matrix.MooeeInv(src_e,tmp);     assert(  tmp.checkerboard ==Even); | ||||
|       _Matrix.Meooe   (tmp,Mtmp);      assert( Mtmp.checkerboard ==Odd);      | ||||
|       tmp=src_o-Mtmp;                  assert(  tmp.checkerboard ==Odd);      | ||||
|  | ||||
|       // get the right MpcDag | ||||
|       _HermOpEO.MpcDag(tmp,src_o);     assert(src_o.checkerboard ==Odd);        | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlack solver calling the MpcDagMp solver" <<std::endl; | ||||
| //      _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
|       _HermitianRBSolver(_HermOpEO,src_o,tmp);  assert(tmp.checkerboard==Odd); | ||||
|       _Matrix.MooeeInv(tmp,sol_o);        assert(  sol_o.checkerboard   ==Odd); | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // sol_e = M_ee^-1 * ( src_e - Meo sol_o )... | ||||
|       /////////////////////////////////////////////////// | ||||
|       _Matrix.Meooe(sol_o,tmp);        assert(  tmp.checkerboard   ==Even); | ||||
|       src_e = src_e-tmp;               assert(  src_e.checkerboard ==Even); | ||||
|       _Matrix.MooeeInv(src_e,sol_e);   assert(  sol_e.checkerboard ==Even); | ||||
|       | ||||
|       setCheckerboard(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       _Matrix.M(out,resid);  | ||||
|       resid = resid-in; | ||||
|       RealD ns = norm2(in); | ||||
|       RealD nr = norm2(resid); | ||||
|  | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackDiagTwo solver true unprec resid "<< std::sqrt(nr/ns) <<" nr "<< nr <<" ns "<<ns << std::endl; | ||||
|     }      | ||||
|   }; | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Take a matrix and form a Red Black solver calling a Herm solver | ||||
|   // Use of RB info prevents making SchurRedBlackSolve conform to standard interface | ||||
|   /////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   template<class Field> class SchurRedBlackDiagTwoMixed { | ||||
|   private: | ||||
|     LinearFunction<Field> & _HermitianRBSolver; | ||||
|     int CBfactorise; | ||||
|   public: | ||||
|  | ||||
|     ///////////////////////////////////////////////////// | ||||
|     // Wrap the usual normal equations Schur trick | ||||
|     ///////////////////////////////////////////////////// | ||||
|   SchurRedBlackDiagTwoMixed(LinearFunction<Field> &HermitianRBSolver)  : | ||||
|      _HermitianRBSolver(HermitianRBSolver)  | ||||
|     {  | ||||
|       CBfactorise=0; | ||||
|     }; | ||||
|  | ||||
|     template<class Matrix> | ||||
|       void operator() (Matrix & _Matrix,const Field &in, Field &out){ | ||||
|  | ||||
|       // FIXME CGdiagonalMee not implemented virtual function | ||||
|       // FIXME use CBfactorise to control schur decomp | ||||
|       GridBase *grid = _Matrix.RedBlackGrid(); | ||||
|       GridBase *fgrid= _Matrix.Grid(); | ||||
|  | ||||
|       SchurDiagTwoOperator<Matrix,Field> _HermOpEO(_Matrix); | ||||
|   | ||||
|       Field src_e(grid); | ||||
|       Field src_o(grid); | ||||
|       Field sol_e(grid); | ||||
|       Field sol_o(grid); | ||||
|       Field   tmp(grid); | ||||
|       Field  Mtmp(grid); | ||||
|       Field resid(fgrid); | ||||
|  | ||||
|       pickCheckerboard(Even,src_e,in); | ||||
|       pickCheckerboard(Odd ,src_o,in); | ||||
|       pickCheckerboard(Even,sol_e,out); | ||||
|       pickCheckerboard(Odd ,sol_o,out); | ||||
|      | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // src_o = Mdag * (source_o - Moe MeeInv source_e) | ||||
|       ///////////////////////////////////////////////////// | ||||
|       _Matrix.MooeeInv(src_e,tmp);     assert(  tmp.checkerboard ==Even); | ||||
|       _Matrix.Meooe   (tmp,Mtmp);      assert( Mtmp.checkerboard ==Odd);      | ||||
|       tmp=src_o-Mtmp;                  assert(  tmp.checkerboard ==Odd);      | ||||
|  | ||||
|       // get the right MpcDag | ||||
|       _HermOpEO.MpcDag(tmp,src_o);     assert(src_o.checkerboard ==Odd);        | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       // Call the red-black solver | ||||
|       ////////////////////////////////////////////////////////////// | ||||
|       std::cout<<GridLogMessage << "SchurRedBlack solver calling the MpcDagMp solver" <<std::endl; | ||||
| //      _HermitianRBSolver(_HermOpEO,src_o,sol_o);  assert(sol_o.checkerboard==Odd); | ||||
| //      _HermitianRBSolver(_HermOpEO,src_o,tmp);  assert(tmp.checkerboard==Odd); | ||||
|       _HermitianRBSolver(src_o,tmp);  assert(tmp.checkerboard==Odd); | ||||
|       _Matrix.MooeeInv(tmp,sol_o);        assert(  sol_o.checkerboard   ==Odd); | ||||
|  | ||||
|       /////////////////////////////////////////////////// | ||||
|       // sol_e = M_ee^-1 * ( src_e - Meo sol_o )... | ||||
|       /////////////////////////////////////////////////// | ||||
|       _Matrix.Meooe(sol_o,tmp);        assert(  tmp.checkerboard   ==Even); | ||||
|       src_e = src_e-tmp;               assert(  src_e.checkerboard ==Even); | ||||
|       _Matrix.MooeeInv(src_e,sol_e);   assert(  sol_e.checkerboard ==Even); | ||||
|       | ||||
|       setCheckerboard(out,sol_e); assert(  sol_e.checkerboard ==Even); | ||||
|       setCheckerboard(out,sol_o); assert(  sol_o.checkerboard ==Odd ); | ||||
|  | ||||
|       // Verify the unprec residual | ||||
|       _Matrix.M(out,resid);  | ||||
|       resid = resid-in; | ||||
|       RealD ns = norm2(in); | ||||
|       RealD nr = norm2(resid); | ||||
|  | ||||
|       std::cout<<GridLogMessage << "SchurRedBlackDiagTwo solver true unprec resid "<< std::sqrt(nr/ns) <<" nr "<< nr <<" ns "<<ns << std::endl; | ||||
|     }      | ||||
|   }; | ||||
|  | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
|  | ||||
|  | ||||
|  | ||||
| #include <Grid/GridCore.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| namespace Grid { | ||||
|  | ||||
| @@ -63,4 +61,37 @@ void *PointerCache::Lookup(size_t bytes) { | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| void check_huge_pages(void *Buf,uint64_t BYTES) | ||||
| { | ||||
| #ifdef __linux__ | ||||
|   int fd = open("/proc/self/pagemap", O_RDONLY); | ||||
|   assert(fd >= 0); | ||||
|   const int page_size = 4096; | ||||
|   uint64_t virt_pfn = (uint64_t)Buf / page_size; | ||||
|   off_t offset = sizeof(uint64_t) * virt_pfn; | ||||
|   uint64_t npages = (BYTES + page_size-1) / page_size; | ||||
|   uint64_t pagedata[npages]; | ||||
|   uint64_t ret = lseek(fd, offset, SEEK_SET); | ||||
|   assert(ret == offset); | ||||
|   ret = ::read(fd, pagedata, sizeof(uint64_t)*npages); | ||||
|   assert(ret == sizeof(uint64_t) * npages); | ||||
|   int nhugepages = npages / 512; | ||||
|   int n4ktotal, nnothuge; | ||||
|   n4ktotal = 0; | ||||
|   nnothuge = 0; | ||||
|   for (int i = 0; i < nhugepages; ++i) { | ||||
|     uint64_t baseaddr = (pagedata[i*512] & 0x7fffffffffffffULL) * page_size; | ||||
|     for (int j = 0; j < 512; ++j) { | ||||
|       uint64_t pageaddr = (pagedata[i*512+j] & 0x7fffffffffffffULL) * page_size; | ||||
|       ++n4ktotal; | ||||
|       if (pageaddr != baseaddr + j * page_size) | ||||
| 	++nnothuge; | ||||
|       } | ||||
|   } | ||||
|   int rank = CartesianCommunicator::RankWorld(); | ||||
|   printf("rank %d Allocated %d 4k pages, %d not in huge pages\n", rank, n4ktotal, nnothuge); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -64,6 +64,8 @@ namespace Grid { | ||||
|  | ||||
|   }; | ||||
|  | ||||
|   void check_huge_pages(void *Buf,uint64_t BYTES); | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////// | ||||
| // A lattice of something, but assume the something is SIMDized. | ||||
| //////////////////////////////////////////////////////////////////// | ||||
|   | ||||
| @@ -44,11 +44,20 @@ namespace Grid{ | ||||
|   class GridBase : public CartesianCommunicator , public GridThread { | ||||
|  | ||||
| public: | ||||
|  | ||||
|     int dummy; | ||||
|     // Give Lattice access | ||||
|     template<class object> friend class Lattice; | ||||
|  | ||||
|     GridBase(const std::vector<int> & processor_grid) : CartesianCommunicator(processor_grid) {}; | ||||
|     GridBase(const std::vector<int> & processor_grid, | ||||
| 	     const CartesianCommunicator &parent, | ||||
| 	     int &split_rank)  | ||||
|       : CartesianCommunicator(processor_grid,parent,split_rank) {}; | ||||
|     GridBase(const std::vector<int> & processor_grid, | ||||
| 	     const CartesianCommunicator &parent)  | ||||
|       : CartesianCommunicator(processor_grid,parent,dummy) {}; | ||||
|  | ||||
|     virtual ~GridBase() = default; | ||||
|  | ||||
|     // Physics Grid information. | ||||
|     std::vector<int> _simd_layout;// Which dimensions get relayed out over simd lanes. | ||||
| @@ -210,9 +219,6 @@ public: | ||||
|       assert(lidx<lSites()); | ||||
|       Lexicographic::CoorFromIndex(lcoor,lidx,_ldimensions); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     void GlobalCoorToGlobalIndex(const std::vector<int> & gcoor,int & gidx){ | ||||
|       gidx=0; | ||||
|       int mult=1; | ||||
|   | ||||
| @@ -38,7 +38,7 @@ namespace Grid{ | ||||
| class GridCartesian: public GridBase { | ||||
|  | ||||
| public: | ||||
|  | ||||
|     int dummy; | ||||
|     virtual int  CheckerBoardFromOindexTable (int Oindex) { | ||||
|       return 0; | ||||
|     } | ||||
| @@ -61,9 +61,38 @@ public: | ||||
|     virtual int CheckerBoardShift(int source_cb,int dim,int shift, int osite){ | ||||
|       return shift; | ||||
|     } | ||||
|     ///////////////////////////////////////////////////////////////////////// | ||||
|     // Constructor takes a parent grid and possibly subdivides communicator. | ||||
|     ///////////////////////////////////////////////////////////////////////// | ||||
|     GridCartesian(const std::vector<int> &dimensions, | ||||
|                   const std::vector<int> &simd_layout, | ||||
|                   const std::vector<int> &processor_grid) : GridBase(processor_grid) | ||||
| 		  const std::vector<int> &simd_layout, | ||||
| 		  const std::vector<int> &processor_grid, | ||||
| 		  const GridCartesian &parent) : GridBase(processor_grid,parent,dummy) | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid); | ||||
|     } | ||||
|     GridCartesian(const std::vector<int> &dimensions, | ||||
| 		  const std::vector<int> &simd_layout, | ||||
| 		  const std::vector<int> &processor_grid, | ||||
| 		  const GridCartesian &parent,int &split_rank) : GridBase(processor_grid,parent,split_rank) | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid); | ||||
|     } | ||||
|     ///////////////////////////////////////////////////////////////////////// | ||||
|     // Construct from comm world | ||||
|     ///////////////////////////////////////////////////////////////////////// | ||||
|     GridCartesian(const std::vector<int> &dimensions, | ||||
| 		  const std::vector<int> &simd_layout, | ||||
| 		  const std::vector<int> &processor_grid) : GridBase(processor_grid) | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid); | ||||
|     } | ||||
|  | ||||
|     virtual ~GridCartesian() = default; | ||||
|  | ||||
|     void Init(const std::vector<int> &dimensions, | ||||
| 	      const std::vector<int> &simd_layout, | ||||
| 	      const std::vector<int> &processor_grid) | ||||
|     { | ||||
|       /////////////////////// | ||||
|       // Grid information | ||||
|   | ||||
| @@ -112,24 +112,59 @@ public: | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|     GridRedBlackCartesian(const GridBase *base) : GridRedBlackCartesian(base->_fdimensions,base->_simd_layout,base->_processors)  {}; | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     // Create Redblack from original grid; require full grid pointer ? | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     GridRedBlackCartesian(const GridBase *base) : GridBase(base->_processors,*base) | ||||
|     { | ||||
|       int dims = base->_ndimension; | ||||
|       std::vector<int> checker_dim_mask(dims,1); | ||||
|       int checker_dim = 0; | ||||
|       Init(base->_fdimensions,base->_simd_layout,base->_processors,checker_dim_mask,checker_dim); | ||||
|     }; | ||||
|  | ||||
|     GridRedBlackCartesian(const std::vector<int> &dimensions, | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     // Create redblack from original grid, with non-trivial checker dim mask | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     GridRedBlackCartesian(const GridBase *base, | ||||
| 			  const std::vector<int> &checker_dim_mask, | ||||
| 			  int checker_dim | ||||
| 			  ) :  GridBase(base->_processors,*base)  | ||||
|     { | ||||
|       Init(base->_fdimensions,base->_simd_layout,base->_processors,checker_dim_mask,checker_dim)  ; | ||||
|     } | ||||
|  | ||||
|     virtual ~GridRedBlackCartesian() = default; | ||||
| #if 0 | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     // Create redblack grid ;; deprecate these. Should not | ||||
|     // need direct creation of redblack without a full grid to base on | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     GridRedBlackCartesian(const GridBase *base, | ||||
| 			  const std::vector<int> &dimensions, | ||||
| 			  const std::vector<int> &simd_layout, | ||||
| 			  const std::vector<int> &processor_grid, | ||||
| 			  const std::vector<int> &checker_dim_mask, | ||||
| 			  int checker_dim | ||||
| 			  ) :  GridBase(processor_grid)  | ||||
| 			  ) :  GridBase(processor_grid,*base)  | ||||
|     { | ||||
|       Init(dimensions,simd_layout,processor_grid,checker_dim_mask,checker_dim); | ||||
|     } | ||||
|     GridRedBlackCartesian(const std::vector<int> &dimensions, | ||||
|  | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     // Create redblack grid | ||||
|     //////////////////////////////////////////////////////////// | ||||
|     GridRedBlackCartesian(const GridBase *base, | ||||
| 			  const std::vector<int> &dimensions, | ||||
| 			  const std::vector<int> &simd_layout, | ||||
| 			  const std::vector<int> &processor_grid) : GridBase(processor_grid)  | ||||
| 			  const std::vector<int> &processor_grid) : GridBase(processor_grid,*base)  | ||||
|     { | ||||
|       std::vector<int> checker_dim_mask(dimensions.size(),1); | ||||
|       Init(dimensions,simd_layout,processor_grid,checker_dim_mask,0); | ||||
|       int checker_dim = 0; | ||||
|       Init(dimensions,simd_layout,processor_grid,checker_dim_mask,checker_dim); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     void Init(const std::vector<int> &dimensions, | ||||
|               const std::vector<int> &simd_layout, | ||||
|               const std::vector<int> &processor_grid, | ||||
| @@ -172,6 +207,7 @@ public: | ||||
|         { | ||||
|           assert((_gdimensions[d] & 0x1) == 0); | ||||
|           _gdimensions[d] = _gdimensions[d] / 2; // Remove a checkerboard | ||||
| 	  _gsites /= 2; | ||||
|         } | ||||
|         _ldimensions[d] = _gdimensions[d] / _processors[d]; | ||||
|         assert(_ldimensions[d] * _processors[d] == _gdimensions[d]); | ||||
|   | ||||
| @@ -67,7 +67,7 @@ void CartesianCommunicator::ShmBufferFreeAll(void) { | ||||
| ///////////////////////////////// | ||||
| // Grid information queries | ||||
| ///////////////////////////////// | ||||
| int                      CartesianCommunicator::Dimensions(void)         { return _ndimension; }; | ||||
| int                      CartesianCommunicator::Dimensions(void)        { return _ndimension; }; | ||||
| int                      CartesianCommunicator::IsBoss(void)            { return _processor==0; }; | ||||
| int                      CartesianCommunicator::BossRank(void)          { return 0; }; | ||||
| int                      CartesianCommunicator::ThisRank(void)          { return _processor; }; | ||||
| @@ -96,6 +96,138 @@ void CartesianCommunicator::GlobalSumVector(ComplexD *c,int N) | ||||
|   GlobalSumVector((double *)c,2*N); | ||||
| } | ||||
|  | ||||
|  | ||||
| #if defined( GRID_COMMS_MPI) || defined (GRID_COMMS_MPIT) || defined (GRID_COMMS_MPI3) | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent,int &srank)  | ||||
| { | ||||
|   _ndimension = processors.size(); | ||||
|   assert(_ndimension = parent._ndimension); | ||||
|    | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // split the communicator | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   int Nparent; | ||||
|   MPI_Comm_size(parent.communicator,&Nparent); | ||||
|  | ||||
|   int childsize=1; | ||||
|   for(int d=0;d<processors.size();d++) { | ||||
|     childsize *= processors[d]; | ||||
|   } | ||||
|   int Nchild = Nparent/childsize; | ||||
|   assert (childsize * Nchild == Nparent); | ||||
|  | ||||
|   std::vector<int> ccoor(_ndimension); // coor within subcommunicator | ||||
|   std::vector<int> scoor(_ndimension); // coor of split within parent | ||||
|   std::vector<int> ssize(_ndimension); // coor of split within parent | ||||
|  | ||||
|   for(int d=0;d<_ndimension;d++){ | ||||
|     ccoor[d] = parent._processor_coor[d] % processors[d]; | ||||
|     scoor[d] = parent._processor_coor[d] / processors[d]; | ||||
|     ssize[d] = parent._processors[d]     / processors[d]; | ||||
|   } | ||||
|   int crank;  // rank within subcomm ; srank is rank of subcomm within blocks of subcomms | ||||
|   // Mpi uses the reverse Lexico convention to us | ||||
|   Lexicographic::IndexFromCoorReversed(ccoor,crank,processors); | ||||
|   Lexicographic::IndexFromCoorReversed(scoor,srank,ssize); | ||||
|  | ||||
|   MPI_Comm comm_split; | ||||
|   if ( Nchild > 1 ) {  | ||||
|  | ||||
|     /* | ||||
|     std::cout << GridLogMessage<<"Child communicator of "<< std::hex << parent.communicator << std::dec<<std::endl; | ||||
|     std::cout << GridLogMessage<<" parent grid["<< parent._ndimension<<"]    "; | ||||
|     for(int d=0;d<parent._processors.size();d++)  std::cout << parent._processors[d] << " "; | ||||
|     std::cout<<std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage<<" child grid["<< _ndimension <<"]    "; | ||||
|     for(int d=0;d<processors.size();d++)  std::cout << processors[d] << " "; | ||||
|     std::cout<<std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage<<" old rank "<< parent._processor<<" coor ["<< _ndimension <<"]    "; | ||||
|     for(int d=0;d<processors.size();d++)  std::cout << parent._processor_coor[d] << " "; | ||||
|     std::cout<<std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage<<" new rank "<< crank<<" coor ["<< _ndimension <<"]    "; | ||||
|     for(int d=0;d<processors.size();d++)  std::cout << ccoor[d] << " "; | ||||
|     std::cout<<std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage<<" new coor ["<< _ndimension <<"]    "; | ||||
|     for(int d=0;d<processors.size();d++)  std::cout << parent._processor_coor[d] << " "; | ||||
|     std::cout<<std::endl; | ||||
|     */ | ||||
|  | ||||
|     int ierr= MPI_Comm_split(parent.communicator,srank,crank,&comm_split); | ||||
|     assert(ierr==0); | ||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     // Declare victory | ||||
|     ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|     /* | ||||
|     std::cout << GridLogMessage<<"Divided communicator "<< parent._Nprocessors<<" into " | ||||
| 	      << Nchild <<" communicators with " << childsize << " ranks"<<std::endl; | ||||
|     */ | ||||
|   } else { | ||||
|     comm_split=parent.communicator; | ||||
|     srank = 0; | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Set up from the new split communicator | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   InitFromMPICommunicator(processors,comm_split); | ||||
| } | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Take an MPI_Comm and self assemble | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| void CartesianCommunicator::InitFromMPICommunicator(const std::vector<int> &processors, MPI_Comm communicator_base) | ||||
| { | ||||
|   _ndimension = processors.size(); | ||||
|   _processor_coor.resize(_ndimension); | ||||
|  | ||||
|   ///////////////////////////////// | ||||
|   // Count the requested nodes | ||||
|   ///////////////////////////////// | ||||
|   _Nprocessors=1; | ||||
|   _processors = processors; | ||||
|   for(int i=0;i<_ndimension;i++){ | ||||
|     _Nprocessors*=_processors[i]; | ||||
|   } | ||||
|  | ||||
|   std::vector<int> periodic(_ndimension,1); | ||||
|   MPI_Cart_create(communicator_base, _ndimension,&_processors[0],&periodic[0],0,&communicator); | ||||
|   MPI_Comm_rank(communicator,&_processor); | ||||
|   MPI_Cart_coords(communicator,_processor,_ndimension,&_processor_coor[0]); | ||||
|  | ||||
|   if ( communicator_base != communicator_world ) { | ||||
|     std::cout << "Cartesian communicator created with a non-world communicator"<<std::endl; | ||||
|      | ||||
|     std::cout << " new communicator rank "<<_processor<< " coor ["<<_ndimension<<"] "; | ||||
|     for(int d=0;d<_processors.size();d++){ | ||||
|       std::cout << _processor_coor[d]<<" "; | ||||
|     } | ||||
|     std::cout << std::endl; | ||||
|   } | ||||
|  | ||||
|   int Size; | ||||
|   MPI_Comm_size(communicator,&Size); | ||||
|  | ||||
| #ifdef GRID_COMMS_MPIT | ||||
|   communicator_halo.resize (2*_ndimension); | ||||
|   for(int i=0;i<_ndimension*2;i++){ | ||||
|     MPI_Comm_dup(communicator,&communicator_halo[i]); | ||||
|   } | ||||
| #endif | ||||
|    | ||||
|   assert(Size==_Nprocessors); | ||||
| } | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors)  | ||||
| { | ||||
|   InitFromMPICommunicator(processors,communicator_world); | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #if !defined( GRID_COMMS_MPI3)  | ||||
|  | ||||
| int                      CartesianCommunicator::NodeCount(void)    { return ProcessorCount();}; | ||||
| @@ -147,8 +279,13 @@ void *CartesianCommunicator::ShmBufferTranslate(int rank,void * local_p) { | ||||
| } | ||||
| void CartesianCommunicator::ShmInitGeneric(void){ | ||||
| #if 1 | ||||
|  | ||||
|   int mmap_flag = MAP_SHARED | MAP_ANONYMOUS; | ||||
|   int mmap_flag =0; | ||||
| #ifdef MAP_ANONYMOUS | ||||
|   mmap_flag = mmap_flag| MAP_SHARED | MAP_ANONYMOUS; | ||||
| #endif | ||||
| #ifdef MAP_ANON | ||||
|   mmap_flag = mmap_flag| MAP_SHARED | MAP_ANON; | ||||
| #endif | ||||
| #ifdef MAP_HUGETLB | ||||
|   if ( Hugepages ) mmap_flag |= MAP_HUGETLB; | ||||
| #endif | ||||
| @@ -157,7 +294,9 @@ void CartesianCommunicator::ShmInitGeneric(void){ | ||||
|     perror("mmap failed "); | ||||
|     exit(EXIT_FAILURE);   | ||||
|   } | ||||
| #ifdef MADV_HUGEPAGE | ||||
|   if (!Hugepages ) madvise(ShmCommBuf,MAX_MPI_SHM_BYTES,MADV_HUGEPAGE); | ||||
| #endif | ||||
| #else  | ||||
|   ShmBufStorageVector.resize(MAX_MPI_SHM_BYTES); | ||||
|   ShmCommBuf=(void *)&ShmBufStorageVector[0]; | ||||
|   | ||||
| @@ -83,6 +83,7 @@ class CartesianCommunicator { | ||||
|   std::vector<MPI_Comm> communicator_halo; | ||||
|  | ||||
|   typedef MPI_Request CommsRequest_t; | ||||
|  | ||||
| #else  | ||||
|   typedef int CommsRequest_t; | ||||
| #endif | ||||
| @@ -149,9 +150,22 @@ class CartesianCommunicator { | ||||
|   static void Init(int *argc, char ***argv); | ||||
|  | ||||
|   //////////////////////////////////////////////// | ||||
|   // Constructor of any given grid | ||||
|   // Constructors to sub-divide a parent communicator | ||||
|   // and default to comm world | ||||
|   //////////////////////////////////////////////// | ||||
|   CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent,int &srank); | ||||
|   CartesianCommunicator(const std::vector<int> &pdimensions_in); | ||||
|   virtual ~CartesianCommunicator(); | ||||
|  | ||||
|  private: | ||||
| #if defined (GRID_COMMS_MPI) || defined (GRID_COMMS_MPIT)  | ||||
|   //////////////////////////////////////////////// | ||||
|   // Private initialise from an MPI communicator | ||||
|   // Can use after an MPI_Comm_split, but hidden from user so private | ||||
|   //////////////////////////////////////////////// | ||||
|   void InitFromMPICommunicator(const std::vector<int> &processors, MPI_Comm communicator_base); | ||||
| #endif | ||||
|  public: | ||||
|    | ||||
|   //////////////////////////////////////////////////////////////////////////////////////// | ||||
|   // Wraps MPI_Cart routines, or implements equivalent on other impls | ||||
| @@ -250,6 +264,27 @@ class CartesianCommunicator { | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   void Broadcast(int root,void* data, int bytes); | ||||
|  | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   // All2All down one dimension | ||||
|   //////////////////////////////////////////////////////////// | ||||
|   template<class T> void AllToAll(int dim,std::vector<T> &in, std::vector<T> &out){ | ||||
|     assert(dim>=0); | ||||
|     assert(dim<_ndimension); | ||||
|     int numnode = _processors[dim]; | ||||
|     //    std::cerr << " AllToAll in.size()  "<<in.size()<<std::endl; | ||||
|     //    std::cerr << " AllToAll out.size() "<<out.size()<<std::endl; | ||||
|     assert(in.size()==out.size()); | ||||
|     uint64_t bytes=sizeof(T); | ||||
|     uint64_t words=in.size()/numnode; | ||||
|  | ||||
|     assert(numnode * words == in.size()); | ||||
|     assert(words < (1ULL<<32)); | ||||
|  | ||||
|     AllToAll(dim,(void *)&in[0],(void *)&out[0],words,bytes); | ||||
|   } | ||||
|   void AllToAll(int dim  ,void *in,void *out,uint64_t words,uint64_t bytes); | ||||
|   void AllToAll(void  *in,void *out,uint64_t words         ,uint64_t bytes); | ||||
|    | ||||
|   template<class obj> void Broadcast(int root,obj &data) | ||||
|     { | ||||
|       Broadcast(root,(void *)&data,sizeof(data)); | ||||
|   | ||||
| @@ -53,28 +53,14 @@ void CartesianCommunicator::Init(int *argc, char ***argv) { | ||||
|   ShmInitGeneric(); | ||||
| } | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
| CartesianCommunicator::~CartesianCommunicator() | ||||
| { | ||||
|   _ndimension = processors.size(); | ||||
|   std::vector<int> periodic(_ndimension,1); | ||||
|  | ||||
|   _Nprocessors=1; | ||||
|   _processors = processors; | ||||
|   _processor_coor.resize(_ndimension); | ||||
|    | ||||
|   MPI_Cart_create(communicator_world, _ndimension,&_processors[0],&periodic[0],1,&communicator); | ||||
|   MPI_Comm_rank(communicator,&_processor); | ||||
|   MPI_Cart_coords(communicator,_processor,_ndimension,&_processor_coor[0]); | ||||
|  | ||||
|   for(int i=0;i<_ndimension;i++){ | ||||
|     _Nprocessors*=_processors[i]; | ||||
|   } | ||||
|    | ||||
|   int Size;  | ||||
|   MPI_Comm_size(communicator,&Size); | ||||
|    | ||||
|   assert(Size==_Nprocessors); | ||||
|   int MPI_is_finalised; | ||||
|   MPI_Finalized(&MPI_is_finalised); | ||||
|   if (communicator && MPI_is_finalised) | ||||
|     MPI_Comm_free(&communicator); | ||||
| } | ||||
|  | ||||
| void CartesianCommunicator::GlobalSum(uint32_t &u){ | ||||
|   int ierr=MPI_Allreduce(MPI_IN_PLACE,&u,1,MPI_UINT32_T,MPI_SUM,communicator); | ||||
|   assert(ierr==0); | ||||
| @@ -210,6 +196,36 @@ void CartesianCommunicator::Broadcast(int root,void* data, int bytes) | ||||
| 		     root, | ||||
| 		     communicator); | ||||
|   assert(ierr==0); | ||||
| } | ||||
| void CartesianCommunicator::AllToAll(int dim,void  *in,void *out,uint64_t words,uint64_t bytes) | ||||
| { | ||||
|   std::vector<int> row(_ndimension,1); | ||||
|   assert(dim>=0 && dim<_ndimension); | ||||
|  | ||||
|   //  Split the communicator | ||||
|   row[dim] = _processors[dim]; | ||||
|  | ||||
|   int me; | ||||
|   CartesianCommunicator Comm(row,*this,me); | ||||
|   Comm.AllToAll(in,out,words,bytes); | ||||
| } | ||||
| void CartesianCommunicator::AllToAll(void  *in,void *out,uint64_t words,uint64_t bytes) | ||||
| { | ||||
|   // MPI is a pain and uses "int" arguments | ||||
|   // 64*64*64*128*16 == 500Million elements of data. | ||||
|   // When 24*4 bytes multiples get 50x 10^9 >>> 2x10^9 Y2K bug. | ||||
|   // (Turns up on 32^3 x 64 Gparity too) | ||||
|   MPI_Datatype object; | ||||
|   int iwords;  | ||||
|   int ibytes; | ||||
|   iwords = words; | ||||
|   ibytes = bytes; | ||||
|   assert(words == iwords); // safe to cast to int ? | ||||
|   assert(bytes == ibytes); // safe to cast to int ? | ||||
|   MPI_Type_contiguous(ibytes,MPI_BYTE,&object); | ||||
|   MPI_Type_commit(&object); | ||||
|   MPI_Alltoall(in,iwords,object,out,iwords,object,communicator); | ||||
|   MPI_Type_free(&object); | ||||
| } | ||||
|   /////////////////////////////////////////////////////// | ||||
|   // Should only be used prior to Grid Init finished. | ||||
| @@ -230,5 +246,7 @@ void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) | ||||
|   assert(ierr==0); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -215,8 +215,10 @@ void CartesianCommunicator::Init(int *argc, char ***argv) { | ||||
|       perror("open hugetlbfs"); | ||||
|       exit(0); | ||||
|     } | ||||
|      | ||||
|     int mmap_flag = MAP_SHARED |MAP_POPULATE; | ||||
|     int mmap_flag = MAP_SHARED ; | ||||
| #ifdef MAP_POPULATE     | ||||
|     mmap_flag|=MAP_POPULATE; | ||||
| #endif | ||||
| #ifdef MAP_HUGETLB | ||||
|     if ( Hugepages ) mmap_flag |= MAP_HUGETLB; | ||||
| #endif | ||||
| @@ -249,7 +251,10 @@ void CartesianCommunicator::Init(int *argc, char ***argv) { | ||||
|       if ( fd < 0 ) {	perror("failed shm_open");	assert(0);      } | ||||
|       ftruncate(fd, size); | ||||
|        | ||||
|       int mmap_flag = MAP_SHARED|MAP_POPULATE; | ||||
|       int mmap_flag = MAP_SHARED; | ||||
| #ifdef MAP_POPULATE  | ||||
|       mmap_flag |= MAP_POPULATE; | ||||
| #endif | ||||
| #ifdef MAP_HUGETLB | ||||
|       if (Hugepages) mmap_flag |= MAP_HUGETLB; | ||||
| #endif | ||||
| @@ -445,6 +450,15 @@ void  CartesianCommunicator::ProcessorCoorFromRank(int rank, std::vector<int> &c | ||||
|   assert(lr!=-1); | ||||
|   Lexicographic::CoorFromIndex(coor,lr,_processors); | ||||
| } | ||||
|  | ||||
| ////////////////////////////////// | ||||
| // Try to subdivide communicator | ||||
| ////////////////////////////////// | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent)  | ||||
|   : CartesianCommunicator(processors)  | ||||
| { | ||||
|   std::cout << "Attempts to split MPI3 communicators will fail until implemented" <<std::endl; | ||||
| } | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
| {  | ||||
|   int ierr; | ||||
| @@ -698,7 +712,8 @@ double CartesianCommunicator::StencilSendToRecvFromBegin(std::vector<CommsReques | ||||
| 							 int from, | ||||
| 							 int bytes,int dir) | ||||
| { | ||||
|   assert(dir < communicator_halo.size()); | ||||
|   int ncomm  =communicator_halo.size();  | ||||
|   int commdir=dir%ncomm; | ||||
|  | ||||
|   MPI_Request xrq; | ||||
|   MPI_Request rrq; | ||||
| @@ -718,14 +733,14 @@ double CartesianCommunicator::StencilSendToRecvFromBegin(std::vector<CommsReques | ||||
|   gfrom = MPI_UNDEFINED; | ||||
| #endif | ||||
|   if ( gfrom ==MPI_UNDEFINED) { | ||||
|     ierr=MPI_Irecv(recv, bytes, MPI_CHAR,from,from,communicator_halo[dir],&rrq); | ||||
|     ierr=MPI_Irecv(recv, bytes, MPI_CHAR,from,from,communicator_halo[commdir],&rrq); | ||||
|     assert(ierr==0); | ||||
|     list.push_back(rrq); | ||||
|     off_node_bytes+=bytes; | ||||
|   } | ||||
|  | ||||
|   if ( gdest == MPI_UNDEFINED ) { | ||||
|     ierr =MPI_Isend(xmit, bytes, MPI_CHAR,dest,_processor,communicator_halo[dir],&xrq); | ||||
|     ierr =MPI_Isend(xmit, bytes, MPI_CHAR,dest,_processor,communicator_halo[commdir],&xrq); | ||||
|     assert(ierr==0); | ||||
|     list.push_back(xrq); | ||||
|     off_node_bytes+=bytes; | ||||
|   | ||||
| @@ -53,33 +53,13 @@ void CartesianCommunicator::Init(int *argc, char ***argv) { | ||||
|   ShmInitGeneric(); | ||||
| } | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
| CartesianCommunicator::~CartesianCommunicator() | ||||
| { | ||||
|   _ndimension = processors.size(); | ||||
|   std::vector<int> periodic(_ndimension,1); | ||||
|  | ||||
|   _Nprocessors=1; | ||||
|   _processors = processors; | ||||
|   _processor_coor.resize(_ndimension); | ||||
|    | ||||
|   MPI_Cart_create(communicator_world, _ndimension,&_processors[0],&periodic[0],1,&communicator); | ||||
|   MPI_Comm_rank(communicator,&_processor); | ||||
|   MPI_Cart_coords(communicator,_processor,_ndimension,&_processor_coor[0]); | ||||
|  | ||||
|   for(int i=0;i<_ndimension;i++){ | ||||
|     _Nprocessors*=_processors[i]; | ||||
|   } | ||||
|  | ||||
|   communicator_halo.resize (2*_ndimension); | ||||
|   for(int i=0;i<_ndimension*2;i++){ | ||||
|     MPI_Comm_dup(communicator,&communicator_halo[i]); | ||||
|   } | ||||
|    | ||||
|   int Size;  | ||||
|   MPI_Comm_size(communicator,&Size); | ||||
|    | ||||
|   assert(Size==_Nprocessors); | ||||
|   if (communicator && !MPI::Is_finalized()) | ||||
|     MPI_Comm_free(&communicator); | ||||
| } | ||||
|  | ||||
|  | ||||
| void CartesianCommunicator::GlobalSum(uint32_t &u){ | ||||
|   int ierr=MPI_Allreduce(MPI_IN_PLACE,&u,1,MPI_UINT32_T,MPI_SUM,communicator); | ||||
|   assert(ierr==0); | ||||
| @@ -244,13 +224,14 @@ double CartesianCommunicator::StencilSendToRecvFromBegin(std::vector<CommsReques | ||||
| { | ||||
|   int myrank = _processor; | ||||
|   int ierr; | ||||
|   assert(dir < communicator_halo.size()); | ||||
|   int ncomm  =communicator_halo.size();  | ||||
|   int commdir=dir%ncomm; | ||||
|    | ||||
|   //  std::cout << " sending on communicator "<<dir<<" " <<communicator_halo[dir]<<std::endl; | ||||
|   // Give the CPU to MPI immediately; can use threads to overlap optionally | ||||
|   MPI_Request req[2]; | ||||
|   MPI_Irecv(recv,bytes,MPI_CHAR,recv_from_rank,recv_from_rank, communicator_halo[dir],&req[1]); | ||||
|   MPI_Isend(xmit,bytes,MPI_CHAR,xmit_to_rank  ,myrank        , communicator_halo[dir],&req[0]); | ||||
|   MPI_Irecv(recv,bytes,MPI_CHAR,recv_from_rank,recv_from_rank, communicator_halo[commdir],&req[1]); | ||||
|   MPI_Isend(xmit,bytes,MPI_CHAR,xmit_to_rank  ,myrank        , communicator_halo[commdir],&req[0]); | ||||
|  | ||||
|   list.push_back(req[0]); | ||||
|   list.push_back(req[1]); | ||||
| @@ -269,13 +250,14 @@ double CartesianCommunicator::StencilSendToRecvFrom(void *xmit, | ||||
| { | ||||
|   int myrank = _processor; | ||||
|   int ierr; | ||||
|   assert(dir < communicator_halo.size()); | ||||
|   //  std::cout << " sending on communicator "<<dir<<" " <<communicator_halo.size()<< <std::endl; | ||||
|  | ||||
|   //  std::cout << " sending on communicator "<<dir<<" " <<communicator_halo[dir]<<std::endl; | ||||
|   int ncomm  =communicator_halo.size();  | ||||
|   int commdir=dir%ncomm; | ||||
|   // Give the CPU to MPI immediately; can use threads to overlap optionally | ||||
|   MPI_Request req[2]; | ||||
|   MPI_Irecv(recv,bytes,MPI_CHAR,recv_from_rank,recv_from_rank, communicator_halo[dir],&req[1]); | ||||
|   MPI_Isend(xmit,bytes,MPI_CHAR,xmit_to_rank  ,myrank        , communicator_halo[dir],&req[0]); | ||||
|   MPI_Irecv(recv,bytes,MPI_CHAR,recv_from_rank,recv_from_rank, communicator_halo[commdir],&req[1]); | ||||
|   MPI_Isend(xmit,bytes,MPI_CHAR,xmit_to_rank  ,myrank        , communicator_halo[commdir],&req[0]); | ||||
|   MPI_Waitall(2, req, MPI_STATUSES_IGNORE); | ||||
|   return 2.0*bytes; | ||||
| } | ||||
|   | ||||
| @@ -38,6 +38,9 @@ void CartesianCommunicator::Init(int *argc, char *** arv) | ||||
|   ShmInitGeneric(); | ||||
| } | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent,int &srank)  | ||||
|   : CartesianCommunicator(processors) { srank=0;} | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
| { | ||||
|   _processors = processors; | ||||
| @@ -53,6 +56,8 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
|   } | ||||
| } | ||||
|  | ||||
| CartesianCommunicator::~CartesianCommunicator(){} | ||||
|  | ||||
| void CartesianCommunicator::GlobalSum(float &){} | ||||
| void CartesianCommunicator::GlobalSumVector(float *,int N){} | ||||
| void CartesianCommunicator::GlobalSum(double &){} | ||||
| @@ -95,6 +100,14 @@ void CartesianCommunicator::SendToRecvFromComplete(std::vector<CommsRequest_t> & | ||||
| { | ||||
|   assert(0); | ||||
| } | ||||
| void CartesianCommunicator::AllToAll(int dim,void  *in,void *out,uint64_t words,uint64_t bytes) | ||||
| { | ||||
|   bcopy(in,out,bytes*words); | ||||
| } | ||||
| void CartesianCommunicator::AllToAll(void  *in,void *out,uint64_t words,uint64_t bytes) | ||||
| { | ||||
|   bcopy(in,out,bytes*words); | ||||
| } | ||||
|  | ||||
| int  CartesianCommunicator::RankWorld(void){return 0;} | ||||
| void CartesianCommunicator::Barrier(void){} | ||||
|   | ||||
| @@ -75,6 +75,11 @@ void CartesianCommunicator::Init(int *argc, char ***argv) { | ||||
|   ShmInitGeneric(); | ||||
| } | ||||
|  | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,const CartesianCommunicator &parent)  | ||||
|   : CartesianCommunicator(processors)  | ||||
| { | ||||
|   std::cout << "Attempts to split SHMEM communicators will fail " <<std::endl; | ||||
| } | ||||
| CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors) | ||||
| { | ||||
|   _ndimension = processors.size(); | ||||
|   | ||||
							
								
								
									
										16252
									
								
								lib/json/json.hpp
									
									
									
									
									
								
							
							
						
						
									
										16252
									
								
								lib/json/json.hpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -544,7 +544,6 @@ static void sliceInnerProductMatrix(  Eigen::MatrixXcd &mat, const Lattice<vobj> | ||||
|       for(int i=0;i<Nblock;i++){ | ||||
|       for(int j=0;j<Nblock;j++){ | ||||
| 	auto tmp = innerProduct(Left[i],Right[j]); | ||||
| 	//	vector_typeD rtmp = TensorRemove(tmp); | ||||
| 	auto rtmp = TensorRemove(tmp); | ||||
| 	mat_thread(i,j) += Reduce(rtmp); | ||||
|       }} | ||||
|   | ||||
| @@ -109,8 +109,8 @@ inline void blockProject(Lattice<iVector<CComplex,nbasis > > &coarseData, | ||||
|  | ||||
|   coarseData=zero; | ||||
|  | ||||
|   // Loop with a cache friendly loop ordering | ||||
|   for(int sf=0;sf<fine->oSites();sf++){ | ||||
|   // Loop over coars parallel, and then loop over fine associated with coarse. | ||||
|   parallel_for(int sf=0;sf<fine->oSites();sf++){ | ||||
|  | ||||
|     int sc; | ||||
|     std::vector<int> coor_c(_ndimension); | ||||
| @@ -119,6 +119,7 @@ inline void blockProject(Lattice<iVector<CComplex,nbasis > > &coarseData, | ||||
|     for(int d=0;d<_ndimension;d++) coor_c[d]=coor_f[d]/block_r[d]; | ||||
|     Lexicographic::IndexFromCoor(coor_c,sc,coarse->_rdimensions); | ||||
|  | ||||
| PARALLEL_CRITICAL | ||||
|     for(int i=0;i<nbasis;i++) { | ||||
|  | ||||
|       coarseData._odata[sc](i)=coarseData._odata[sc](i) | ||||
| @@ -139,6 +140,7 @@ inline void blockZAXPY(Lattice<vobj> &fineZ, | ||||
|   GridBase * coarse= coarseA._grid; | ||||
|  | ||||
|   fineZ.checkerboard=fineX.checkerboard; | ||||
|   assert(fineX.checkerboard==fineY.checkerboard); | ||||
|   subdivides(coarse,fine); // require they map | ||||
|   conformable(fineX,fineY); | ||||
|   conformable(fineX,fineZ); | ||||
| @@ -180,9 +182,10 @@ template<class vobj,class CComplex> | ||||
|   GridBase *coarse(CoarseInner._grid); | ||||
|   GridBase *fine  (fineX._grid); | ||||
|  | ||||
|   Lattice<dotp> fine_inner(fine); | ||||
|   Lattice<dotp> fine_inner(fine); fine_inner.checkerboard = fineX.checkerboard; | ||||
|   Lattice<dotp> coarse_inner(coarse); | ||||
|  | ||||
|   // Precision promotion? | ||||
|   fine_inner = localInnerProduct(fineX,fineY); | ||||
|   blockSum(coarse_inner,fine_inner); | ||||
|   parallel_for(int ss=0;ss<coarse->oSites();ss++){ | ||||
| @@ -193,7 +196,7 @@ template<class vobj,class CComplex> | ||||
| inline void blockNormalise(Lattice<CComplex> &ip,Lattice<vobj> &fineX) | ||||
| { | ||||
|   GridBase *coarse = ip._grid; | ||||
|   Lattice<vobj> zz(fineX._grid); zz=zero; | ||||
|   Lattice<vobj> zz(fineX._grid); zz=zero; zz.checkerboard=fineX.checkerboard; | ||||
|   blockInnerProduct(ip,fineX,fineX); | ||||
|   ip = pow(ip,-0.5); | ||||
|   blockZAXPY(fineX,ip,fineX,zz); | ||||
| @@ -216,19 +219,25 @@ inline void blockSum(Lattice<vobj> &coarseData,const Lattice<vobj> &fineData) | ||||
|     block_r[d] = fine->_rdimensions[d] / coarse->_rdimensions[d]; | ||||
|   } | ||||
|  | ||||
|   // Turn this around to loop threaded over sc and interior loop  | ||||
|   // over sf would thread better | ||||
|   coarseData=zero; | ||||
|   for(int sf=0;sf<fine->oSites();sf++){ | ||||
|   parallel_region { | ||||
|  | ||||
|     int sc; | ||||
|     std::vector<int> coor_c(_ndimension); | ||||
|     std::vector<int> coor_f(_ndimension); | ||||
|  | ||||
|     Lexicographic::CoorFromIndex(coor_f,sf,fine->_rdimensions); | ||||
|     for(int d=0;d<_ndimension;d++) coor_c[d]=coor_f[d]/block_r[d]; | ||||
|     Lexicographic::IndexFromCoor(coor_c,sc,coarse->_rdimensions); | ||||
|     parallel_for_internal(int sf=0;sf<fine->oSites();sf++){ | ||||
|      | ||||
|     coarseData._odata[sc]=coarseData._odata[sc]+fineData._odata[sf]; | ||||
|       Lexicographic::CoorFromIndex(coor_f,sf,fine->_rdimensions); | ||||
|       for(int d=0;d<_ndimension;d++) coor_c[d]=coor_f[d]/block_r[d]; | ||||
|       Lexicographic::IndexFromCoor(coor_c,sc,coarse->_rdimensions); | ||||
|        | ||||
| PARALLEL_CRITICAL | ||||
|       coarseData._odata[sc]=coarseData._odata[sc]+fineData._odata[sf]; | ||||
|  | ||||
|     } | ||||
|   } | ||||
|   return; | ||||
| } | ||||
| @@ -238,7 +247,7 @@ inline void blockPick(GridBase *coarse,const Lattice<vobj> &unpicked,Lattice<vob | ||||
| { | ||||
|   GridBase * fine = unpicked._grid; | ||||
|  | ||||
|   Lattice<vobj> zz(fine); | ||||
|   Lattice<vobj> zz(fine); zz.checkerboard = unpicked.checkerboard; | ||||
|   Lattice<iScalar<vInteger> > fcoor(fine); | ||||
|  | ||||
|   zz = zero; | ||||
| @@ -303,20 +312,21 @@ inline void blockPromote(const Lattice<iVector<CComplex,nbasis > > &coarseData, | ||||
|   } | ||||
|  | ||||
|   // Loop with a cache friendly loop ordering | ||||
|   for(int sf=0;sf<fine->oSites();sf++){ | ||||
|  | ||||
|   parallel_region { | ||||
|     int sc; | ||||
|     std::vector<int> coor_c(_ndimension); | ||||
|     std::vector<int> coor_f(_ndimension); | ||||
|  | ||||
|     Lexicographic::CoorFromIndex(coor_f,sf,fine->_rdimensions); | ||||
|     for(int d=0;d<_ndimension;d++) coor_c[d]=coor_f[d]/block_r[d]; | ||||
|     Lexicographic::IndexFromCoor(coor_c,sc,coarse->_rdimensions); | ||||
|     parallel_for_internal(int sf=0;sf<fine->oSites();sf++){ | ||||
|  | ||||
|     for(int i=0;i<nbasis;i++) { | ||||
|       if(i==0) fineData._odata[sf]=coarseData._odata[sc](i) * Basis[i]._odata[sf]; | ||||
|       else     fineData._odata[sf]=fineData._odata[sf]+coarseData._odata[sc](i)*Basis[i]._odata[sf]; | ||||
|       Lexicographic::CoorFromIndex(coor_f,sf,fine->_rdimensions); | ||||
|       for(int d=0;d<_ndimension;d++) coor_c[d]=coor_f[d]/block_r[d]; | ||||
|       Lexicographic::IndexFromCoor(coor_c,sc,coarse->_rdimensions); | ||||
|        | ||||
|       for(int i=0;i<nbasis;i++) { | ||||
| 	if(i==0) fineData._odata[sf]=coarseData._odata[sc](i) * Basis[i]._odata[sf]; | ||||
| 	else     fineData._odata[sf]=fineData._odata[sf]+coarseData._odata[sc](i)*Basis[i]._odata[sf]; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return; | ||||
| @@ -685,5 +695,314 @@ void precisionChange(Lattice<VobjOut> &out, const Lattice<VobjIn> &in){ | ||||
|   } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Communicate between grids | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // All to all plan | ||||
| // | ||||
| // Subvolume on fine grid is v.    Vectors a,b,c,d  | ||||
| // | ||||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // SIMPLEST CASE: | ||||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Mesh of nodes (2) ; subdivide to  1 subdivisions | ||||
| // | ||||
| // Lex ord:    | ||||
| //          N0 va0 vb0  N1 va1 vb1  | ||||
| // | ||||
| // For each dimension do an all to all | ||||
| // | ||||
| // full AllToAll(0) | ||||
| //          N0 va0 va1    N1 vb0 vb1 | ||||
| // | ||||
| // REARRANGE | ||||
| //          N0 va01       N1 vb01 | ||||
| // | ||||
| // Must also rearrange data to get into the NEW lex order of grid at each stage. Some kind of "insert/extract". | ||||
| // NB: Easiest to programme if keep in lex order. | ||||
| // | ||||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // SIMPLE CASE: | ||||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // Mesh of nodes (2x2) ; subdivide to  1x1 subdivisions | ||||
| // | ||||
| // Lex ord:    | ||||
| //          N0 va0 vb0 vc0 vd0       N1 va1 vb1 vc1 vd1   | ||||
| //          N2 va2 vb2 vc2 vd2       N3 va3 vb3 vc3 vd3  | ||||
| // | ||||
| // Ratio = full[dim] / split[dim] | ||||
| // | ||||
| // For each dimension do an all to all; get Nvec -> Nvec / ratio | ||||
| //                                          Ldim -> Ldim * ratio | ||||
| //                                          LocalVol -> LocalVol * ratio | ||||
| // full AllToAll(0) | ||||
| //          N0 va0 vb0 va1 vb1       N1 vc0 vd0 vc1 vd1    | ||||
| //          N2 va2 vb2 va3 vb3       N3 vc2 vd2 vc3 vd3  | ||||
| // | ||||
| // REARRANGE | ||||
| //          N0 va01 vb01      N1 vc01 vd01 | ||||
| //          N2 va23 vb23      N3 vc23 vd23 | ||||
| // | ||||
| // full AllToAll(1)           // Not what is wanted. FIXME | ||||
| //          N0 va01 va23      N1 vc01 vc23  | ||||
| //          N2 vb01 vb23      N3 vd01 vd23 | ||||
| //  | ||||
| // REARRANGE | ||||
| //          N0 va0123      N1 vc0123 | ||||
| //          N2 vb0123      N3 vd0123 | ||||
| // | ||||
| // Must also rearrange data to get into the NEW lex order of grid at each stage. Some kind of "insert/extract". | ||||
| // NB: Easiest to programme if keep in lex order. | ||||
| // | ||||
| ///////////////////////////////////////////////////////// | ||||
|  | ||||
| template<class Vobj> | ||||
| void Grid_split(std::vector<Lattice<Vobj> > & full,Lattice<Vobj>   & split) | ||||
| { | ||||
|   typedef typename Vobj::scalar_object Sobj; | ||||
|  | ||||
|   int full_vecs   = full.size(); | ||||
|  | ||||
|   assert(full_vecs>=1); | ||||
|  | ||||
|   GridBase * full_grid = full[0]._grid; | ||||
|   GridBase *split_grid = split._grid; | ||||
|  | ||||
|   int       ndim  = full_grid->_ndimension; | ||||
|   int  full_nproc = full_grid->_Nprocessors; | ||||
|   int split_nproc =split_grid->_Nprocessors; | ||||
|  | ||||
|   //////////////////////////////// | ||||
|   // Checkerboard management | ||||
|   //////////////////////////////// | ||||
|   int cb = full[0].checkerboard; | ||||
|   split.checkerboard = cb; | ||||
|  | ||||
|   ////////////////////////////// | ||||
|   // Checks | ||||
|   ////////////////////////////// | ||||
|   assert(full_grid->_ndimension==split_grid->_ndimension); | ||||
|   for(int n=0;n<full_vecs;n++){ | ||||
|     assert(full[n].checkerboard == cb); | ||||
|     for(int d=0;d<ndim;d++){ | ||||
|       assert(full[n]._grid->_gdimensions[d]==split._grid->_gdimensions[d]); | ||||
|       assert(full[n]._grid->_fdimensions[d]==split._grid->_fdimensions[d]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   int   nvector   =full_nproc/split_nproc;  | ||||
|   assert(nvector*split_nproc==full_nproc); | ||||
|   assert(nvector == full_vecs); | ||||
|  | ||||
|   std::vector<int> ratio(ndim); | ||||
|   for(int d=0;d<ndim;d++){ | ||||
|     ratio[d] = full_grid->_processors[d]/ split_grid->_processors[d]; | ||||
|   } | ||||
|  | ||||
|   uint64_t lsites = full_grid->lSites(); | ||||
|   uint64_t     sz = lsites * nvector; | ||||
|   std::vector<Sobj> tmpdata(sz); | ||||
|   std::vector<Sobj> alldata(sz); | ||||
|   std::vector<Sobj> scalardata(lsites);  | ||||
|  | ||||
|   for(int v=0;v<nvector;v++){ | ||||
|     unvectorizeToLexOrdArray(scalardata,full[v]);     | ||||
|     parallel_for(int site=0;site<lsites;site++){ | ||||
|       alldata[v*lsites+site] = scalardata[site]; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   int nvec = nvector; // Counts down to 1 as we collapse dims | ||||
|   std::vector<int> ldims = full_grid->_ldimensions; | ||||
|   std::vector<int> lcoor(ndim); | ||||
|  | ||||
|   for(int d=ndim-1;d>=0;d--){ | ||||
|  | ||||
|     if ( ratio[d] != 1 ) { | ||||
|  | ||||
|       full_grid ->AllToAll(d,alldata,tmpdata); | ||||
|       //      std::cout << GridLogMessage << "Grid_split: dim " <<d<<" ratio "<<ratio[d]<<" nvec "<<nvec<<" procs "<<split_grid->_processors[d]<<std::endl; | ||||
|       //      for(int v=0;v<nvec;v++){ | ||||
|       //	std::cout << "Grid_split: alldata["<<v<<"] " << alldata[v] <<std::endl; | ||||
|       //	std::cout << "Grid_split: tmpdata["<<v<<"] " << tmpdata[v] <<std::endl; | ||||
|       //      } | ||||
|       ////////////////////////////////////////// | ||||
|       //Local volume for this dimension is expanded by ratio of processor extents | ||||
|       // Number of vectors is decreased by same factor | ||||
|       // Rearrange to lexico for bigger volume | ||||
|       ////////////////////////////////////////// | ||||
|       nvec    /= ratio[d]; | ||||
|  | ||||
|       auto rdims = ldims; rdims[d]  *=   ratio[d]; | ||||
|       auto rsites= lsites*ratio[d]; | ||||
|       for(int v=0;v<nvec;v++){ | ||||
|  | ||||
| 	// For loop over each site within old subvol | ||||
| 	for(int lsite=0;lsite<lsites;lsite++){ | ||||
|  | ||||
| 	  Lexicographic::CoorFromIndex(lcoor, lsite, ldims);	   | ||||
|  | ||||
| 	  for(int r=0;r<ratio[d];r++){ // ratio*nvec terms | ||||
|  | ||||
| 	    auto rcoor = lcoor;	    rcoor[d]  += r*ldims[d]; | ||||
|  | ||||
| 	    int rsite; Lexicographic::IndexFromCoor(rcoor, rsite, rdims);	   | ||||
| 	    rsite += v * rsites; | ||||
|  | ||||
| 	    int rmul=nvec*lsites; | ||||
| 	    int vmul=     lsites; | ||||
| 	    alldata[rsite] = tmpdata[lsite+r*rmul+v*vmul]; | ||||
| 	    //	    if ( lsite==0 ) { | ||||
| 	    //	      std::cout << "Grid_split: grow alldata["<<rsite<<"] " << alldata[rsite] << " <- tmpdata["<< lsite+r*rmul+v*vmul<<"] "<<tmpdata[lsite+r*rmul+v*vmul]  <<std::endl; | ||||
| 	    //	    }	       | ||||
| 	  } | ||||
| 	} | ||||
|       } | ||||
|       ldims[d]*= ratio[d]; | ||||
|       lsites  *= ratio[d]; | ||||
|  | ||||
|       if ( split_grid->_processors[d] > 1 ) { | ||||
| 	tmpdata = alldata; | ||||
| 	split_grid->AllToAll(d,tmpdata,alldata); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   vectorizeFromLexOrdArray(alldata,split);     | ||||
| } | ||||
|  | ||||
| template<class Vobj> | ||||
| void Grid_split(Lattice<Vobj> &full,Lattice<Vobj>   & split) | ||||
| { | ||||
|   int nvector = full._grid->_Nprocessors / split._grid->_Nprocessors; | ||||
|   std::vector<Lattice<Vobj> > full_v(nvector,full._grid); | ||||
|   for(int n=0;n<nvector;n++){ | ||||
|     full_v[n] = full; | ||||
|   } | ||||
|   Grid_split(full_v,split); | ||||
| } | ||||
|  | ||||
| template<class Vobj> | ||||
| void Grid_unsplit(std::vector<Lattice<Vobj> > & full,Lattice<Vobj>   & split) | ||||
| { | ||||
|   typedef typename Vobj::scalar_object Sobj; | ||||
|  | ||||
|   int full_vecs   = full.size(); | ||||
|  | ||||
|   assert(full_vecs>=1); | ||||
|  | ||||
|   GridBase * full_grid = full[0]._grid; | ||||
|   GridBase *split_grid = split._grid; | ||||
|  | ||||
|   int       ndim  = full_grid->_ndimension; | ||||
|   int  full_nproc = full_grid->_Nprocessors; | ||||
|   int split_nproc =split_grid->_Nprocessors; | ||||
|  | ||||
|   //////////////////////////////// | ||||
|   // Checkerboard management | ||||
|   //////////////////////////////// | ||||
|   int cb = full[0].checkerboard; | ||||
|   split.checkerboard = cb; | ||||
|  | ||||
|   ////////////////////////////// | ||||
|   // Checks | ||||
|   ////////////////////////////// | ||||
|   assert(full_grid->_ndimension==split_grid->_ndimension); | ||||
|   for(int n=0;n<full_vecs;n++){ | ||||
|     assert(full[n].checkerboard == cb); | ||||
|     for(int d=0;d<ndim;d++){ | ||||
|       assert(full[n]._grid->_gdimensions[d]==split._grid->_gdimensions[d]); | ||||
|       assert(full[n]._grid->_fdimensions[d]==split._grid->_fdimensions[d]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   int   nvector   =full_nproc/split_nproc;  | ||||
|   assert(nvector*split_nproc==full_nproc); | ||||
|   assert(nvector == full_vecs); | ||||
|  | ||||
|   std::vector<int> ratio(ndim); | ||||
|   for(int d=0;d<ndim;d++){ | ||||
|     ratio[d] = full_grid->_processors[d]/ split_grid->_processors[d]; | ||||
|   } | ||||
|  | ||||
|   uint64_t lsites = full_grid->lSites(); | ||||
|   uint64_t     sz = lsites * nvector; | ||||
|   std::vector<Sobj> tmpdata(sz); | ||||
|   std::vector<Sobj> alldata(sz); | ||||
|   std::vector<Sobj> scalardata(lsites);  | ||||
|  | ||||
|   unvectorizeToLexOrdArray(alldata,split);     | ||||
|  | ||||
|   ///////////////////////////////////////////////////////////////// | ||||
|   // Start from split grid and work towards full grid | ||||
|   ///////////////////////////////////////////////////////////////// | ||||
|   std::vector<int> lcoor(ndim); | ||||
|   std::vector<int> rcoor(ndim); | ||||
|  | ||||
|   int nvec = 1; | ||||
|   lsites = split_grid->lSites(); | ||||
|   std::vector<int> ldims = split_grid->_ldimensions; | ||||
|  | ||||
|   //  for(int d=ndim-1;d>=0;d--){ | ||||
|   for(int d=0;d<ndim;d++){ | ||||
|  | ||||
|     if ( ratio[d] != 1 ) { | ||||
|  | ||||
|  | ||||
|       if ( split_grid->_processors[d] > 1 ) { | ||||
| 	tmpdata = alldata; | ||||
| 	split_grid->AllToAll(d,tmpdata,alldata); | ||||
|       } | ||||
|  | ||||
|       ////////////////////////////////////////// | ||||
|       //Local volume for this dimension is expanded by ratio of processor extents | ||||
|       // Number of vectors is decreased by same factor | ||||
|       // Rearrange to lexico for bigger volume | ||||
|       ////////////////////////////////////////// | ||||
|       auto rsites= lsites/ratio[d]; | ||||
|       auto rdims = ldims; rdims[d]/=ratio[d]; | ||||
|  | ||||
|       for(int v=0;v<nvec;v++){ | ||||
|  | ||||
| 	// rsite, rcoor --> smaller local volume | ||||
| 	// lsite, lcoor --> bigger original (single node?) volume | ||||
| 	// For loop over each site within smaller subvol | ||||
| 	for(int rsite=0;rsite<rsites;rsite++){ | ||||
|  | ||||
| 	  Lexicographic::CoorFromIndex(rcoor, rsite, rdims);	   | ||||
| 	  int lsite; | ||||
|  | ||||
| 	  for(int r=0;r<ratio[d];r++){  | ||||
|  | ||||
| 	    lcoor = rcoor; lcoor[d] += r*rdims[d]; | ||||
| 	    Lexicographic::IndexFromCoor(lcoor, lsite, ldims); lsite += v * lsites; | ||||
|  | ||||
| 	    int rmul=nvec*rsites; | ||||
| 	    int vmul=     rsites; | ||||
| 	    tmpdata[rsite+r*rmul+v*vmul]=alldata[lsite]; | ||||
|  | ||||
| 	  } | ||||
| 	} | ||||
|       } | ||||
|       nvec   *= ratio[d]; | ||||
|       ldims[d]=rdims[d]; | ||||
|       lsites  =rsites; | ||||
|  | ||||
|       full_grid ->AllToAll(d,tmpdata,alldata); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   lsites = full_grid->lSites(); | ||||
|   for(int v=0;v<nvector;v++){ | ||||
|     assert(v<full.size()); | ||||
|     parallel_for(int site=0;site<lsites;site++){ | ||||
|       scalardata[site] = alldata[v*lsites+site]; | ||||
|     } | ||||
|     vectorizeFromLexOrdArray(scalardata,full[v]);     | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -50,7 +50,7 @@ namespace Grid { | ||||
|     return (status==0) ? res.get() : name ; | ||||
|   } | ||||
|    | ||||
| GridStopWatch Logger::StopWatch; | ||||
| GridStopWatch Logger::GlobalStopWatch; | ||||
| int Logger::timestamp; | ||||
| std::ostream Logger::devnull(0); | ||||
|  | ||||
| @@ -59,13 +59,15 @@ void GridLogTimestamp(int on){ | ||||
| } | ||||
|  | ||||
| Colours GridLogColours(0); | ||||
| GridLogger GridLogError(1, "Error", GridLogColours, "RED"); | ||||
| GridLogger GridLogIRL    (1, "IRL"   , GridLogColours, "NORMAL"); | ||||
| GridLogger GridLogSolver (1, "Solver", GridLogColours, "NORMAL"); | ||||
| GridLogger GridLogError  (1, "Error" , GridLogColours, "RED"); | ||||
| GridLogger GridLogWarning(1, "Warning", GridLogColours, "YELLOW"); | ||||
| GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL"); | ||||
| GridLogger GridLogDebug(1, "Debug", GridLogColours, "PURPLE"); | ||||
| GridLogger GridLogDebug  (1, "Debug", GridLogColours, "PURPLE"); | ||||
| GridLogger GridLogPerformance(1, "Performance", GridLogColours, "GREEN"); | ||||
| GridLogger GridLogIterative(1, "Iterative", GridLogColours, "BLUE"); | ||||
| GridLogger GridLogIntegrator(1, "Integrator", GridLogColours, "BLUE"); | ||||
| GridLogger GridLogIterative  (1, "Iterative", GridLogColours, "BLUE"); | ||||
| GridLogger GridLogIntegrator (1, "Integrator", GridLogColours, "BLUE"); | ||||
|  | ||||
| void GridLogConfigure(std::vector<std::string> &logstreams) { | ||||
|   GridLogError.Active(0); | ||||
|   | ||||
| @@ -85,12 +85,15 @@ class Logger { | ||||
| protected: | ||||
|   Colours &Painter; | ||||
|   int active; | ||||
|   int timing_mode; | ||||
|   static int timestamp; | ||||
|   std::string name, topName; | ||||
|   std::string COLOUR; | ||||
|  | ||||
| public: | ||||
|   static GridStopWatch StopWatch; | ||||
|   static GridStopWatch GlobalStopWatch; | ||||
|   GridStopWatch         LocalStopWatch; | ||||
|   GridStopWatch *StopWatch; | ||||
|   static std::ostream devnull; | ||||
|  | ||||
|   std::string background() {return Painter.colour["NORMAL"];} | ||||
| @@ -101,22 +104,38 @@ public: | ||||
|     name(nm), | ||||
|     topName(topNm), | ||||
|     Painter(col_class), | ||||
|     COLOUR(col) {} ; | ||||
|     timing_mode(0), | ||||
|     COLOUR(col)  | ||||
|     { | ||||
|       StopWatch = & GlobalStopWatch; | ||||
|     }; | ||||
|    | ||||
|   void Active(int on) {active = on;}; | ||||
|   int  isActive(void) {return active;}; | ||||
|   static void Timestamp(int on) {timestamp = on;}; | ||||
|   void Reset(void) {  | ||||
|     StopWatch->Reset();  | ||||
|     StopWatch->Start();  | ||||
|   } | ||||
|   void TimingMode(int on) {  | ||||
|     timing_mode = on;  | ||||
|     if(on) {  | ||||
|       StopWatch = &LocalStopWatch; | ||||
|       Reset();  | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   friend std::ostream& operator<< (std::ostream& stream, Logger& log){ | ||||
|  | ||||
|     if ( log.active ) { | ||||
|       stream << log.background()<< std::setw(8) << std::left << log.topName << log.background()<< " : "; | ||||
|       stream << log.colour() << std::setw(10) << std::left << log.name << log.background() << " : "; | ||||
|       stream << log.background()<<  std::left << log.topName << log.background()<< " : "; | ||||
|       stream << log.colour() <<  std::left << log.name << log.background() << " : "; | ||||
|       if ( log.timestamp ) { | ||||
| 	StopWatch.Stop(); | ||||
| 	GridTime now = StopWatch.Elapsed(); | ||||
| 	StopWatch.Start(); | ||||
| 	stream << log.evidence()<< now << log.background() << " : " ; | ||||
| 	log.StopWatch->Stop(); | ||||
| 	GridTime now = log.StopWatch->Elapsed(); | ||||
| 	if ( log.timing_mode==1 ) log.StopWatch->Reset(); | ||||
| 	log.StopWatch->Start(); | ||||
| 	stream << log.evidence()<< std::setw(6)<<now << log.background() << " : " ; | ||||
|       } | ||||
|       stream << log.colour(); | ||||
|       return stream; | ||||
| @@ -135,6 +154,8 @@ public: | ||||
|  | ||||
| void GridLogConfigure(std::vector<std::string> &logstreams); | ||||
|  | ||||
| extern GridLogger GridLogIRL; | ||||
| extern GridLogger GridLogSolver; | ||||
| extern GridLogger GridLogError; | ||||
| extern GridLogger GridLogWarning; | ||||
| extern GridLogger GridLogMessage; | ||||
|   | ||||
| @@ -261,7 +261,7 @@ class BinaryIO { | ||||
| 			      GridBase *grid, | ||||
| 			      std::vector<fobj> &iodata, | ||||
| 			      std::string file, | ||||
| 			      int offset, | ||||
| 			      Integer offset, | ||||
| 			      const std::string &format, int control, | ||||
| 			      uint32_t &nersc_csum, | ||||
| 			      uint32_t &scidac_csuma, | ||||
| @@ -356,7 +356,7 @@ class BinaryIO { | ||||
|  | ||||
|       if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) { | ||||
| #ifdef USE_MPI_IO | ||||
| 	std::cout<< GridLogMessage<< "MPI read I/O "<< file<< std::endl; | ||||
| 	std::cout<< GridLogMessage<<"IOobject: MPI read I/O "<< file<< std::endl; | ||||
| 	ierr=MPI_File_open(grid->communicator,(char *) file.c_str(), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);    assert(ierr==0); | ||||
| 	ierr=MPI_File_set_view(fh, disp, mpiObject, fileArray, "native", MPI_INFO_NULL);    assert(ierr==0); | ||||
| 	ierr=MPI_File_read_all(fh, &iodata[0], 1, localArray, &status);    assert(ierr==0); | ||||
| @@ -367,7 +367,7 @@ class BinaryIO { | ||||
| 	assert(0); | ||||
| #endif | ||||
|       } else { | ||||
|         std::cout << GridLogMessage << "C++ read I/O " << file << " : " | ||||
| 	std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : " | ||||
|                   << iodata.size() * sizeof(fobj) << " bytes" << std::endl; | ||||
|         std::ifstream fin; | ||||
|         fin.open(file, std::ios::binary | std::ios::in); | ||||
| @@ -413,9 +413,9 @@ class BinaryIO { | ||||
|       timer.Start(); | ||||
|       if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) { | ||||
| #ifdef USE_MPI_IO | ||||
|         std::cout << GridLogMessage << "MPI write I/O " << file << std::endl; | ||||
|         std::cout << GridLogMessage <<"IOobject: MPI write I/O " << file << std::endl; | ||||
|         ierr = MPI_File_open(grid->communicator, (char *)file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_INFO_NULL, &fh); | ||||
|         std::cout << GridLogMessage << "Checking for errors" << std::endl; | ||||
| 	//        std::cout << GridLogMessage << "Checking for errors" << std::endl; | ||||
|         if (ierr != MPI_SUCCESS) | ||||
|         { | ||||
|           char error_string[BUFSIZ]; | ||||
| @@ -445,46 +445,54 @@ class BinaryIO { | ||||
| #endif | ||||
|       } else {  | ||||
|  | ||||
| 	std::ofstream fout;  | ||||
|   fout.exceptions ( std::fstream::failbit | std::fstream::badbit ); | ||||
|   try { | ||||
|     fout.open(file,std::ios::binary|std::ios::out|std::ios::in); | ||||
|   } catch (const std::fstream::failure& exc) { | ||||
|     std::cout << GridLogError << "Error in opening the file " << file << " for output" <<std::endl; | ||||
|     std::cout << GridLogError << "Exception description: " << exc.what() << std::endl; | ||||
|     std::cout << GridLogError << "Probable cause: wrong path, inaccessible location "<< std::endl; | ||||
|     #ifdef USE_MPI_IO | ||||
|     MPI_Abort(MPI_COMM_WORLD,1); | ||||
|     #else | ||||
|     exit(1); | ||||
|     #endif | ||||
|   } | ||||
| 	std::cout << GridLogMessage<< "C++ write I/O "<< file<<" : " | ||||
| 		        << iodata.size()*sizeof(fobj)<<" bytes"<<std::endl; | ||||
|         std::cout << GridLogMessage << "IOobject: C++ write I/O " << file << " : " | ||||
|                   << iodata.size() * sizeof(fobj) << " bytes" << std::endl; | ||||
|          | ||||
|   if ( control & BINARYIO_MASTER_APPEND )  { | ||||
| 	  fout.seekp(0,fout.end); | ||||
| 	} else { | ||||
| 	  fout.seekp(offset+myrank*lsites*sizeof(fobj)); | ||||
| 	std::ofstream fout;  | ||||
| 	fout.exceptions ( std::fstream::failbit | std::fstream::badbit ); | ||||
| 	try { | ||||
| 	  fout.open(file,std::ios::binary|std::ios::out|std::ios::in); | ||||
| 	} catch (const std::fstream::failure& exc) { | ||||
| 	  std::cout << GridLogError << "Error in opening the file " << file << " for output" <<std::endl; | ||||
| 	  std::cout << GridLogError << "Exception description: " << exc.what() << std::endl; | ||||
| 	  std::cout << GridLogError << "Probable cause: wrong path, inaccessible location "<< std::endl; | ||||
| #ifdef USE_MPI_IO | ||||
| 	  MPI_Abort(MPI_COMM_WORLD,1); | ||||
| #else | ||||
| 	  exit(1); | ||||
| #endif | ||||
| 	} | ||||
| 	 | ||||
|   try { | ||||
|   	fout.write((char *)&iodata[0],iodata.size()*sizeof(fobj));//assert( fout.fail()==0); | ||||
|   } | ||||
|   catch (const std::fstream::failure& exc) { | ||||
|     std::cout << "Exception in writing file " << file << std::endl; | ||||
|     std::cout << GridLogError << "Exception description: "<< exc.what() << std::endl; | ||||
|     #ifdef USE_MPI_IO | ||||
|     MPI_Abort(MPI_COMM_WORLD,1); | ||||
|     #else | ||||
|     exit(1); | ||||
|     #endif | ||||
|   } | ||||
| 	if ( control & BINARYIO_MASTER_APPEND )  { | ||||
| 	  try { | ||||
| 	    fout.seekp(0,fout.end); | ||||
| 	  } catch (const std::fstream::failure& exc) { | ||||
| 	    std::cout << "Exception in seeking file end " << file << std::endl; | ||||
| 	  } | ||||
| 	} else { | ||||
| 	  try {  | ||||
| 	    fout.seekp(offset+myrank*lsites*sizeof(fobj)); | ||||
| 	  } catch (const std::fstream::failure& exc) { | ||||
| 	    std::cout << "Exception in seeking file " << file <<" offset "<< offset << std::endl; | ||||
| 	  } | ||||
| 	} | ||||
|  | ||||
| 	try { | ||||
| 	  fout.write((char *)&iodata[0],iodata.size()*sizeof(fobj));//assert( fout.fail()==0); | ||||
| 	} | ||||
| 	catch (const std::fstream::failure& exc) { | ||||
| 	  std::cout << "Exception in writing file " << file << std::endl; | ||||
| 	  std::cout << GridLogError << "Exception description: "<< exc.what() << std::endl; | ||||
| #ifdef USE_MPI_IO | ||||
| 	  MPI_Abort(MPI_COMM_WORLD,1); | ||||
| #else | ||||
| 	  exit(1); | ||||
| #endif | ||||
| 	} | ||||
| 	fout.close(); | ||||
|   } | ||||
|   timer.Stop(); | ||||
|   } | ||||
|       } | ||||
|       timer.Stop(); | ||||
|     } | ||||
|      | ||||
|     std::cout<<GridLogMessage<<"IOobject: "; | ||||
|     if ( control & BINARYIO_READ) std::cout << " read  "; | ||||
| @@ -515,7 +523,7 @@ class BinaryIO { | ||||
|   static inline void readLatticeObject(Lattice<vobj> &Umu, | ||||
| 				       std::string file, | ||||
| 				       munger munge, | ||||
| 				       int offset, | ||||
| 				       Integer offset, | ||||
| 				       const std::string &format, | ||||
| 				       uint32_t &nersc_csum, | ||||
| 				       uint32_t &scidac_csuma, | ||||
| @@ -552,7 +560,7 @@ class BinaryIO { | ||||
|     static inline void writeLatticeObject(Lattice<vobj> &Umu, | ||||
| 					  std::string file, | ||||
| 					  munger munge, | ||||
| 					  int offset, | ||||
| 					  Integer offset, | ||||
| 					  const std::string &format, | ||||
| 					  uint32_t &nersc_csum, | ||||
| 					  uint32_t &scidac_csuma, | ||||
| @@ -589,7 +597,7 @@ class BinaryIO { | ||||
|   static inline void readRNG(GridSerialRNG &serial, | ||||
| 			     GridParallelRNG ¶llel, | ||||
| 			     std::string file, | ||||
| 			     int offset, | ||||
| 			     Integer offset, | ||||
| 			     uint32_t &nersc_csum, | ||||
| 			     uint32_t &scidac_csuma, | ||||
| 			     uint32_t &scidac_csumb) | ||||
| @@ -651,7 +659,7 @@ class BinaryIO { | ||||
|   static inline void writeRNG(GridSerialRNG &serial, | ||||
| 			      GridParallelRNG ¶llel, | ||||
| 			      std::string file, | ||||
| 			      int offset, | ||||
| 			      Integer offset, | ||||
| 			      uint32_t &nersc_csum, | ||||
| 			      uint32_t &scidac_csuma, | ||||
| 			      uint32_t &scidac_csumb) | ||||
|   | ||||
| @@ -84,10 +84,6 @@ namespace QCD { | ||||
|    stream << "GRID_"; | ||||
|    stream << ScidacWordMnemonic<stype>(); | ||||
|  | ||||
|    //   std::cout << " Lorentz N/S/V/M : " << _LorentzN<<" "<<_LorentzScalar<<"/"<<_LorentzVector<<"/"<<_LorentzMatrix<<std::endl; | ||||
|    //   std::cout << " Spin    N/S/V/M : " << _SpinN   <<" "<<_SpinScalar   <<"/"<<_SpinVector   <<"/"<<_SpinMatrix<<std::endl; | ||||
|    //   std::cout << " Colour  N/S/V/M : " << _ColourN <<" "<<_ColourScalar <<"/"<<_ColourVector <<"/"<<_ColourMatrix<<std::endl; | ||||
|  | ||||
|    if ( _LorentzVector )   stream << "_LorentzVector"<<_LorentzN; | ||||
|    if ( _LorentzMatrix )   stream << "_LorentzMatrix"<<_LorentzN; | ||||
|  | ||||
| @@ -151,7 +147,7 @@ namespace QCD { | ||||
|  | ||||
|    _scidacRecord = sr; | ||||
|  | ||||
|    std::cout << GridLogMessage << "Build SciDAC datatype " <<sr.datatype<<std::endl; | ||||
|    //   std::cout << GridLogMessage << "Build SciDAC datatype " <<sr.datatype<<std::endl; | ||||
|  } | ||||
|   | ||||
|  /////////////////////////////////////////////////////// | ||||
| @@ -163,7 +159,7 @@ namespace QCD { | ||||
|    uint32_t scidac_checksumb = stoull(scidacChecksum_.sumb,0,16); | ||||
|    if ( scidac_csuma !=scidac_checksuma) return 0; | ||||
|    if ( scidac_csumb !=scidac_checksumb) return 0; | ||||
|     return 1; | ||||
|    return 1; | ||||
|  } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -182,7 +178,7 @@ class GridLimeReader : public BinaryIO { | ||||
|    ///////////////////////////////////////////// | ||||
|    // Open the file | ||||
|    ///////////////////////////////////////////// | ||||
|    void open(std::string &_filename)  | ||||
|    void open(const std::string &_filename)  | ||||
|    { | ||||
|      filename= _filename; | ||||
|      File = fopen(filename.c_str(), "r"); | ||||
| @@ -210,24 +206,38 @@ class GridLimeReader : public BinaryIO { | ||||
|  | ||||
|     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||
|  | ||||
|       std::cout << GridLogMessage << limeReaderType(LimeR) <<std::endl; | ||||
|       uint64_t file_bytes =limeReaderBytes(LimeR); | ||||
|  | ||||
|       if ( strncmp(limeReaderType(LimeR), record_name.c_str(),strlen(record_name.c_str()) )  ) { | ||||
|       //      std::cout << GridLogMessage << limeReaderType(LimeR) << " "<< file_bytes <<" bytes "<<std::endl; | ||||
|       //      std::cout << GridLogMessage<< " readLimeObject seeking "<<  record_name <<" found record :" <<limeReaderType(LimeR) <<std::endl; | ||||
|  | ||||
|       if ( !strncmp(limeReaderType(LimeR), record_name.c_str(),strlen(record_name.c_str()) )  ) { | ||||
|  | ||||
| 	off_t offset= ftell(File); | ||||
| 	//	std::cout << GridLogMessage<< " readLimeLatticeBinaryObject matches ! " <<std::endl; | ||||
|  | ||||
| 	uint64_t PayloadSize = sizeof(sobj) * field._grid->_gsites; | ||||
|  | ||||
| 	//	std::cout << "R sizeof(sobj)= " <<sizeof(sobj)<<std::endl; | ||||
| 	//	std::cout << "R Gsites " <<field._grid->_gsites<<std::endl; | ||||
| 	//	std::cout << "R Payload expected " <<PayloadSize<<std::endl; | ||||
| 	//	std::cout << "R file size " <<file_bytes <<std::endl; | ||||
|  | ||||
| 	assert(PayloadSize == file_bytes);// Must match or user error | ||||
|  | ||||
| 	uint64_t offset= ftello(File); | ||||
| 	//	std::cout << " ReadLatticeObject from offset "<<offset << std::endl; | ||||
| 	BinarySimpleMunger<sobj,sobj> munge; | ||||
| 	BinaryIO::readLatticeObject< sobj, sobj >(field, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||
| 	BinaryIO::readLatticeObject< vobj, sobj >(field, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||
|  | ||||
| 	///////////////////////////////////////////// | ||||
| 	// Insist checksum is next record | ||||
| 	///////////////////////////////////////////// | ||||
| 	readLimeObject(scidacChecksum_,std::string("scidacChecksum"),record_name); | ||||
| 	readLimeObject(scidacChecksum_,std::string("scidacChecksum"),std::string(SCIDAC_CHECKSUM)); | ||||
|  | ||||
| 	///////////////////////////////////////////// | ||||
| 	// Verify checksums | ||||
| 	///////////////////////////////////////////// | ||||
| 	scidacChecksumVerify(scidacChecksum_,scidac_csuma,scidac_csumb); | ||||
| 	assert(scidacChecksumVerify(scidacChecksum_,scidac_csuma,scidac_csumb)==1); | ||||
| 	return; | ||||
|       } | ||||
|     } | ||||
| @@ -242,11 +252,16 @@ class GridLimeReader : public BinaryIO { | ||||
|     // should this be a do while; can we miss a first record?? | ||||
|     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||
|  | ||||
|       //      std::cout << GridLogMessage<< " readLimeObject seeking "<< record_name <<" found record :" <<limeReaderType(LimeR) <<std::endl; | ||||
|       uint64_t nbytes = limeReaderBytes(LimeR);//size of this record (configuration) | ||||
|  | ||||
|       if ( strncmp(limeReaderType(LimeR), record_name.c_str(),strlen(record_name.c_str()) )  ) { | ||||
|       if ( !strncmp(limeReaderType(LimeR), record_name.c_str(),strlen(record_name.c_str()) )  ) { | ||||
|  | ||||
| 	//	std::cout << GridLogMessage<< " readLimeObject matches ! " << record_name <<std::endl; | ||||
| 	std::vector<char> xmlc(nbytes+1,'\0'); | ||||
| 	limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);     | ||||
| 	//	std::cout << GridLogMessage<< " readLimeObject matches XML " << &xmlc[0] <<std::endl; | ||||
|  | ||||
| 	XmlReader RD(&xmlc[0],""); | ||||
| 	read(RD,object_name,object); | ||||
| 	return; | ||||
| @@ -261,13 +276,14 @@ class GridLimeWriter : public BinaryIO { | ||||
|  public: | ||||
|    /////////////////////////////////////////////////// | ||||
|    // FIXME: format for RNG? Now just binary out instead | ||||
|    // FIXME: collective calls or not ? | ||||
|    //      : must know if I am the I/O boss | ||||
|    /////////////////////////////////////////////////// | ||||
|  | ||||
|    FILE       *File; | ||||
|    LimeWriter *LimeW; | ||||
|    std::string filename; | ||||
|  | ||||
|    void open(std::string &_filename) {  | ||||
|    void open(const std::string &_filename) {  | ||||
|      filename= _filename; | ||||
|      File = fopen(filename.c_str(), "w"); | ||||
|      LimeW = limeCreateWriter(File); assert(LimeW != NULL ); | ||||
| @@ -302,14 +318,18 @@ class GridLimeWriter : public BinaryIO { | ||||
|       write(WR,object_name,object); | ||||
|       xmlstring = WR.XmlString(); | ||||
|     } | ||||
|     //    std::cout << "WriteLimeObject" << record_name <<std::endl; | ||||
|     uint64_t nbytes = xmlstring.size(); | ||||
|     //    std::cout << " xmlstring "<< nbytes<< " " << xmlstring <<std::endl; | ||||
|     int err; | ||||
|     LimeRecordHeader *h = limeCreateHeader(MB, ME,(char *)record_name.c_str(), nbytes); assert(h!= NULL); | ||||
|     LimeRecordHeader *h = limeCreateHeader(MB, ME,const_cast<char *>(record_name.c_str()), nbytes);  | ||||
|     assert(h!= NULL); | ||||
|  | ||||
|     err=limeWriteRecordHeader(h, LimeW);                    assert(err>=0); | ||||
|     err=limeWriteRecordData(&xmlstring[0], &nbytes, LimeW); assert(err>=0); | ||||
|     err=limeWriterCloseRecord(LimeW);                       assert(err>=0); | ||||
|     limeDestroyHeader(h); | ||||
|     //    std::cout << " File offset is now"<<ftello(File) << std::endl; | ||||
|   } | ||||
|   //////////////////////////////////////////// | ||||
|   // Write a generic lattice field and csum | ||||
| @@ -326,6 +346,10 @@ class GridLimeWriter : public BinaryIO { | ||||
|     uint64_t PayloadSize = sizeof(sobj) * field._grid->_gsites; | ||||
|     createLimeRecordHeader(record_name, 0, 0, PayloadSize); | ||||
|  | ||||
|     //    std::cout << "W sizeof(sobj)"      <<sizeof(sobj)<<std::endl; | ||||
|     //    std::cout << "W Gsites "           <<field._grid->_gsites<<std::endl; | ||||
|     //    std::cout << "W Payload expected " <<PayloadSize<<std::endl; | ||||
|  | ||||
|     //////////////////////////////////////////////////////////////////// | ||||
|     // NB: FILE and iostream are jointly writing disjoint sequences in the | ||||
|     // the same file through different file handles (integer units). | ||||
| @@ -333,17 +357,20 @@ class GridLimeWriter : public BinaryIO { | ||||
|     // These are both buffered, so why I think this code is right is as follows. | ||||
|     // | ||||
|     // i)  write record header to FILE *File, telegraphing the size.  | ||||
|     // ii) ftell reads the offset from FILE *File . | ||||
|     // ii) ftello reads the offset from FILE *File . | ||||
|     // iii) iostream / MPI Open independently seek this offset. Write sequence direct to disk. | ||||
|     //      Closes iostream and flushes. | ||||
|     // iv) fseek on FILE * to end of this disjoint section. | ||||
|     //  v) Continue writing scidac record. | ||||
|     //////////////////////////////////////////////////////////////////// | ||||
|     off_t offset = ftell(File); | ||||
|     uint64_t offset = ftello(File); | ||||
|     //    std::cout << " Writing to offset "<<offset << std::endl; | ||||
|     std::string format = getFormatString<vobj>(); | ||||
|     BinarySimpleMunger<sobj,sobj> munge; | ||||
|     BinaryIO::writeLatticeObject<vobj,sobj>(field, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||
|     //    fseek(File,0,SEEK_END);    offset = ftello(File);std::cout << " offset now "<<offset << std::endl; | ||||
|     err=limeWriterCloseRecord(LimeW);  assert(err>=0); | ||||
|  | ||||
|     //////////////////////////////////////// | ||||
|     // Write checksum element, propagaing forward from the BinaryIO | ||||
|     // Always pair a checksum with a binary object, and close message | ||||
| @@ -353,8 +380,8 @@ class GridLimeWriter : public BinaryIO { | ||||
|     std::stringstream streamb; streamb << std::hex << scidac_csumb; | ||||
|     checksum.suma= streama.str(); | ||||
|     checksum.sumb= streamb.str(); | ||||
|     std::cout << GridLogMessage<<" writing scidac checksums "<<std::hex<<scidac_csuma<<"/"<<scidac_csumb<<std::dec<<std::endl; | ||||
|     writeLimeObject(0,1,checksum,std::string("scidacChecksum"    ),std::string(SCIDAC_CHECKSUM)); | ||||
|     //    std::cout << GridLogMessage<<" writing scidac checksums "<<std::hex<<scidac_csuma<<"/"<<scidac_csumb<<std::dec<<std::endl; | ||||
|     writeLimeObject(0,1,checksum,std::string("scidacChecksum"),std::string(SCIDAC_CHECKSUM)); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @@ -371,11 +398,9 @@ class ScidacWriter : public GridLimeWriter { | ||||
|   //////////////////////////////////////////////// | ||||
|   // Write generic lattice field in scidac format | ||||
|   //////////////////////////////////////////////// | ||||
|    template <class vobj, class userRecord> | ||||
|   template <class vobj, class userRecord> | ||||
|   void writeScidacFieldRecord(Lattice<vobj> &field,userRecord _userRecord)  | ||||
|   { | ||||
|     typedef typename vobj::scalar_object sobj; | ||||
|     uint64_t nbytes; | ||||
|     GridBase * grid = field._grid; | ||||
|  | ||||
|     //////////////////////////////////////// | ||||
| @@ -397,6 +422,66 @@ class ScidacWriter : public GridLimeWriter { | ||||
|   } | ||||
| }; | ||||
|  | ||||
|  | ||||
| class ScidacReader : public GridLimeReader { | ||||
|  public: | ||||
|  | ||||
|    template<class SerialisableUserFile> | ||||
|    void readScidacFileRecord(GridBase *grid,SerialisableUserFile &_userFile) | ||||
|    { | ||||
|      scidacFile    _scidacFile(grid); | ||||
|      readLimeObject(_scidacFile,_scidacFile.SerialisableClassName(),std::string(SCIDAC_PRIVATE_FILE_XML)); | ||||
|      readLimeObject(_userFile,_userFile.SerialisableClassName(),std::string(SCIDAC_FILE_XML)); | ||||
|    } | ||||
|   //////////////////////////////////////////////// | ||||
|   // Write generic lattice field in scidac format | ||||
|   //////////////////////////////////////////////// | ||||
|   template <class vobj, class userRecord> | ||||
|   void readScidacFieldRecord(Lattice<vobj> &field,userRecord &_userRecord)  | ||||
|   { | ||||
|     typedef typename vobj::scalar_object sobj; | ||||
|     GridBase * grid = field._grid; | ||||
|  | ||||
|     //////////////////////////////////////// | ||||
|     // fill the Grid header | ||||
|     //////////////////////////////////////// | ||||
|     FieldMetaData header; | ||||
|     scidacRecord  _scidacRecord; | ||||
|     scidacFile    _scidacFile; | ||||
|  | ||||
|     ////////////////////////////////////////////// | ||||
|     // Fill the Lime file record by record | ||||
|     ////////////////////////////////////////////// | ||||
|     readLimeObject(header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message  | ||||
|     readLimeObject(_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML)); | ||||
|     readLimeObject(_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML)); | ||||
|     readLimeLatticeBinaryObject(field,std::string(ILDG_BINARY_DATA)); | ||||
|   } | ||||
|   void skipPastBinaryRecord(void) { | ||||
|     std::string rec_name(ILDG_BINARY_DATA); | ||||
|     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||
|       if ( !strncmp(limeReaderType(LimeR), rec_name.c_str(),strlen(rec_name.c_str()) )  ) { | ||||
| 	skipPastObjectRecord(std::string(SCIDAC_CHECKSUM)); | ||||
| 	return; | ||||
|       } | ||||
|     }     | ||||
|   } | ||||
|   void skipPastObjectRecord(std::string rec_name) { | ||||
|     while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) {  | ||||
|       if ( !strncmp(limeReaderType(LimeR), rec_name.c_str(),strlen(rec_name.c_str()) )  ) { | ||||
| 	return; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   void skipScidacFieldRecord() { | ||||
|     skipPastObjectRecord(std::string(GRID_FORMAT)); | ||||
|     skipPastObjectRecord(std::string(SCIDAC_RECORD_XML)); | ||||
|     skipPastObjectRecord(std::string(SCIDAC_PRIVATE_RECORD_XML)); | ||||
|     skipPastBinaryRecord(); | ||||
|   } | ||||
| }; | ||||
|  | ||||
|  | ||||
| class IldgWriter : public ScidacWriter { | ||||
|  public: | ||||
|  | ||||
| @@ -425,8 +510,6 @@ class IldgWriter : public ScidacWriter { | ||||
|     typedef iLorentzColourMatrix<vsimd> vobj; | ||||
|     typedef typename vobj::scalar_object sobj; | ||||
|  | ||||
|     uint64_t nbytes; | ||||
|  | ||||
|     //////////////////////////////////////// | ||||
|     // fill the Grid header | ||||
|     //////////////////////////////////////// | ||||
| @@ -557,7 +640,7 @@ class IldgReader : public GridLimeReader { | ||||
| 	// Copy out the string | ||||
| 	std::vector<char> xmlc(nbytes+1,'\0'); | ||||
| 	limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR);     | ||||
| 	std::cout << GridLogMessage<< "Non binary record :" <<limeReaderType(LimeR) <<std::endl; //<<"\n"<<(&xmlc[0])<<std::endl; | ||||
| 	//	std::cout << GridLogMessage<< "Non binary record :" <<limeReaderType(LimeR) <<std::endl; //<<"\n"<<(&xmlc[0])<<std::endl; | ||||
|  | ||||
| 	////////////////////////////////// | ||||
| 	// ILDG format record | ||||
| @@ -601,7 +684,7 @@ class IldgReader : public GridLimeReader { | ||||
| 	  std::string xmls(&xmlc[0]); | ||||
| 	  // is it a USQCD info field | ||||
| 	  if ( xmls.find(std::string("usqcdInfo")) != std::string::npos ) {  | ||||
| 	    std::cout << GridLogMessage<<"...found a usqcdInfo field"<<std::endl; | ||||
| 	    //	    std::cout << GridLogMessage<<"...found a usqcdInfo field"<<std::endl; | ||||
| 	    XmlReader RD(&xmlc[0],""); | ||||
| 	    read(RD,"usqcdInfo",usqcdInfo_); | ||||
| 	    found_usqcdInfo = 1; | ||||
| @@ -619,8 +702,7 @@ class IldgReader : public GridLimeReader { | ||||
| 	// Binary data | ||||
| 	///////////////////////////////// | ||||
| 	std::cout << GridLogMessage << "ILDG Binary record found : "  ILDG_BINARY_DATA << std::endl; | ||||
| 	off_t offset= ftell(File); | ||||
|  | ||||
| 	uint64_t offset= ftello(File); | ||||
| 	if ( format == std::string("IEEE64BIG") ) { | ||||
| 	  GaugeSimpleMunger<dobj, sobj> munge; | ||||
| 	  BinaryIO::readLatticeObject< vobj, dobj >(Umu, filename, munge, offset, format,nersc_csum,scidac_csuma,scidac_csumb); | ||||
|   | ||||
| @@ -64,6 +64,11 @@ namespace Grid { | ||||
| // file compatability, so should be correct to assume the undocumented but defacto file structure. | ||||
| ///////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| struct emptyUserRecord : Serializable {  | ||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(emptyUserRecord,int,dummy); | ||||
|   emptyUserRecord() { dummy=0; }; | ||||
| }; | ||||
|  | ||||
| //////////////////////// | ||||
| // Scidac private file xml | ||||
| // <?xml version="1.0" encoding="UTF-8"?><scidacFile><version>1.1</version><spacetime>4</spacetime><dims>16 16 16 32 </dims><volfmt>0</volfmt></scidacFile> | ||||
|   | ||||
| @@ -85,6 +85,9 @@ namespace Grid { | ||||
| 	nd=4; | ||||
| 	dimension.resize(4); | ||||
| 	boundary.resize(4); | ||||
| 	scidac_checksuma=0; | ||||
| 	scidac_checksumb=0; | ||||
| 	checksum=0; | ||||
|       } | ||||
|     }; | ||||
|  | ||||
| @@ -104,6 +107,7 @@ namespace Grid { | ||||
|       header.nd = nd; | ||||
|       header.dimension.resize(nd); | ||||
|       header.boundary.resize(nd); | ||||
|       header.data_start = 0; | ||||
|       for(int d=0;d<nd;d++) { | ||||
| 	header.dimension[d] = grid->_fdimensions[d]; | ||||
|       } | ||||
|   | ||||
							
								
								
									
										100
									
								
								lib/qcd/action/fermion/AbstractEOFAFermion.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								lib/qcd/action/fermion/AbstractEOFAFermion.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/AbstractEOFAFermion.h | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| 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 */ | ||||
| #ifndef  GRID_QCD_ABSTRACT_EOFA_FERMION_H | ||||
| #define  GRID_QCD_ABSTRACT_EOFA_FERMION_H | ||||
|  | ||||
| #include <Grid/qcd/action/fermion/CayleyFermion5D.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   // DJM: Abstract base class for EOFA fermion types. | ||||
|   // Defines layout of additional EOFA-specific parameters and operators. | ||||
|   // Use to construct EOFA pseudofermion actions that are agnostic to | ||||
|   // Shamir / Mobius / etc., and ensure that no one can construct EOFA | ||||
|   // pseudofermion action with non-EOFA fermion type. | ||||
|   template<class Impl> | ||||
|   class AbstractEOFAFermion : public CayleyFermion5D<Impl> { | ||||
|     public: | ||||
|       INHERIT_IMPL_TYPES(Impl); | ||||
|  | ||||
|     public: | ||||
|       // Fermion operator: D(mq1) + shift*\gamma_{5}*R_{5}*\Delta_{\pm}(mq2,mq3)*P_{\pm} | ||||
|       RealD mq1; | ||||
|       RealD mq2; | ||||
|       RealD mq3; | ||||
|       RealD shift; | ||||
|       int pm; | ||||
|  | ||||
|       RealD alpha; // Mobius scale | ||||
|       RealD k;     // EOFA normalization constant | ||||
|  | ||||
|       virtual void Instantiatable(void) = 0; | ||||
|  | ||||
|       // EOFA-specific operations | ||||
|       // Force user to implement in derived classes | ||||
|       virtual void  Omega    (const FermionField& in, FermionField& out, int sign, int dag) = 0; | ||||
|       virtual void  Dtilde   (const FermionField& in, FermionField& out) = 0; | ||||
|       virtual void  DtildeInv(const FermionField& in, FermionField& out) = 0; | ||||
|  | ||||
|       // Implement derivatives in base class: | ||||
|       // for EOFA both DWF and Mobius just need d(Dw)/dU | ||||
|       virtual void MDeriv(GaugeField& mat, const FermionField& U, const FermionField& V, int dag){ | ||||
|         this->DhopDeriv(mat, U, V, dag); | ||||
|       }; | ||||
|       virtual void MoeDeriv(GaugeField& mat, const FermionField& U, const FermionField& V, int dag){ | ||||
|         this->DhopDerivOE(mat, U, V, dag); | ||||
|       }; | ||||
|       virtual void MeoDeriv(GaugeField& mat, const FermionField& U, const FermionField& V, int dag){ | ||||
|         this->DhopDerivEO(mat, U, V, dag); | ||||
|       }; | ||||
|  | ||||
|       // Recompute 5D coefficients for different value of shift constant | ||||
|       // (needed for heatbath loop over poles) | ||||
|       virtual void RefreshShiftCoefficients(RealD new_shift) = 0; | ||||
|  | ||||
|       // Constructors | ||||
|       AbstractEOFAFermion(GaugeField& _Umu, GridCartesian& FiveDimGrid, GridRedBlackCartesian& FiveDimRedBlackGrid, | ||||
|         GridCartesian& FourDimGrid, GridRedBlackCartesian& FourDimRedBlackGrid, | ||||
|         RealD _mq1, RealD _mq2, RealD _mq3, RealD _shift, int _pm, | ||||
|         RealD _M5, RealD _b, RealD _c, const ImplParams& p=ImplParams()) | ||||
|         : CayleyFermion5D<Impl>(_Umu, FiveDimGrid, FiveDimRedBlackGrid, FourDimGrid, FourDimRedBlackGrid, | ||||
|           _mq1, _M5, p), mq1(_mq1), mq2(_mq2), mq3(_mq3), shift(_shift), pm(_pm) | ||||
|       { | ||||
|         int Ls = this->Ls; | ||||
|         this->alpha = _b + _c; | ||||
|         this->k = this->alpha * (_mq3-_mq2) * std::pow(this->alpha+1.0,2*Ls) / | ||||
|                     ( std::pow(this->alpha+1.0,Ls) + _mq2*std::pow(this->alpha-1.0,Ls) ) / | ||||
|                     ( std::pow(this->alpha+1.0,Ls) + _mq3*std::pow(this->alpha-1.0,Ls) ); | ||||
|       }; | ||||
|   }; | ||||
| }} | ||||
|  | ||||
| #endif | ||||
| @@ -77,7 +77,6 @@ void CayleyFermion5D<Impl>::DminusDag(const FermionField &psi, FermionField &chi | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class Impl> void CayleyFermion5D<Impl>::CayleyReport(void) | ||||
| { | ||||
|   this->Report(); | ||||
| @@ -119,7 +118,6 @@ template<class Impl> void CayleyFermion5D<Impl>::CayleyZeroCounters(void) | ||||
|   MooeeInvTime=0; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class Impl>   | ||||
| void CayleyFermion5D<Impl>::M5D   (const FermionField &psi, FermionField &chi) | ||||
| { | ||||
|   | ||||
| @@ -179,9 +179,9 @@ namespace Grid { | ||||
|      double MooeeInvTime; | ||||
|  | ||||
|     protected: | ||||
|       void SetCoefficientsZolotarev(RealD zolohi,Approx::zolotarev_data *zdata,RealD b,RealD c); | ||||
|       void SetCoefficientsTanh(Approx::zolotarev_data *zdata,RealD b,RealD c); | ||||
|       void SetCoefficientsInternal(RealD zolo_hi,std::vector<Coeff_t> & gamma,RealD b,RealD c); | ||||
|       virtual void SetCoefficientsZolotarev(RealD zolohi,Approx::zolotarev_data *zdata,RealD b,RealD c); | ||||
|       virtual void SetCoefficientsTanh(Approx::zolotarev_data *zdata,RealD b,RealD c); | ||||
|       virtual void SetCoefficientsInternal(RealD zolo_hi,std::vector<Coeff_t> & gamma,RealD b,RealD c); | ||||
|     }; | ||||
|  | ||||
|   } | ||||
|   | ||||
							
								
								
									
										438
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermion.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										438
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermion.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,438 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/DomainWallEOFAFermion.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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_Eigen_Dense.h> | ||||
| #include <Grid/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|     template<class Impl> | ||||
|     DomainWallEOFAFermion<Impl>::DomainWallEOFAFermion( | ||||
|       GaugeField            &_Umu, | ||||
|       GridCartesian         &FiveDimGrid, | ||||
|       GridRedBlackCartesian &FiveDimRedBlackGrid, | ||||
|       GridCartesian         &FourDimGrid, | ||||
|       GridRedBlackCartesian &FourDimRedBlackGrid, | ||||
|       RealD _mq1, RealD _mq2, RealD _mq3, | ||||
|       RealD _shift, int _pm, RealD _M5, const ImplParams &p) : | ||||
|     AbstractEOFAFermion<Impl>(_Umu, FiveDimGrid, FiveDimRedBlackGrid, | ||||
|         FourDimGrid, FourDimRedBlackGrid, _mq1, _mq2, _mq3, | ||||
|         _shift, _pm, _M5, 1.0, 0.0, p) | ||||
|     { | ||||
|         RealD eps = 1.0; | ||||
|         Approx::zolotarev_data *zdata = Approx::higham(eps,this->Ls); | ||||
|         assert(zdata->n == this->Ls); | ||||
|  | ||||
|         std::cout << GridLogMessage << "DomainWallEOFAFermion with Ls=" << this->Ls << std::endl; | ||||
|         this->SetCoefficientsTanh(zdata, 1.0, 0.0); | ||||
|  | ||||
|         Approx::zolotarev_free(zdata); | ||||
|     } | ||||
|  | ||||
|     /*************************************************************** | ||||
|      * Additional EOFA operators only called outside the inverter. | ||||
|      * Since speed is not essential, simple axpby-style | ||||
|      * implementations should be fine. | ||||
|      ***************************************************************/ | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::Omega(const FermionField& psi, FermionField& Din, int sign, int dag) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         Din = zero; | ||||
|         if((sign == 1) && (dag == 0)){ axpby_ssp(Din, 0.0, psi, 1.0, psi, Ls-1, 0); } | ||||
|         else if((sign == -1) && (dag == 0)){ axpby_ssp(Din, 0.0, psi, 1.0, psi, 0, 0); } | ||||
|         else if((sign == 1 ) && (dag == 1)){ axpby_ssp(Din, 0.0, psi, 1.0, psi, 0, Ls-1); } | ||||
|         else if((sign == -1) && (dag == 1)){ axpby_ssp(Din, 0.0, psi, 1.0, psi, 0, 0); } | ||||
|     } | ||||
|  | ||||
|     // This is just the identity for DWF | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::Dtilde(const FermionField& psi, FermionField& chi){ chi = psi; } | ||||
|  | ||||
|     // This is just the identity for DWF | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::DtildeInv(const FermionField& psi, FermionField& chi){ chi = psi; } | ||||
|  | ||||
|     /*****************************************************************************************************/ | ||||
|  | ||||
|     template<class Impl> | ||||
|     RealD DomainWallEOFAFermion<Impl>::M(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         FermionField Din(psi._grid); | ||||
|  | ||||
|         this->Meooe5D(psi, Din); | ||||
|         this->DW(Din, chi, DaggerNo); | ||||
|         axpby(chi, 1.0, 1.0, chi, psi); | ||||
|         this->M5D(psi, chi); | ||||
|         return(norm2(chi)); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     RealD DomainWallEOFAFermion<Impl>::Mdag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         FermionField Din(psi._grid); | ||||
|  | ||||
|         this->DW(psi, Din, DaggerYes); | ||||
|         this->MeooeDag5D(Din, chi); | ||||
|         this->M5Ddag(psi, chi); | ||||
|         axpby(chi, 1.0, 1.0, chi, psi); | ||||
|         return(norm2(chi)); | ||||
|     } | ||||
|  | ||||
|     /******************************************************************** | ||||
|      * Performance critical fermion operators called inside the inverter | ||||
|      ********************************************************************/ | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5D(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         int   Ls    = this->Ls; | ||||
|         int   pm    = this->pm; | ||||
|         RealD shift = this->shift; | ||||
|         RealD mq1   = this->mq1; | ||||
|         RealD mq2   = this->mq2; | ||||
|         RealD mq3   = this->mq3; | ||||
|  | ||||
|         // coefficients for shift operator ( = shift*\gamma_{5}*R_{5}*\Delta_{\pm}(mq2,mq3)*P_{\pm} ) | ||||
|         Coeff_t shiftp(0.0), shiftm(0.0); | ||||
|         if(shift != 0.0){ | ||||
|           if(pm == 1){ shiftp = shift*(mq3-mq2); } | ||||
|           else{ shiftm = -shift*(mq3-mq2); } | ||||
|         } | ||||
|  | ||||
|         std::vector<Coeff_t> diag(Ls,1.0); | ||||
|         std::vector<Coeff_t> upper(Ls,-1.0); upper[Ls-1] = mq1 + shiftm; | ||||
|         std::vector<Coeff_t> lower(Ls,-1.0); lower[0]    = mq1 + shiftp; | ||||
|  | ||||
|         #if(0) | ||||
|             std::cout << GridLogMessage << "DomainWallEOFAFermion::M5D(FF&,FF&):" << std::endl; | ||||
|             for(int i=0; i<diag.size(); ++i){ | ||||
|                 std::cout << GridLogMessage << "diag[" << i << "] =" << diag[i] << std::endl; | ||||
|             } | ||||
|             for(int i=0; i<upper.size(); ++i){ | ||||
|                 std::cout << GridLogMessage << "upper[" << i << "] =" << upper[i] << std::endl; | ||||
|             } | ||||
|             for(int i=0; i<lower.size(); ++i){ | ||||
|                 std::cout << GridLogMessage << "lower[" << i << "] =" << lower[i] << std::endl; | ||||
|             } | ||||
|         #endif | ||||
|  | ||||
|         this->M5D(psi, chi, chi, lower, diag, upper); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5Ddag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         int   Ls    = this->Ls; | ||||
|         int   pm    = this->pm; | ||||
|         RealD shift = this->shift; | ||||
|         RealD mq1   = this->mq1; | ||||
|         RealD mq2   = this->mq2; | ||||
|         RealD mq3   = this->mq3; | ||||
|  | ||||
|         // coefficients for shift operator ( = shift*\gamma_{5}*R_{5}*\Delta_{\pm}(mq2,mq3)*P_{\pm} ) | ||||
|         Coeff_t shiftp(0.0), shiftm(0.0); | ||||
|         if(shift != 0.0){ | ||||
|           if(pm == 1){ shiftp = shift*(mq3-mq2); } | ||||
|           else{ shiftm = -shift*(mq3-mq2); } | ||||
|         } | ||||
|  | ||||
|         std::vector<Coeff_t> diag(Ls,1.0); | ||||
|         std::vector<Coeff_t> upper(Ls,-1.0); upper[Ls-1] = mq1 + shiftp; | ||||
|         std::vector<Coeff_t> lower(Ls,-1.0); lower[0]    = mq1 + shiftm; | ||||
|  | ||||
|         #if(0) | ||||
|             std::cout << GridLogMessage << "DomainWallEOFAFermion::M5Ddag(FF&,FF&):" << std::endl; | ||||
|             for(int i=0; i<diag.size(); ++i){ | ||||
|                 std::cout << GridLogMessage << "diag[" << i << "] =" << diag[i] << std::endl; | ||||
|             } | ||||
|             for(int i=0; i<upper.size(); ++i){ | ||||
|                 std::cout << GridLogMessage << "upper[" << i << "] =" << upper[i] << std::endl; | ||||
|             } | ||||
|             for(int i=0; i<lower.size(); ++i){ | ||||
|                 std::cout << GridLogMessage << "lower[" << i << "] =" << lower[i] << std::endl; | ||||
|             } | ||||
|         #endif | ||||
|  | ||||
|         this->M5Ddag(psi, chi, chi, lower, diag, upper); | ||||
|     } | ||||
|  | ||||
|     // half checkerboard operations | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::Mooee(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         std::vector<Coeff_t> diag = this->bee; | ||||
|         std::vector<Coeff_t> upper(Ls); | ||||
|         std::vector<Coeff_t> lower(Ls); | ||||
|  | ||||
|         for(int s=0; s<Ls; s++){ | ||||
|           upper[s] = -this->cee[s]; | ||||
|           lower[s] = -this->cee[s]; | ||||
|         } | ||||
|         upper[Ls-1] = this->dm; | ||||
|         lower[0]    = this->dp; | ||||
|  | ||||
|         this->M5D(psi, psi, chi, lower, diag, upper); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeDag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         std::vector<Coeff_t> diag = this->bee; | ||||
|         std::vector<Coeff_t> upper(Ls); | ||||
|         std::vector<Coeff_t> lower(Ls); | ||||
|  | ||||
|         for(int s=0; s<Ls; s++){ | ||||
|           upper[s] = -this->cee[s]; | ||||
|           lower[s] = -this->cee[s]; | ||||
|         } | ||||
|         upper[Ls-1] = this->dp; | ||||
|         lower[0]    = this->dm; | ||||
|  | ||||
|         this->M5Ddag(psi, psi, chi, lower, diag, upper); | ||||
|     } | ||||
|  | ||||
|     /****************************************************************************************/ | ||||
|  | ||||
|     //Zolo | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::SetCoefficientsInternal(RealD zolo_hi, std::vector<Coeff_t>& gamma, RealD b, RealD c) | ||||
|     { | ||||
|         int   Ls    = this->Ls; | ||||
|         int   pm    = this->pm; | ||||
|         RealD mq1   = this->mq1; | ||||
|         RealD mq2   = this->mq2; | ||||
|         RealD mq3   = this->mq3; | ||||
|         RealD shift = this->shift; | ||||
|  | ||||
|         //////////////////////////////////////////////////////// | ||||
|         // Constants for the preconditioned matrix Cayley form | ||||
|         //////////////////////////////////////////////////////// | ||||
|         this->bs.resize(Ls); | ||||
|         this->cs.resize(Ls); | ||||
|         this->aee.resize(Ls); | ||||
|         this->aeo.resize(Ls); | ||||
|         this->bee.resize(Ls); | ||||
|         this->beo.resize(Ls); | ||||
|         this->cee.resize(Ls); | ||||
|         this->ceo.resize(Ls); | ||||
|  | ||||
|         for(int i=0; i<Ls; ++i){ | ||||
|           this->bee[i] = 4.0 - this->M5 + 1.0; | ||||
|           this->cee[i] = 1.0; | ||||
|         } | ||||
|  | ||||
|         for(int i=0; i<Ls; ++i){ | ||||
|           this->aee[i] = this->cee[i]; | ||||
|           this->bs[i] = this->beo[i] = 1.0; | ||||
|           this->cs[i] = this->ceo[i] = 0.0; | ||||
|         } | ||||
|  | ||||
|         ////////////////////////////////////////// | ||||
|         // EOFA shift terms | ||||
|         ////////////////////////////////////////// | ||||
|         if(pm == 1){ | ||||
|           this->dp = mq1*this->cee[0] + shift*(mq3-mq2); | ||||
|           this->dm = mq1*this->cee[Ls-1]; | ||||
|         } else if(this->pm == -1) { | ||||
|           this->dp = mq1*this->cee[0]; | ||||
|           this->dm = mq1*this->cee[Ls-1] - shift*(mq3-mq2); | ||||
|         } else { | ||||
|           this->dp = mq1*this->cee[0]; | ||||
|           this->dm = mq1*this->cee[Ls-1]; | ||||
|         } | ||||
|  | ||||
|         ////////////////////////////////////////// | ||||
|         // LDU decomposition of eeoo | ||||
|         ////////////////////////////////////////// | ||||
|         this->dee.resize(Ls+1); | ||||
|         this->lee.resize(Ls); | ||||
|         this->leem.resize(Ls); | ||||
|         this->uee.resize(Ls); | ||||
|         this->ueem.resize(Ls); | ||||
|  | ||||
|         for(int i=0; i<Ls; ++i){ | ||||
|  | ||||
|           if(i < Ls-1){ | ||||
|  | ||||
|             this->lee[i] = -this->cee[i+1]/this->bee[i]; // sub-diag entry on the ith column | ||||
|  | ||||
|             this->leem[i] = this->dm/this->bee[i]; | ||||
|             for(int j=0; j<i; j++){ this->leem[i] *= this->aee[j]/this->bee[j]; } | ||||
|  | ||||
|             this->dee[i] = this->bee[i]; | ||||
|  | ||||
|             this->uee[i] = -this->aee[i]/this->bee[i];   // up-diag entry on the ith row | ||||
|  | ||||
|             this->ueem[i] = this->dp / this->bee[0]; | ||||
|             for(int j=1; j<=i; j++){ this->ueem[i] *= this->cee[j]/this->bee[j]; } | ||||
|  | ||||
|           } else { | ||||
|  | ||||
|             this->lee[i]  = 0.0; | ||||
|             this->leem[i] = 0.0; | ||||
|             this->uee[i]  = 0.0; | ||||
|             this->ueem[i] = 0.0; | ||||
|  | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         { | ||||
|           Coeff_t delta_d = 1.0 / this->bee[0]; | ||||
|           for(int j=1; j<Ls-1; j++){ delta_d *= this->cee[j] / this->bee[j]; } | ||||
|           this->dee[Ls-1] = this->bee[Ls-1] + this->cee[0] * this->dm * delta_d; | ||||
|           this->dee[Ls] = this->bee[Ls-1] + this->cee[Ls-1] * this->dp * delta_d; | ||||
|         } | ||||
|  | ||||
|         int inv = 1; | ||||
|         this->MooeeInternalCompute(0, inv, this->MatpInv, this->MatmInv); | ||||
|         this->MooeeInternalCompute(1, inv, this->MatpInvDag, this->MatmInvDag); | ||||
|     } | ||||
|  | ||||
|     // Recompute Cayley-form coefficients for different shift | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::RefreshShiftCoefficients(RealD new_shift) | ||||
|     { | ||||
|         this->shift = new_shift; | ||||
|         Approx::zolotarev_data *zdata = Approx::higham(1.0, this->Ls); | ||||
|         this->SetCoefficientsTanh(zdata, 1.0, 0.0); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInternalCompute(int dag, int inv, | ||||
|         Vector<iSinglet<Simd> >& Matp, Vector<iSinglet<Simd> >& Matm) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         GridBase* grid = this->FermionRedBlackGrid(); | ||||
|         int LLs = grid->_rdimensions[0]; | ||||
|  | ||||
|         if(LLs == Ls){ return; } // Not vectorised in 5th direction | ||||
|  | ||||
|         Eigen::MatrixXcd Pplus  = Eigen::MatrixXcd::Zero(Ls,Ls); | ||||
|         Eigen::MatrixXcd Pminus = Eigen::MatrixXcd::Zero(Ls,Ls); | ||||
|  | ||||
|         for(int s=0; s<Ls; s++){ | ||||
|             Pplus(s,s)  = this->bee[s]; | ||||
|             Pminus(s,s) = this->bee[s]; | ||||
|         } | ||||
|  | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             Pminus(s,s+1) = -this->cee[s]; | ||||
|         } | ||||
|  | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             Pplus(s+1,s) = -this->cee[s+1]; | ||||
|         } | ||||
|  | ||||
|         Pplus (0,Ls-1) = this->dp; | ||||
|         Pminus(Ls-1,0) = this->dm; | ||||
|  | ||||
|         Eigen::MatrixXcd PplusMat ; | ||||
|         Eigen::MatrixXcd PminusMat; | ||||
|  | ||||
|         #if(0) | ||||
|             std::cout << GridLogMessage << "Pplus:" << std::endl; | ||||
|             for(int s=0; s<Ls; ++s){ | ||||
|                 for(int ss=0; ss<Ls; ++ss){ | ||||
|                     std::cout << Pplus(s,ss) << "\t"; | ||||
|                 } | ||||
|                 std::cout << std::endl; | ||||
|             } | ||||
|             std::cout << GridLogMessage << "Pminus:" << std::endl; | ||||
|             for(int s=0; s<Ls; ++s){ | ||||
|                 for(int ss=0; ss<Ls; ++ss){ | ||||
|                     std::cout << Pminus(s,ss) << "\t"; | ||||
|                 } | ||||
|                 std::cout << std::endl; | ||||
|             } | ||||
|         #endif | ||||
|  | ||||
|         if(inv) { | ||||
|             PplusMat  = Pplus.inverse(); | ||||
|             PminusMat = Pminus.inverse(); | ||||
|         } else { | ||||
|             PplusMat  = Pplus; | ||||
|             PminusMat = Pminus; | ||||
|         } | ||||
|  | ||||
|         if(dag){ | ||||
|             PplusMat.adjointInPlace(); | ||||
|             PminusMat.adjointInPlace(); | ||||
|         } | ||||
|  | ||||
|         typedef typename SiteHalfSpinor::scalar_type scalar_type; | ||||
|         const int Nsimd = Simd::Nsimd(); | ||||
|         Matp.resize(Ls*LLs); | ||||
|         Matm.resize(Ls*LLs); | ||||
|  | ||||
|         for(int s2=0; s2<Ls; s2++){ | ||||
|         for(int s1=0; s1<LLs; s1++){ | ||||
|             int istride = LLs; | ||||
|             int ostride = 1; | ||||
|             Simd Vp; | ||||
|             Simd Vm; | ||||
|             scalar_type *sp = (scalar_type*) &Vp; | ||||
|             scalar_type *sm = (scalar_type*) &Vm; | ||||
|             for(int l=0; l<Nsimd; l++){ | ||||
|                 if(switcheroo<Coeff_t>::iscomplex()) { | ||||
|                     sp[l] = PplusMat (l*istride+s1*ostride,s2); | ||||
|                     sm[l] = PminusMat(l*istride+s1*ostride,s2); | ||||
|                 } else { | ||||
|                     // if real | ||||
|                     scalar_type tmp; | ||||
|                     tmp = PplusMat (l*istride+s1*ostride,s2); | ||||
|                     sp[l] = scalar_type(tmp.real(),tmp.real()); | ||||
|                     tmp = PminusMat(l*istride+s1*ostride,s2); | ||||
|                     sm[l] = scalar_type(tmp.real(),tmp.real()); | ||||
|                 } | ||||
|             } | ||||
|             Matp[LLs*s2+s1] = Vp; | ||||
|             Matm[LLs*s2+s1] = Vm; | ||||
|         }} | ||||
|     } | ||||
|  | ||||
|     FermOpTemplateInstantiate(DomainWallEOFAFermion); | ||||
|     GparityFermOpTemplateInstantiate(DomainWallEOFAFermion); | ||||
|  | ||||
| }} | ||||
							
								
								
									
										115
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermion.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermion.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/DomainWallEOFAFermion.h | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| 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 */ | ||||
| #ifndef  GRID_QCD_DOMAIN_WALL_EOFA_FERMION_H | ||||
| #define  GRID_QCD_DOMAIN_WALL_EOFA_FERMION_H | ||||
|  | ||||
| #include <Grid/qcd/action/fermion/AbstractEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   template<class Impl> | ||||
|   class DomainWallEOFAFermion : public AbstractEOFAFermion<Impl> | ||||
|   { | ||||
|     public: | ||||
|       INHERIT_IMPL_TYPES(Impl); | ||||
|  | ||||
|     public: | ||||
|       // Modified (0,Ls-1) and (Ls-1,0) elements of Mooee | ||||
|       // for red-black preconditioned Shamir EOFA | ||||
|       Coeff_t dm; | ||||
|       Coeff_t dp; | ||||
|  | ||||
|       virtual void Instantiatable(void) {}; | ||||
|  | ||||
|       // EOFA-specific operations | ||||
|       virtual void  Omega      (const FermionField& in, FermionField& out, int sign, int dag); | ||||
|       virtual void  Dtilde     (const FermionField& in, FermionField& out); | ||||
|       virtual void  DtildeInv  (const FermionField& in, FermionField& out); | ||||
|  | ||||
|       // override multiply | ||||
|       virtual RealD M          (const FermionField& in, FermionField& out); | ||||
|       virtual RealD Mdag       (const FermionField& in, FermionField& out); | ||||
|  | ||||
|       // half checkerboard operations | ||||
|       virtual void  Mooee      (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeDag   (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeInv   (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeInvDag(const FermionField& in, FermionField& out); | ||||
|  | ||||
|       virtual void   M5D       (const FermionField& psi, FermionField& chi); | ||||
|       virtual void   M5Ddag    (const FermionField& psi, FermionField& chi); | ||||
|  | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // Instantiate different versions depending on Impl | ||||
|       ///////////////////////////////////////////////////// | ||||
|       void M5D(const FermionField& psi, const FermionField& phi, FermionField& chi, | ||||
|         std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); | ||||
|  | ||||
|       void M5Ddag(const FermionField& psi, const FermionField& phi, FermionField& chi, | ||||
|         std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); | ||||
|  | ||||
|       void MooeeInternal(const FermionField& in, FermionField& out, int dag, int inv); | ||||
|  | ||||
|       void MooeeInternalCompute(int dag, int inv, Vector<iSinglet<Simd>>& Matp, Vector<iSinglet<Simd>>& Matm); | ||||
|  | ||||
|       void MooeeInternalAsm(const FermionField& in, FermionField& out, int LLs, int site, | ||||
|         Vector<iSinglet<Simd>>& Matp, Vector<iSinglet<Simd>>& Matm); | ||||
|  | ||||
|       void MooeeInternalZAsm(const FermionField& in, FermionField& out, int LLs, int site, | ||||
|         Vector<iSinglet<Simd>>& Matp, Vector<iSinglet<Simd>>& Matm); | ||||
|  | ||||
|       virtual void RefreshShiftCoefficients(RealD new_shift); | ||||
|  | ||||
|       // Constructors | ||||
|       DomainWallEOFAFermion(GaugeField& _Umu, GridCartesian& FiveDimGrid, GridRedBlackCartesian& FiveDimRedBlackGrid, | ||||
|         GridCartesian& FourDimGrid, GridRedBlackCartesian& FourDimRedBlackGrid, | ||||
|         RealD _mq1, RealD _mq2, RealD _mq3, RealD _shift, int pm, | ||||
|         RealD _M5, const ImplParams& p=ImplParams()); | ||||
|  | ||||
|     protected: | ||||
|       void SetCoefficientsInternal(RealD zolo_hi, std::vector<Coeff_t>& gamma, RealD b, RealD c); | ||||
|   }; | ||||
| }} | ||||
|  | ||||
| #define INSTANTIATE_DPERP_DWF_EOFA(A)\ | ||||
| template void DomainWallEOFAFermion<A>::M5D(const FermionField& psi, const FermionField& phi, FermionField& chi, \ | ||||
|   std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); \ | ||||
| template void DomainWallEOFAFermion<A>::M5Ddag(const FermionField& psi, const FermionField& phi, FermionField& chi, \ | ||||
|   std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); \ | ||||
| template void DomainWallEOFAFermion<A>::MooeeInv(const FermionField& psi, FermionField& chi); \ | ||||
| template void DomainWallEOFAFermion<A>::MooeeInvDag(const FermionField& psi, FermionField& chi); | ||||
|  | ||||
| #undef  DOMAIN_WALL_EOFA_DPERP_DENSE | ||||
| #define DOMAIN_WALL_EOFA_DPERP_CACHE | ||||
| #undef  DOMAIN_WALL_EOFA_DPERP_LINALG | ||||
| #define DOMAIN_WALL_EOFA_DPERP_VEC | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										248
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermioncache.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermioncache.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,248 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/DomainWallEOFAFermioncache.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|     // FIXME -- make a version of these routines with site loop outermost for cache reuse. | ||||
|  | ||||
|     // Pminus fowards | ||||
|     // Pplus  backwards.. | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5D(const FermionField& psi, const FermionField& phi, | ||||
|         FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|         GridBase* grid = psi._grid; | ||||
|  | ||||
|         assert(phi.checkerboard == psi.checkerboard); | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|         // Flops = 6.0*(Nc*Ns) *Ls*vol | ||||
|         this->M5Dcalls++; | ||||
|         this->M5Dtime -= usecond(); | ||||
|  | ||||
|         parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ // adds Ls | ||||
|             for(int s=0; s<Ls; s++){ | ||||
|                 auto tmp = psi._odata[0]; | ||||
|                 if(s==0) { | ||||
|                     spProj5m(tmp, psi._odata[ss+s+1]); | ||||
|                     chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|                     spProj5p(tmp, psi._odata[ss+Ls-1]); | ||||
|                     chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|                 } else if(s==(Ls-1)) { | ||||
|                     spProj5m(tmp, psi._odata[ss+0]); | ||||
|                     chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|                     spProj5p(tmp, psi._odata[ss+s-1]); | ||||
|                     chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|                 } else { | ||||
|                     spProj5m(tmp, psi._odata[ss+s+1]); | ||||
|                     chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|                     spProj5p(tmp, psi._odata[ss+s-1]); | ||||
|                     chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this->M5Dtime += usecond(); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5Ddag(const FermionField& psi, const FermionField& phi, | ||||
|         FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|         GridBase* grid = psi._grid; | ||||
|         assert(phi.checkerboard == psi.checkerboard); | ||||
|         chi.checkerboard=psi.checkerboard; | ||||
|  | ||||
|         // Flops = 6.0*(Nc*Ns) *Ls*vol | ||||
|         this->M5Dcalls++; | ||||
|         this->M5Dtime -= usecond(); | ||||
|  | ||||
|         parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ // adds Ls | ||||
|             auto tmp = psi._odata[0]; | ||||
|             for(int s=0; s<Ls; s++){ | ||||
|                 if(s==0) { | ||||
|                     spProj5p(tmp, psi._odata[ss+s+1]); | ||||
|                     chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|                     spProj5m(tmp, psi._odata[ss+Ls-1]); | ||||
|                     chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|                 } else if(s==(Ls-1)) { | ||||
|                     spProj5p(tmp, psi._odata[ss+0]); | ||||
|                     chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|                     spProj5m(tmp, psi._odata[ss+s-1]); | ||||
|                     chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|                 } else { | ||||
|                     spProj5p(tmp, psi._odata[ss+s+1]); | ||||
|                     chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|                     spProj5m(tmp, psi._odata[ss+s-1]); | ||||
|                     chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this->M5Dtime += usecond(); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         GridBase* grid = psi._grid; | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|         this->MooeeInvCalls++; | ||||
|         this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|         parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ // adds Ls | ||||
|  | ||||
|             auto tmp1 = psi._odata[0]; | ||||
|             auto tmp2 = psi._odata[0]; | ||||
|  | ||||
|             // flops = 12*2*Ls + 12*2*Ls + 3*12*Ls + 12*2*Ls  = 12*Ls * (9) = 108*Ls flops | ||||
|             // Apply (L^{\prime})^{-1} | ||||
|             chi[ss] = psi[ss]; // chi[0]=psi[0] | ||||
|             for(int s=1; s<Ls; s++){ | ||||
|                 spProj5p(tmp1, chi[ss+s-1]); | ||||
|                 chi[ss+s] = psi[ss+s] - this->lee[s-1]*tmp1; | ||||
|             } | ||||
|  | ||||
|             // L_m^{-1} | ||||
|             for(int s=0; s<Ls-1; s++){ // Chi[ee] = 1 - sum[s<Ls-1] -leem[s]P_- chi | ||||
|                 spProj5m(tmp1, chi[ss+s]); | ||||
|                 chi[ss+Ls-1] = chi[ss+Ls-1] - this->leem[s]*tmp1; | ||||
|             } | ||||
|  | ||||
|             // U_m^{-1} D^{-1} | ||||
|             for(int s=0; s<Ls-1; s++){ // Chi[s] + 1/d chi[s] | ||||
|                 spProj5p(tmp1, chi[ss+Ls-1]); | ||||
|                 chi[ss+s] = (1.0/this->dee[s])*chi[ss+s] - (this->ueem[s]/this->dee[Ls])*tmp1; | ||||
|             } | ||||
|             spProj5m(tmp2, chi[ss+Ls-1]); | ||||
|             chi[ss+Ls-1] = (1.0/this->dee[Ls])*tmp1 + (1.0/this->dee[Ls-1])*tmp2; | ||||
|  | ||||
|             // Apply U^{-1} | ||||
|             for(int s=Ls-2; s>=0; s--){ | ||||
|                 spProj5m(tmp1, chi[ss+s+1]); | ||||
|                 chi[ss+s] = chi[ss+s] - this->uee[s]*tmp1; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this->MooeeInvTime += usecond(); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         GridBase* grid = psi._grid; | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         assert(psi.checkerboard == psi.checkerboard); | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|         std::vector<Coeff_t> ueec(Ls); | ||||
|         std::vector<Coeff_t> deec(Ls+1); | ||||
|         std::vector<Coeff_t> leec(Ls); | ||||
|         std::vector<Coeff_t> ueemc(Ls); | ||||
|         std::vector<Coeff_t> leemc(Ls); | ||||
|  | ||||
|         for(int s=0; s<ueec.size(); s++){ | ||||
|             ueec[s]  = conjugate(this->uee[s]); | ||||
|             deec[s]  = conjugate(this->dee[s]); | ||||
|             leec[s]  = conjugate(this->lee[s]); | ||||
|             ueemc[s] = conjugate(this->ueem[s]); | ||||
|             leemc[s] = conjugate(this->leem[s]); | ||||
|         } | ||||
|         deec[Ls] = conjugate(this->dee[Ls]); | ||||
|  | ||||
|         this->MooeeInvCalls++; | ||||
|         this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|         parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ // adds Ls | ||||
|  | ||||
|             auto tmp1 = psi._odata[0]; | ||||
|             auto tmp2 = psi._odata[0]; | ||||
|  | ||||
|             // Apply (U^{\prime})^{-dagger} | ||||
|             chi[ss] = psi[ss]; | ||||
|             for(int s=1; s<Ls; s++){ | ||||
|                 spProj5m(tmp1, chi[ss+s-1]); | ||||
|                 chi[ss+s] = psi[ss+s] - ueec[s-1]*tmp1; | ||||
|             } | ||||
|  | ||||
|             // U_m^{-\dagger} | ||||
|             for(int s=0; s<Ls-1; s++){ | ||||
|                 spProj5p(tmp1, chi[ss+s]); | ||||
|                 chi[ss+Ls-1] = chi[ss+Ls-1] - ueemc[s]*tmp1; | ||||
|             } | ||||
|  | ||||
|             // L_m^{-\dagger} D^{-dagger} | ||||
|             for(int s=0; s<Ls-1; s++){ | ||||
|                 spProj5m(tmp1, chi[ss+Ls-1]); | ||||
|                 chi[ss+s] = (1.0/deec[s])*chi[ss+s] - (leemc[s]/deec[Ls-1])*tmp1; | ||||
|             } | ||||
|             spProj5p(tmp2, chi[ss+Ls-1]); | ||||
|             chi[ss+Ls-1] = (1.0/deec[Ls-1])*tmp1 + (1.0/deec[Ls])*tmp2; | ||||
|  | ||||
|             // Apply L^{-dagger} | ||||
|             for(int s=Ls-2; s>=0; s--){ | ||||
|                 spProj5p(tmp1, chi[ss+s+1]); | ||||
|                 chi[ss+s] = chi[ss+s] - leec[s]*tmp1; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this->MooeeInvTime += usecond(); | ||||
|     } | ||||
|  | ||||
|     #ifdef DOMAIN_WALL_EOFA_DPERP_CACHE | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplD); | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplDF); | ||||
|  | ||||
|     #endif | ||||
|  | ||||
| }} | ||||
							
								
								
									
										159
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermiondense.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermiondense.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/DomainWallEOFAFermiondense.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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_Eigen_Dense.h> | ||||
| #include <Grid/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|     /* | ||||
|     * Dense matrix versions of routines | ||||
|     */ | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         this->MooeeInternal(psi, chi, DaggerYes, InverseYes); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         this->MooeeInternal(psi, chi, DaggerNo, InverseYes); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv) | ||||
|     { | ||||
|         int Ls = this->Ls; | ||||
|         int LLs = psi._grid->_rdimensions[0]; | ||||
|         int vol = psi._grid->oSites()/LLs; | ||||
|  | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|         assert(Ls==LLs); | ||||
|  | ||||
|         Eigen::MatrixXd Pplus  = Eigen::MatrixXd::Zero(Ls,Ls); | ||||
|         Eigen::MatrixXd Pminus = Eigen::MatrixXd::Zero(Ls,Ls); | ||||
|  | ||||
|         for(int s=0;s<Ls;s++){ | ||||
|             Pplus(s,s)  = this->bee[s]; | ||||
|             Pminus(s,s) = this->bee[s]; | ||||
|         } | ||||
|  | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             Pminus(s,s+1) = -this->cee[s]; | ||||
|         } | ||||
|  | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             Pplus(s+1,s) = -this->cee[s+1]; | ||||
|         } | ||||
|  | ||||
|         Pplus (0,Ls-1) = this->dp; | ||||
|         Pminus(Ls-1,0) = this->dm; | ||||
|  | ||||
|         Eigen::MatrixXd PplusMat ; | ||||
|         Eigen::MatrixXd PminusMat; | ||||
|  | ||||
|         if(inv) { | ||||
|             PplusMat  = Pplus.inverse(); | ||||
|             PminusMat = Pminus.inverse(); | ||||
|         } else { | ||||
|             PplusMat  = Pplus; | ||||
|             PminusMat = Pminus; | ||||
|         } | ||||
|  | ||||
|         if(dag){ | ||||
|             PplusMat.adjointInPlace(); | ||||
|             PminusMat.adjointInPlace(); | ||||
|         } | ||||
|  | ||||
|         // For the non-vectorised s-direction this is simple | ||||
|  | ||||
|         for(auto site=0; site<vol; site++){ | ||||
|  | ||||
|             SiteSpinor     SiteChi; | ||||
|             SiteHalfSpinor SitePplus; | ||||
|             SiteHalfSpinor SitePminus; | ||||
|  | ||||
|             for(int s1=0; s1<Ls; s1++){ | ||||
|                 SiteChi = zero; | ||||
|                 for(int s2=0; s2<Ls; s2++){ | ||||
|                     int lex2 = s2 + Ls*site; | ||||
|                     if(PplusMat(s1,s2) != 0.0){ | ||||
|                         spProj5p(SitePplus,psi[lex2]); | ||||
|                         accumRecon5p(SiteChi, PplusMat(s1,s2)*SitePplus); | ||||
|                     } | ||||
|                     if(PminusMat(s1,s2) != 0.0){ | ||||
|                         spProj5m(SitePminus, psi[lex2]); | ||||
|                         accumRecon5m(SiteChi, PminusMat(s1,s2)*SitePminus); | ||||
|                     } | ||||
|                 } | ||||
|                 chi[s1+Ls*site] = SiteChi*0.5; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #ifdef DOMAIN_WALL_EOFA_DPERP_DENSE | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplD); | ||||
|  | ||||
|         template void DomainWallEOFAFermion<GparityWilsonImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<GparityWilsonImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<WilsonImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<WilsonImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZWilsonImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZWilsonImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplDF); | ||||
|  | ||||
|         template void DomainWallEOFAFermion<GparityWilsonImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<GparityWilsonImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<WilsonImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<WilsonImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZWilsonImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZWilsonImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|     #endif | ||||
|  | ||||
| }} | ||||
							
								
								
									
										168
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermionssp.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermionssp.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/DomainWallEOFAFermionssp.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|     // FIXME -- make a version of these routines with site loop outermost for cache reuse. | ||||
|     // Pminus fowards | ||||
|     // Pplus  backwards | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5D(const FermionField& psi, const FermionField& phi, | ||||
|         FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|     { | ||||
|         Coeff_t one(1.0); | ||||
|         int Ls = this->Ls; | ||||
|         for(int s=0; s<Ls; s++){ | ||||
|             if(s==0) { | ||||
|               axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|               axpby_ssp_pplus (chi, one, chi, lower[s], psi, s, Ls-1); | ||||
|             } else if (s==(Ls-1)) { | ||||
|               axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, 0); | ||||
|               axpby_ssp_pplus (chi, one, chi, lower[s], psi, s, s-1); | ||||
|             } else { | ||||
|               axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|               axpby_ssp_pplus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5Ddag(const FermionField& psi, const FermionField& phi, | ||||
|         FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|     { | ||||
|         Coeff_t one(1.0); | ||||
|         int Ls = this->Ls; | ||||
|         for(int s=0; s<Ls; s++){ | ||||
|             if(s==0) { | ||||
|               axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|               axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, Ls-1); | ||||
|             } else if (s==(Ls-1)) { | ||||
|               axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, 0); | ||||
|               axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|             } else { | ||||
|               axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|               axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         Coeff_t one(1.0); | ||||
|         Coeff_t czero(0.0); | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         FermionField tmp(psi._grid); | ||||
|  | ||||
|         // Apply (L^{\prime})^{-1} | ||||
|         axpby_ssp(chi, one, psi, czero, psi, 0, 0);      // chi[0]=psi[0] | ||||
|         for(int s=1; s<Ls; s++){ | ||||
|             axpby_ssp_pplus(chi, one, psi, -this->lee[s-1], chi, s, s-1);// recursion Psi[s] -lee P_+ chi[s-1] | ||||
|         } | ||||
|  | ||||
|         // L_m^{-1} | ||||
|         for(int s=0; s<Ls-1; s++){ // Chi[ee] = 1 - sum[s<Ls-1] -leem[s]P_- chi | ||||
|             axpby_ssp_pminus(chi, one, chi, -this->leem[s], chi, Ls-1, s); | ||||
|         } | ||||
|  | ||||
|         // U_m^{-1} D^{-1} | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             axpby_ssp_pplus(chi, one/this->dee[s], chi, -this->ueem[s]/this->dee[Ls], chi, s, Ls-1); | ||||
|         } | ||||
|         axpby_ssp_pminus(tmp, czero, chi, one/this->dee[Ls-1], chi, Ls-1, Ls-1); | ||||
|         axpby_ssp_pplus(chi, one, tmp, one/this->dee[Ls], chi, Ls-1, Ls-1); | ||||
|  | ||||
|         // Apply U^{-1} | ||||
|         for(int s=Ls-2; s>=0; s--){ | ||||
|             axpby_ssp_pminus(chi, one, chi, -this->uee[s], chi, s, s+1);  // chi[Ls] | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         Coeff_t one(1.0); | ||||
|         Coeff_t czero(0.0); | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|         int Ls = this->Ls; | ||||
|  | ||||
|         FermionField tmp(psi._grid); | ||||
|  | ||||
|         // Apply (U^{\prime})^{-dagger} | ||||
|         axpby_ssp(chi, one, psi, czero, psi, 0, 0);      // chi[0]=psi[0] | ||||
|         for(int s=1; s<Ls; s++){ | ||||
|             axpby_ssp_pminus(chi, one, psi, -conjugate(this->uee[s-1]), chi, s, s-1); | ||||
|         } | ||||
|  | ||||
|         // U_m^{-\dagger} | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             axpby_ssp_pplus(chi, one, chi, -conjugate(this->ueem[s]), chi, Ls-1, s); | ||||
|         } | ||||
|  | ||||
|         // L_m^{-\dagger} D^{-dagger} | ||||
|         for(int s=0; s<Ls-1; s++){ | ||||
|             axpby_ssp_pminus(chi, one/conjugate(this->dee[s]), chi, -conjugate(this->leem[s]/this->dee[Ls-1]), chi, s, Ls-1); | ||||
|         } | ||||
|         axpby_ssp_pminus(tmp, czero, chi, one/conjugate(this->dee[Ls-1]), chi, Ls-1, Ls-1); | ||||
|         axpby_ssp_pplus(chi, one, tmp, one/conjugate(this->dee[Ls]), chi, Ls-1, Ls-1); | ||||
|  | ||||
|         // Apply L^{-dagger} | ||||
|         for(int s=Ls-2; s>=0; s--){ | ||||
|             axpby_ssp_pplus(chi, one, chi, -conjugate(this->lee[s]), chi, s, s+1);  // chi[Ls] | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #ifdef DOMAIN_WALL_EOFA_DPERP_LINALG | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplD); | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(WilsonImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(GparityWilsonImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZWilsonImplDF); | ||||
|  | ||||
|     #endif | ||||
|  | ||||
| }} | ||||
							
								
								
									
										605
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermionvec.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										605
									
								
								lib/qcd/action/fermion/DomainWallEOFAFermionvec.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,605 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/DomainWallEOFAFermionvec.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|     /* | ||||
|     * Dense matrix versions of routines | ||||
|     */ | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         this->MooeeInternal(psi, chi, DaggerYes, InverseYes); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|         this->MooeeInternal(psi, chi, DaggerNo, InverseYes); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5D(const FermionField& psi, const FermionField& phi, | ||||
|         FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|     { | ||||
|         GridBase* grid = psi._grid; | ||||
|         int Ls  = this->Ls; | ||||
|         int LLs = grid->_rdimensions[0]; | ||||
|         const int nsimd = Simd::Nsimd(); | ||||
|  | ||||
|         Vector<iSinglet<Simd> > u(LLs); | ||||
|         Vector<iSinglet<Simd> > l(LLs); | ||||
|         Vector<iSinglet<Simd> > d(LLs); | ||||
|  | ||||
|         assert(Ls/LLs == nsimd); | ||||
|         assert(phi.checkerboard == psi.checkerboard); | ||||
|  | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|         // just directly address via type pun | ||||
|         typedef typename Simd::scalar_type scalar_type; | ||||
|         scalar_type* u_p = (scalar_type*) &u[0]; | ||||
|         scalar_type* l_p = (scalar_type*) &l[0]; | ||||
|         scalar_type* d_p = (scalar_type*) &d[0]; | ||||
|  | ||||
|         for(int o=0;o<LLs;o++){ // outer | ||||
|         for(int i=0;i<nsimd;i++){ //inner | ||||
|             int s  = o + i*LLs; | ||||
|             int ss = o*nsimd + i; | ||||
|             u_p[ss] = upper[s]; | ||||
|             l_p[ss] = lower[s]; | ||||
|             d_p[ss] = diag[s]; | ||||
|         }} | ||||
|  | ||||
|         this->M5Dcalls++; | ||||
|         this->M5Dtime -= usecond(); | ||||
|  | ||||
|         assert(Nc == 3); | ||||
|  | ||||
|         parallel_for(int ss=0; ss<grid->oSites(); ss+=LLs){ // adds LLs | ||||
|  | ||||
|             #if 0 | ||||
|  | ||||
|                 alignas(64) SiteHalfSpinor hp; | ||||
|                 alignas(64) SiteHalfSpinor hm; | ||||
|                 alignas(64) SiteSpinor fp; | ||||
|                 alignas(64) SiteSpinor fm; | ||||
|  | ||||
|                 for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|                     int vp = (v+1)%LLs; | ||||
|                     int vm = (v+LLs-1)%LLs; | ||||
|  | ||||
|                     spProj5m(hp, psi[ss+vp]); | ||||
|                     spProj5p(hm, psi[ss+vm]); | ||||
|  | ||||
|                     if (vp <= v){ rotate(hp, hp, 1); } | ||||
|                     if (vm >= v){ rotate(hm, hm, nsimd-1); } | ||||
|  | ||||
|                     hp = 0.5*hp; | ||||
|                     hm = 0.5*hm; | ||||
|  | ||||
|                     spRecon5m(fp, hp); | ||||
|                     spRecon5p(fm, hm); | ||||
|  | ||||
|                     chi[ss+v] = d[v]*phi[ss+v]; | ||||
|                     chi[ss+v] = chi[ss+v] + u[v]*fp; | ||||
|                     chi[ss+v] = chi[ss+v] + l[v]*fm; | ||||
|  | ||||
|                 } | ||||
|  | ||||
|             #else | ||||
|  | ||||
|                 for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|                     vprefetch(psi[ss+v+LLs]); | ||||
|  | ||||
|                     int vp = (v==LLs-1) ? 0     : v+1; | ||||
|                     int vm = (v==0)     ? LLs-1 : v-1; | ||||
|  | ||||
|                     Simd hp_00 = psi[ss+vp]()(2)(0); | ||||
|                     Simd hp_01 = psi[ss+vp]()(2)(1); | ||||
|                     Simd hp_02 = psi[ss+vp]()(2)(2); | ||||
|                     Simd hp_10 = psi[ss+vp]()(3)(0); | ||||
|                     Simd hp_11 = psi[ss+vp]()(3)(1); | ||||
|                     Simd hp_12 = psi[ss+vp]()(3)(2); | ||||
|  | ||||
|                     Simd hm_00 = psi[ss+vm]()(0)(0); | ||||
|                     Simd hm_01 = psi[ss+vm]()(0)(1); | ||||
|                     Simd hm_02 = psi[ss+vm]()(0)(2); | ||||
|                     Simd hm_10 = psi[ss+vm]()(1)(0); | ||||
|                     Simd hm_11 = psi[ss+vm]()(1)(1); | ||||
|                     Simd hm_12 = psi[ss+vm]()(1)(2); | ||||
|  | ||||
|                     if(vp <= v){ | ||||
|                         hp_00.v = Optimization::Rotate::tRotate<2>(hp_00.v); | ||||
|                         hp_01.v = Optimization::Rotate::tRotate<2>(hp_01.v); | ||||
|                         hp_02.v = Optimization::Rotate::tRotate<2>(hp_02.v); | ||||
|                         hp_10.v = Optimization::Rotate::tRotate<2>(hp_10.v); | ||||
|                         hp_11.v = Optimization::Rotate::tRotate<2>(hp_11.v); | ||||
|                         hp_12.v = Optimization::Rotate::tRotate<2>(hp_12.v); | ||||
|                     } | ||||
|  | ||||
|                     if(vm >= v){ | ||||
|                         hm_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_00.v); | ||||
|                         hm_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_01.v); | ||||
|                         hm_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_02.v); | ||||
|                         hm_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_10.v); | ||||
|                         hm_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_11.v); | ||||
|                         hm_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_12.v); | ||||
|                     } | ||||
|  | ||||
|                     // Can force these to real arithmetic and save 2x. | ||||
|                     Simd p_00 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00); | ||||
|                     Simd p_01 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01); | ||||
|                     Simd p_02 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02); | ||||
|                     Simd p_10 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10); | ||||
|                     Simd p_11 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11); | ||||
|                     Simd p_12 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12); | ||||
|                     Simd p_20 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00); | ||||
|                     Simd p_21 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01); | ||||
|                     Simd p_22 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02); | ||||
|                     Simd p_30 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10); | ||||
|                     Simd p_31 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11); | ||||
|                     Simd p_32 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12); | ||||
|  | ||||
|                     vstream(chi[ss+v]()(0)(0), p_00); | ||||
|                     vstream(chi[ss+v]()(0)(1), p_01); | ||||
|                     vstream(chi[ss+v]()(0)(2), p_02); | ||||
|                     vstream(chi[ss+v]()(1)(0), p_10); | ||||
|                     vstream(chi[ss+v]()(1)(1), p_11); | ||||
|                     vstream(chi[ss+v]()(1)(2), p_12); | ||||
|                     vstream(chi[ss+v]()(2)(0), p_20); | ||||
|                     vstream(chi[ss+v]()(2)(1), p_21); | ||||
|                     vstream(chi[ss+v]()(2)(2), p_22); | ||||
|                     vstream(chi[ss+v]()(3)(0), p_30); | ||||
|                     vstream(chi[ss+v]()(3)(1), p_31); | ||||
|                     vstream(chi[ss+v]()(3)(2), p_32); | ||||
|                 } | ||||
|  | ||||
|             #endif | ||||
|         } | ||||
|  | ||||
|         this->M5Dtime += usecond(); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::M5Ddag(const FermionField& psi, const FermionField& phi, | ||||
|         FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|     { | ||||
|         GridBase* grid = psi._grid; | ||||
|         int Ls  = this->Ls; | ||||
|         int LLs = grid->_rdimensions[0]; | ||||
|         int nsimd = Simd::Nsimd(); | ||||
|  | ||||
|         Vector<iSinglet<Simd> > u(LLs); | ||||
|         Vector<iSinglet<Simd> > l(LLs); | ||||
|         Vector<iSinglet<Simd> > d(LLs); | ||||
|  | ||||
|         assert(Ls/LLs == nsimd); | ||||
|         assert(phi.checkerboard == psi.checkerboard); | ||||
|  | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|         // just directly address via type pun | ||||
|         typedef typename Simd::scalar_type scalar_type; | ||||
|         scalar_type* u_p = (scalar_type*) &u[0]; | ||||
|         scalar_type* l_p = (scalar_type*) &l[0]; | ||||
|         scalar_type* d_p = (scalar_type*) &d[0]; | ||||
|  | ||||
|         for(int o=0; o<LLs; o++){ // outer | ||||
|         for(int i=0; i<nsimd; i++){ //inner | ||||
|             int s  = o + i*LLs; | ||||
|             int ss = o*nsimd + i; | ||||
|             u_p[ss] = upper[s]; | ||||
|             l_p[ss] = lower[s]; | ||||
|             d_p[ss] = diag[s]; | ||||
|         }} | ||||
|  | ||||
|         this->M5Dcalls++; | ||||
|         this->M5Dtime -= usecond(); | ||||
|  | ||||
|         parallel_for(int ss=0; ss<grid->oSites(); ss+=LLs){ // adds LLs | ||||
|  | ||||
|         #if 0 | ||||
|  | ||||
|             alignas(64) SiteHalfSpinor hp; | ||||
|             alignas(64) SiteHalfSpinor hm; | ||||
|             alignas(64) SiteSpinor fp; | ||||
|             alignas(64) SiteSpinor fm; | ||||
|  | ||||
|             for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|                 int vp = (v+1)%LLs; | ||||
|                 int vm = (v+LLs-1)%LLs; | ||||
|  | ||||
|                 spProj5p(hp, psi[ss+vp]); | ||||
|                 spProj5m(hm, psi[ss+vm]); | ||||
|  | ||||
|                 if(vp <= v){ rotate(hp, hp, 1); } | ||||
|                 if(vm >= v){ rotate(hm, hm, nsimd-1); } | ||||
|  | ||||
|                 hp = hp*0.5; | ||||
|                 hm = hm*0.5; | ||||
|                 spRecon5p(fp, hp); | ||||
|                 spRecon5m(fm, hm); | ||||
|  | ||||
|                 chi[ss+v] = d[v]*phi[ss+v]+u[v]*fp; | ||||
|                 chi[ss+v] = chi[ss+v]     +l[v]*fm; | ||||
|             } | ||||
|  | ||||
|         #else | ||||
|  | ||||
|             for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|                 vprefetch(psi[ss+v+LLs]); | ||||
|  | ||||
|                 int vp = (v == LLs-1) ? 0     : v+1; | ||||
|                 int vm = (v == 0    ) ? LLs-1 : v-1; | ||||
|  | ||||
|                 Simd hp_00 = psi[ss+vp]()(0)(0); | ||||
|                 Simd hp_01 = psi[ss+vp]()(0)(1); | ||||
|                 Simd hp_02 = psi[ss+vp]()(0)(2); | ||||
|                 Simd hp_10 = psi[ss+vp]()(1)(0); | ||||
|                 Simd hp_11 = psi[ss+vp]()(1)(1); | ||||
|                 Simd hp_12 = psi[ss+vp]()(1)(2); | ||||
|  | ||||
|                 Simd hm_00 = psi[ss+vm]()(2)(0); | ||||
|                 Simd hm_01 = psi[ss+vm]()(2)(1); | ||||
|                 Simd hm_02 = psi[ss+vm]()(2)(2); | ||||
|                 Simd hm_10 = psi[ss+vm]()(3)(0); | ||||
|                 Simd hm_11 = psi[ss+vm]()(3)(1); | ||||
|                 Simd hm_12 = psi[ss+vm]()(3)(2); | ||||
|  | ||||
|                 if (vp <= v){ | ||||
|                     hp_00.v = Optimization::Rotate::tRotate<2>(hp_00.v); | ||||
|                     hp_01.v = Optimization::Rotate::tRotate<2>(hp_01.v); | ||||
|                     hp_02.v = Optimization::Rotate::tRotate<2>(hp_02.v); | ||||
|                     hp_10.v = Optimization::Rotate::tRotate<2>(hp_10.v); | ||||
|                     hp_11.v = Optimization::Rotate::tRotate<2>(hp_11.v); | ||||
|                     hp_12.v = Optimization::Rotate::tRotate<2>(hp_12.v); | ||||
|                 } | ||||
|  | ||||
|                 if(vm >= v){ | ||||
|                     hm_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_00.v); | ||||
|                     hm_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_01.v); | ||||
|                     hm_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_02.v); | ||||
|                     hm_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_10.v); | ||||
|                     hm_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_11.v); | ||||
|                     hm_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_12.v); | ||||
|                 } | ||||
|  | ||||
|                 Simd p_00 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00); | ||||
|                 Simd p_01 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01); | ||||
|                 Simd p_02 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02); | ||||
|                 Simd p_10 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10); | ||||
|                 Simd p_11 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11); | ||||
|                 Simd p_12 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12); | ||||
|                 Simd p_20 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00); | ||||
|                 Simd p_21 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01); | ||||
|                 Simd p_22 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02); | ||||
|                 Simd p_30 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10); | ||||
|                 Simd p_31 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11); | ||||
|                 Simd p_32 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12); | ||||
|  | ||||
|                 vstream(chi[ss+v]()(0)(0), p_00); | ||||
|                 vstream(chi[ss+v]()(0)(1), p_01); | ||||
|                 vstream(chi[ss+v]()(0)(2), p_02); | ||||
|                 vstream(chi[ss+v]()(1)(0), p_10); | ||||
|                 vstream(chi[ss+v]()(1)(1), p_11); | ||||
|                 vstream(chi[ss+v]()(1)(2), p_12); | ||||
|                 vstream(chi[ss+v]()(2)(0), p_20); | ||||
|                 vstream(chi[ss+v]()(2)(1), p_21); | ||||
|                 vstream(chi[ss+v]()(2)(2), p_22); | ||||
|                 vstream(chi[ss+v]()(3)(0), p_30); | ||||
|                 vstream(chi[ss+v]()(3)(1), p_31); | ||||
|                 vstream(chi[ss+v]()(3)(2), p_32); | ||||
|             } | ||||
|         #endif | ||||
|  | ||||
|         } | ||||
|  | ||||
|         this->M5Dtime += usecond(); | ||||
|     } | ||||
|  | ||||
|     #ifdef AVX512 | ||||
|         #include<simd/Intel512common.h> | ||||
|         #include<simd/Intel512avx.h> | ||||
|         #include<simd/Intel512single.h> | ||||
|     #endif | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInternalAsm(const FermionField& psi, FermionField& chi, | ||||
|         int LLs, int site, Vector<iSinglet<Simd> >& Matp, Vector<iSinglet<Simd> >& Matm) | ||||
|     { | ||||
|         #ifndef AVX512 | ||||
|         { | ||||
|             SiteHalfSpinor BcastP; | ||||
|             SiteHalfSpinor BcastM; | ||||
|             SiteHalfSpinor SiteChiP; | ||||
|             SiteHalfSpinor SiteChiM; | ||||
|  | ||||
|             // Ls*Ls * 2 * 12 * vol flops | ||||
|             for(int s1=0; s1<LLs; s1++){ | ||||
|  | ||||
|                 for(int s2=0; s2<LLs; s2++){ | ||||
|                 for(int l=0; l < Simd::Nsimd(); l++){ // simd lane | ||||
|  | ||||
|                     int s = s2 + l*LLs; | ||||
|                     int lex = s2 + LLs*site; | ||||
|  | ||||
|                     if( s2==0 && l==0 ){ | ||||
|                         SiteChiP=zero; | ||||
|                         SiteChiM=zero; | ||||
|                     } | ||||
|  | ||||
|                     for(int sp=0; sp<2;  sp++){ | ||||
|                     for(int co=0; co<Nc; co++){ | ||||
|                         vbroadcast(BcastP()(sp)(co), psi[lex]()(sp)(co), l); | ||||
|                     }} | ||||
|  | ||||
|                     for(int sp=0; sp<2;  sp++){ | ||||
|                     for(int co=0; co<Nc; co++){ | ||||
|                         vbroadcast(BcastM()(sp)(co), psi[lex]()(sp+2)(co), l); | ||||
|                     }} | ||||
|  | ||||
|                     for(int sp=0; sp<2;  sp++){ | ||||
|                     for(int co=0; co<Nc; co++){ | ||||
|                         SiteChiP()(sp)(co) = real_madd(Matp[LLs*s+s1]()()(), BcastP()(sp)(co), SiteChiP()(sp)(co)); // 1100 us. | ||||
|                         SiteChiM()(sp)(co) = real_madd(Matm[LLs*s+s1]()()(), BcastM()(sp)(co), SiteChiM()(sp)(co)); // each found by commenting out | ||||
|                     }} | ||||
|                 }} | ||||
|  | ||||
|                 { | ||||
|                     int lex = s1 + LLs*site; | ||||
|                     for(int sp=0; sp<2;  sp++){ | ||||
|                     for(int co=0; co<Nc; co++){ | ||||
|                         vstream(chi[lex]()(sp)(co),   SiteChiP()(sp)(co)); | ||||
|                         vstream(chi[lex]()(sp+2)(co), SiteChiM()(sp)(co)); | ||||
|                     }} | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         #else | ||||
|         { | ||||
|             // pointers | ||||
|             //  MASK_REGS; | ||||
|             #define Chi_00 %%zmm1 | ||||
|             #define Chi_01 %%zmm2 | ||||
|             #define Chi_02 %%zmm3 | ||||
|             #define Chi_10 %%zmm4 | ||||
|             #define Chi_11 %%zmm5 | ||||
|             #define Chi_12 %%zmm6 | ||||
|             #define Chi_20 %%zmm7 | ||||
|             #define Chi_21 %%zmm8 | ||||
|             #define Chi_22 %%zmm9 | ||||
|             #define Chi_30 %%zmm10 | ||||
|             #define Chi_31 %%zmm11 | ||||
|             #define Chi_32 %%zmm12 | ||||
|  | ||||
|             #define BCAST0  %%zmm13 | ||||
|             #define BCAST1  %%zmm14 | ||||
|             #define BCAST2  %%zmm15 | ||||
|             #define BCAST3  %%zmm16 | ||||
|             #define BCAST4  %%zmm17 | ||||
|             #define BCAST5  %%zmm18 | ||||
|             #define BCAST6  %%zmm19 | ||||
|             #define BCAST7  %%zmm20 | ||||
|             #define BCAST8  %%zmm21 | ||||
|             #define BCAST9  %%zmm22 | ||||
|             #define BCAST10 %%zmm23 | ||||
|             #define BCAST11 %%zmm24 | ||||
|  | ||||
|             int incr = LLs*LLs*sizeof(iSinglet<Simd>); | ||||
|             for(int s1=0; s1<LLs; s1++){ | ||||
|  | ||||
|                 for(int s2=0; s2<LLs; s2++){ | ||||
|  | ||||
|                     int lex = s2 + LLs*site; | ||||
|                     uint64_t a0 = (uint64_t) &Matp[LLs*s2+s1]; // should be cacheable | ||||
|                     uint64_t a1 = (uint64_t) &Matm[LLs*s2+s1]; | ||||
|                     uint64_t a2 = (uint64_t) &psi[lex]; | ||||
|  | ||||
|                     for(int l=0; l<Simd::Nsimd(); l++){ // simd lane | ||||
|                         if((s2+l)==0) { | ||||
|                             asm( | ||||
|                                     VPREFETCH1(0,%2)              VPREFETCH1(0,%1) | ||||
|                                     VPREFETCH1(12,%2)  	          VPREFETCH1(13,%2) | ||||
|                                     VPREFETCH1(14,%2)  	          VPREFETCH1(15,%2) | ||||
|                                     VBCASTCDUP(0,%2,BCAST0) | ||||
|                                     VBCASTCDUP(1,%2,BCAST1) | ||||
|                                     VBCASTCDUP(2,%2,BCAST2) | ||||
|                                     VBCASTCDUP(3,%2,BCAST3) | ||||
|                                     VBCASTCDUP(4,%2,BCAST4)       VMULMEM(0,%0,BCAST0,Chi_00) | ||||
|                                     VBCASTCDUP(5,%2,BCAST5)       VMULMEM(0,%0,BCAST1,Chi_01) | ||||
|                                     VBCASTCDUP(6,%2,BCAST6)       VMULMEM(0,%0,BCAST2,Chi_02) | ||||
|                                     VBCASTCDUP(7,%2,BCAST7)       VMULMEM(0,%0,BCAST3,Chi_10) | ||||
|                                     VBCASTCDUP(8,%2,BCAST8)       VMULMEM(0,%0,BCAST4,Chi_11) | ||||
|                                     VBCASTCDUP(9,%2,BCAST9)       VMULMEM(0,%0,BCAST5,Chi_12) | ||||
|                                     VBCASTCDUP(10,%2,BCAST10)     VMULMEM(0,%1,BCAST6,Chi_20) | ||||
|                                     VBCASTCDUP(11,%2,BCAST11)     VMULMEM(0,%1,BCAST7,Chi_21) | ||||
|                                     VMULMEM(0,%1,BCAST8,Chi_22) | ||||
|                                     VMULMEM(0,%1,BCAST9,Chi_30) | ||||
|                                     VMULMEM(0,%1,BCAST10,Chi_31) | ||||
|                                     VMULMEM(0,%1,BCAST11,Chi_32) | ||||
|                                     : : "r" (a0), "r" (a1), "r" (a2)                            ); | ||||
|                         } else { | ||||
|                             asm( | ||||
|                                     VBCASTCDUP(0,%2,BCAST0)   VMADDMEM(0,%0,BCAST0,Chi_00) | ||||
|                                     VBCASTCDUP(1,%2,BCAST1)   VMADDMEM(0,%0,BCAST1,Chi_01) | ||||
|                                     VBCASTCDUP(2,%2,BCAST2)   VMADDMEM(0,%0,BCAST2,Chi_02) | ||||
|                                     VBCASTCDUP(3,%2,BCAST3)   VMADDMEM(0,%0,BCAST3,Chi_10) | ||||
|                                     VBCASTCDUP(4,%2,BCAST4)   VMADDMEM(0,%0,BCAST4,Chi_11) | ||||
|                                     VBCASTCDUP(5,%2,BCAST5)   VMADDMEM(0,%0,BCAST5,Chi_12) | ||||
|                                     VBCASTCDUP(6,%2,BCAST6)   VMADDMEM(0,%1,BCAST6,Chi_20) | ||||
|                                     VBCASTCDUP(7,%2,BCAST7)   VMADDMEM(0,%1,BCAST7,Chi_21) | ||||
|                                     VBCASTCDUP(8,%2,BCAST8)   VMADDMEM(0,%1,BCAST8,Chi_22) | ||||
|                                     VBCASTCDUP(9,%2,BCAST9)   VMADDMEM(0,%1,BCAST9,Chi_30) | ||||
|                                     VBCASTCDUP(10,%2,BCAST10) VMADDMEM(0,%1,BCAST10,Chi_31) | ||||
|                                     VBCASTCDUP(11,%2,BCAST11) VMADDMEM(0,%1,BCAST11,Chi_32) | ||||
|                                     : : "r" (a0), "r" (a1), "r" (a2)                            ); | ||||
|                         } | ||||
|                         a0 = a0 + incr; | ||||
|                         a1 = a1 + incr; | ||||
|                         a2 = a2 + sizeof(Simd::scalar_type); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 { | ||||
|                   int lexa = s1+LLs*site; | ||||
|                   asm ( | ||||
|                      VSTORE(0,%0,Chi_00) VSTORE(1 ,%0,Chi_01)  VSTORE(2 ,%0,Chi_02) | ||||
|                      VSTORE(3,%0,Chi_10) VSTORE(4 ,%0,Chi_11)  VSTORE(5 ,%0,Chi_12) | ||||
|                      VSTORE(6,%0,Chi_20) VSTORE(7 ,%0,Chi_21)  VSTORE(8 ,%0,Chi_22) | ||||
|                      VSTORE(9,%0,Chi_30) VSTORE(10,%0,Chi_31)  VSTORE(11,%0,Chi_32) | ||||
|                      : : "r" ((uint64_t)&chi[lexa]) : "memory" ); | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         #undef Chi_00 | ||||
|         #undef Chi_01 | ||||
|         #undef Chi_02 | ||||
|         #undef Chi_10 | ||||
|         #undef Chi_11 | ||||
|         #undef Chi_12 | ||||
|         #undef Chi_20 | ||||
|         #undef Chi_21 | ||||
|         #undef Chi_22 | ||||
|         #undef Chi_30 | ||||
|         #undef Chi_31 | ||||
|         #undef Chi_32 | ||||
|  | ||||
|         #undef BCAST0 | ||||
|         #undef BCAST1 | ||||
|         #undef BCAST2 | ||||
|         #undef BCAST3 | ||||
|         #undef BCAST4 | ||||
|         #undef BCAST5 | ||||
|         #undef BCAST6 | ||||
|         #undef BCAST7 | ||||
|         #undef BCAST8 | ||||
|         #undef BCAST9 | ||||
|         #undef BCAST10 | ||||
|         #undef BCAST11 | ||||
|         #endif | ||||
|     }; | ||||
|  | ||||
|     // Z-mobius version | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInternalZAsm(const FermionField& psi, FermionField& chi, | ||||
|         int LLs, int site, Vector<iSinglet<Simd> >& Matp, Vector<iSinglet<Simd> >& Matm) | ||||
|     { | ||||
|         std::cout << "Error: zMobius not implemented for EOFA" << std::endl; | ||||
|         exit(-1); | ||||
|     }; | ||||
|  | ||||
|     template<class Impl> | ||||
|     void DomainWallEOFAFermion<Impl>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv) | ||||
|     { | ||||
|         int Ls  = this->Ls; | ||||
|         int LLs = psi._grid->_rdimensions[0]; | ||||
|         int vol = psi._grid->oSites()/LLs; | ||||
|  | ||||
|         chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|         Vector<iSinglet<Simd> > Matp; | ||||
|         Vector<iSinglet<Simd> > Matm; | ||||
|         Vector<iSinglet<Simd> > *_Matp; | ||||
|         Vector<iSinglet<Simd> > *_Matm; | ||||
|  | ||||
|         //  MooeeInternalCompute(dag,inv,Matp,Matm); | ||||
|         if(inv && dag){ | ||||
|             _Matp = &this->MatpInvDag; | ||||
|             _Matm = &this->MatmInvDag; | ||||
|         } | ||||
|  | ||||
|         if(inv && (!dag)){ | ||||
|             _Matp = &this->MatpInv; | ||||
|             _Matm = &this->MatmInv; | ||||
|         } | ||||
|  | ||||
|         if(!inv){ | ||||
|             MooeeInternalCompute(dag, inv, Matp, Matm); | ||||
|             _Matp = &Matp; | ||||
|             _Matm = &Matm; | ||||
|         } | ||||
|  | ||||
|         assert(_Matp->size() == Ls*LLs); | ||||
|  | ||||
|         this->MooeeInvCalls++; | ||||
|         this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|         if(switcheroo<Coeff_t>::iscomplex()){ | ||||
|             parallel_for(auto site=0; site<vol; site++){ | ||||
|                 MooeeInternalZAsm(psi, chi, LLs, site, *_Matp, *_Matm); | ||||
|             } | ||||
|         } else { | ||||
|             parallel_for(auto site=0; site<vol; site++){ | ||||
|                 MooeeInternalAsm(psi, chi, LLs, site, *_Matp, *_Matm); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this->MooeeInvTime += usecond(); | ||||
|     } | ||||
|  | ||||
|     #ifdef DOMAIN_WALL_EOFA_DPERP_VEC | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(DomainWallVec5dImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(DomainWallVec5dImplF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZDomainWallVec5dImplD); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZDomainWallVec5dImplF); | ||||
|  | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(DomainWallVec5dImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(DomainWallVec5dImplFH); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZDomainWallVec5dImplDF); | ||||
|         INSTANTIATE_DPERP_DWF_EOFA(ZDomainWallVec5dImplFH); | ||||
|  | ||||
|         template void DomainWallEOFAFermion<DomainWallVec5dImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<DomainWallVec5dImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZDomainWallVec5dImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZDomainWallVec5dImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|         template void DomainWallEOFAFermion<DomainWallVec5dImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<DomainWallVec5dImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZDomainWallVec5dImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|         template void DomainWallEOFAFermion<ZDomainWallVec5dImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|     #endif | ||||
|  | ||||
| }} | ||||
| @@ -38,6 +38,8 @@ Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| // - ContinuedFractionFermion5D.cc | ||||
| // - WilsonFermion.cc | ||||
| // - WilsonKernels.cc | ||||
| // - DomainWallEOFAFermion.cc | ||||
| // - MobiusEOFAFermion.cc | ||||
| // | ||||
| // The explicit instantiation is only avoidable if we move this source to headers and end up with include/parse/recompile | ||||
| // for EVERY .cc file. This define centralises the list and restores global push of impl cases | ||||
| @@ -55,8 +57,9 @@ Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| #include <Grid/qcd/action/fermion/ImprovedStaggeredFermion5D.h> | ||||
| #include <Grid/qcd/action/fermion/CayleyFermion5D.h>     // Cayley types | ||||
| #include <Grid/qcd/action/fermion/DomainWallFermion.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallFermion.h> | ||||
| #include <Grid/qcd/action/fermion/DomainWallEOFAFermion.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusFermion.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusEOFAFermion.h> | ||||
| #include <Grid/qcd/action/fermion/ZMobiusFermion.h> | ||||
| #include <Grid/qcd/action/fermion/SchurDiagTwoKappa.h> | ||||
| #include <Grid/qcd/action/fermion/ScaledShamirFermion.h> | ||||
| @@ -113,6 +116,14 @@ typedef DomainWallFermion<WilsonImplRL> DomainWallFermionRL; | ||||
| typedef DomainWallFermion<WilsonImplFH> DomainWallFermionFH; | ||||
| typedef DomainWallFermion<WilsonImplDF> DomainWallFermionDF; | ||||
|  | ||||
| typedef DomainWallEOFAFermion<WilsonImplR> DomainWallEOFAFermionR; | ||||
| typedef DomainWallEOFAFermion<WilsonImplF> DomainWallEOFAFermionF; | ||||
| typedef DomainWallEOFAFermion<WilsonImplD> DomainWallEOFAFermionD; | ||||
|  | ||||
| typedef DomainWallEOFAFermion<WilsonImplRL> DomainWallEOFAFermionRL; | ||||
| typedef DomainWallEOFAFermion<WilsonImplFH> DomainWallEOFAFermionFH; | ||||
| typedef DomainWallEOFAFermion<WilsonImplDF> DomainWallEOFAFermionDF; | ||||
|  | ||||
| typedef MobiusFermion<WilsonImplR> MobiusFermionR; | ||||
| typedef MobiusFermion<WilsonImplF> MobiusFermionF; | ||||
| typedef MobiusFermion<WilsonImplD> MobiusFermionD; | ||||
| @@ -121,6 +132,14 @@ typedef MobiusFermion<WilsonImplRL> MobiusFermionRL; | ||||
| typedef MobiusFermion<WilsonImplFH> MobiusFermionFH; | ||||
| typedef MobiusFermion<WilsonImplDF> MobiusFermionDF; | ||||
|  | ||||
| typedef MobiusEOFAFermion<WilsonImplR> MobiusEOFAFermionR; | ||||
| typedef MobiusEOFAFermion<WilsonImplF> MobiusEOFAFermionF; | ||||
| typedef MobiusEOFAFermion<WilsonImplD> MobiusEOFAFermionD; | ||||
|  | ||||
| typedef MobiusEOFAFermion<WilsonImplRL> MobiusEOFAFermionRL; | ||||
| typedef MobiusEOFAFermion<WilsonImplFH> MobiusEOFAFermionFH; | ||||
| typedef MobiusEOFAFermion<WilsonImplDF> MobiusEOFAFermionDF; | ||||
|  | ||||
| typedef ZMobiusFermion<ZWilsonImplR> ZMobiusFermionR; | ||||
| typedef ZMobiusFermion<ZWilsonImplF> ZMobiusFermionF; | ||||
| typedef ZMobiusFermion<ZWilsonImplD> ZMobiusFermionD; | ||||
| @@ -138,6 +157,14 @@ typedef DomainWallFermion<DomainWallVec5dImplRL> DomainWallFermionVec5dRL; | ||||
| typedef DomainWallFermion<DomainWallVec5dImplFH> DomainWallFermionVec5dFH; | ||||
| typedef DomainWallFermion<DomainWallVec5dImplDF> DomainWallFermionVec5dDF; | ||||
|  | ||||
| typedef DomainWallEOFAFermion<DomainWallVec5dImplR> DomainWallEOFAFermionVec5dR; | ||||
| typedef DomainWallEOFAFermion<DomainWallVec5dImplF> DomainWallEOFAFermionVec5dF; | ||||
| typedef DomainWallEOFAFermion<DomainWallVec5dImplD> DomainWallEOFAFermionVec5dD; | ||||
|  | ||||
| typedef DomainWallEOFAFermion<DomainWallVec5dImplRL> DomainWallEOFAFermionVec5dRL; | ||||
| typedef DomainWallEOFAFermion<DomainWallVec5dImplFH> DomainWallEOFAFermionVec5dFH; | ||||
| typedef DomainWallEOFAFermion<DomainWallVec5dImplDF> DomainWallEOFAFermionVec5dDF; | ||||
|  | ||||
| typedef MobiusFermion<DomainWallVec5dImplR> MobiusFermionVec5dR; | ||||
| typedef MobiusFermion<DomainWallVec5dImplF> MobiusFermionVec5dF; | ||||
| typedef MobiusFermion<DomainWallVec5dImplD> MobiusFermionVec5dD; | ||||
| @@ -146,6 +173,14 @@ typedef MobiusFermion<DomainWallVec5dImplRL> MobiusFermionVec5dRL; | ||||
| typedef MobiusFermion<DomainWallVec5dImplFH> MobiusFermionVec5dFH; | ||||
| typedef MobiusFermion<DomainWallVec5dImplDF> MobiusFermionVec5dDF; | ||||
|  | ||||
| typedef MobiusEOFAFermion<DomainWallVec5dImplR> MobiusEOFAFermionVec5dR; | ||||
| typedef MobiusEOFAFermion<DomainWallVec5dImplF> MobiusEOFAFermionVec5dF; | ||||
| typedef MobiusEOFAFermion<DomainWallVec5dImplD> MobiusEOFAFermionVec5dD; | ||||
|  | ||||
| typedef MobiusEOFAFermion<DomainWallVec5dImplRL> MobiusEOFAFermionVec5dRL; | ||||
| typedef MobiusEOFAFermion<DomainWallVec5dImplFH> MobiusEOFAFermionVec5dFH; | ||||
| typedef MobiusEOFAFermion<DomainWallVec5dImplDF> MobiusEOFAFermionVec5dDF; | ||||
|  | ||||
| typedef ZMobiusFermion<ZDomainWallVec5dImplR> ZMobiusFermionVec5dR; | ||||
| typedef ZMobiusFermion<ZDomainWallVec5dImplF> ZMobiusFermionVec5dF; | ||||
| typedef ZMobiusFermion<ZDomainWallVec5dImplD> ZMobiusFermionVec5dD; | ||||
| @@ -206,6 +241,14 @@ typedef DomainWallFermion<GparityWilsonImplRL> GparityDomainWallFermionRL; | ||||
| typedef DomainWallFermion<GparityWilsonImplFH> GparityDomainWallFermionFH; | ||||
| typedef DomainWallFermion<GparityWilsonImplDF> GparityDomainWallFermionDF; | ||||
|  | ||||
| typedef DomainWallEOFAFermion<GparityWilsonImplR> GparityDomainWallEOFAFermionR; | ||||
| typedef DomainWallEOFAFermion<GparityWilsonImplF> GparityDomainWallEOFAFermionF; | ||||
| typedef DomainWallEOFAFermion<GparityWilsonImplD> GparityDomainWallEOFAFermionD; | ||||
|  | ||||
| typedef DomainWallEOFAFermion<GparityWilsonImplRL> GparityDomainWallEOFAFermionRL; | ||||
| typedef DomainWallEOFAFermion<GparityWilsonImplFH> GparityDomainWallEOFAFermionFH; | ||||
| typedef DomainWallEOFAFermion<GparityWilsonImplDF> GparityDomainWallEOFAFermionDF; | ||||
|  | ||||
| typedef WilsonTMFermion<GparityWilsonImplR> GparityWilsonTMFermionR; | ||||
| typedef WilsonTMFermion<GparityWilsonImplF> GparityWilsonTMFermionF; | ||||
| typedef WilsonTMFermion<GparityWilsonImplD> GparityWilsonTMFermionD; | ||||
| @@ -222,6 +265,14 @@ typedef MobiusFermion<GparityWilsonImplRL> GparityMobiusFermionRL; | ||||
| typedef MobiusFermion<GparityWilsonImplFH> GparityMobiusFermionFH; | ||||
| typedef MobiusFermion<GparityWilsonImplDF> GparityMobiusFermionDF; | ||||
|  | ||||
| typedef MobiusEOFAFermion<GparityWilsonImplR> GparityMobiusEOFAFermionR; | ||||
| typedef MobiusEOFAFermion<GparityWilsonImplF> GparityMobiusEOFAFermionF; | ||||
| typedef MobiusEOFAFermion<GparityWilsonImplD> GparityMobiusEOFAFermionD; | ||||
|  | ||||
| typedef MobiusEOFAFermion<GparityWilsonImplRL> GparityMobiusEOFAFermionRL; | ||||
| typedef MobiusEOFAFermion<GparityWilsonImplFH> GparityMobiusEOFAFermionFH; | ||||
| typedef MobiusEOFAFermion<GparityWilsonImplDF> GparityMobiusEOFAFermionDF; | ||||
|  | ||||
| typedef ImprovedStaggeredFermion<StaggeredImplR> ImprovedStaggeredFermionR; | ||||
| typedef ImprovedStaggeredFermion<StaggeredImplF> ImprovedStaggeredFermionF; | ||||
| typedef ImprovedStaggeredFermion<StaggeredImplD> ImprovedStaggeredFermionD; | ||||
|   | ||||
| @@ -538,6 +538,12 @@ class GparityWilsonImpl : public ConjugateGaugeImpl<GaugeImplTypes<S, Nrepresent | ||||
|     | ||||
|  } | ||||
|  | ||||
|  | ||||
|  template <class ref> | ||||
|  inline void loadLinkElement(Simd ®, ref &memory) { | ||||
|    reg = memory; | ||||
|  } | ||||
|  | ||||
|  inline void DoubleStore(GridBase *GaugeGrid,DoubledGaugeField &Uds,const GaugeField &Umu) | ||||
|  { | ||||
|    conformable(Uds._grid,GaugeGrid); | ||||
|   | ||||
							
								
								
									
										502
									
								
								lib/qcd/action/fermion/MobiusEOFAFermion.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										502
									
								
								lib/qcd/action/fermion/MobiusEOFAFermion.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,502 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/MobiusEOFAFermion.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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_Eigen_Dense.h> | ||||
| #include <Grid/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   template<class Impl> | ||||
|     MobiusEOFAFermion<Impl>::MobiusEOFAFermion( | ||||
|       GaugeField            &_Umu, | ||||
|       GridCartesian         &FiveDimGrid, | ||||
|       GridRedBlackCartesian &FiveDimRedBlackGrid, | ||||
|       GridCartesian         &FourDimGrid, | ||||
|       GridRedBlackCartesian &FourDimRedBlackGrid, | ||||
|       RealD _mq1, RealD _mq2, RealD _mq3, | ||||
|       RealD _shift, int _pm, RealD _M5, | ||||
|       RealD _b, RealD _c, const ImplParams &p) : | ||||
|     AbstractEOFAFermion<Impl>(_Umu, FiveDimGrid, FiveDimRedBlackGrid, | ||||
|         FourDimGrid, FourDimRedBlackGrid, _mq1, _mq2, _mq3, | ||||
|         _shift, _pm, _M5, _b, _c, p) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       RealD eps = 1.0; | ||||
|       Approx::zolotarev_data *zdata = Approx::higham(eps, this->Ls); | ||||
|       assert(zdata->n == this->Ls); | ||||
|  | ||||
|       std::cout << GridLogMessage << "MobiusEOFAFermion (b=" << _b << | ||||
|         ",c=" << _c << ") with Ls=" << Ls << std::endl; | ||||
|       this->SetCoefficientsTanh(zdata, _b, _c); | ||||
|       std::cout << GridLogMessage << "EOFA parameters: (mq1=" << _mq1 << | ||||
|         ",mq2=" << _mq2 << ",mq3=" << _mq3 << ",shift=" << _shift << | ||||
|         ",pm=" << _pm << ")" << std::endl; | ||||
|  | ||||
|       Approx::zolotarev_free(zdata); | ||||
|  | ||||
|       if(_shift != 0.0){ | ||||
|         SetCoefficientsPrecondShiftOps(); | ||||
|       } else { | ||||
|         Mooee_shift.resize(Ls, 0.0); | ||||
|         MooeeInv_shift_lc.resize(Ls, 0.0); | ||||
|         MooeeInv_shift_norm.resize(Ls, 0.0); | ||||
|         MooeeInvDag_shift_lc.resize(Ls, 0.0); | ||||
|         MooeeInvDag_shift_norm.resize(Ls, 0.0); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /**************************************************************** | ||||
|      * Additional EOFA operators only called outside the inverter.   | ||||
|      * Since speed is not essential, simple axpby-style | ||||
|      * implementations should be fine. | ||||
|      ***************************************************************/ | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::Omega(const FermionField& psi, FermionField& Din, int sign, int dag) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|       RealD alpha = this->alpha; | ||||
|  | ||||
|       Din = zero; | ||||
|       if((sign == 1) && (dag == 0)) { // \Omega_{+} | ||||
|         for(int s=0; s<Ls; ++s){ | ||||
|           axpby_ssp(Din, 0.0, psi, 2.0*std::pow(1.0-alpha,Ls-s-1)/std::pow(1.0+alpha,Ls-s), psi, s, 0); | ||||
|         } | ||||
|       } else if((sign == -1) && (dag == 0)) { // \Omega_{-} | ||||
|         for(int s=0; s<Ls; ++s){ | ||||
|           axpby_ssp(Din, 0.0, psi, 2.0*std::pow(1.0-alpha,s)/std::pow(1.0+alpha,s+1), psi, s, 0); | ||||
|         } | ||||
|       } else if((sign == 1 ) && (dag == 1)) { // \Omega_{+}^{\dagger} | ||||
|         for(int sp=0; sp<Ls; ++sp){ | ||||
|           axpby_ssp(Din, 1.0, Din, 2.0*std::pow(1.0-alpha,Ls-sp-1)/std::pow(1.0+alpha,Ls-sp), psi, 0, sp); | ||||
|         } | ||||
|       } else if((sign == -1) && (dag == 1)) { // \Omega_{-}^{\dagger} | ||||
|         for(int sp=0; sp<Ls; ++sp){ | ||||
|           axpby_ssp(Din, 1.0, Din, 2.0*std::pow(1.0-alpha,sp)/std::pow(1.0+alpha,sp+1), psi, 0, sp); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // This is the operator relating the usual Ddwf to TWQCD's EOFA Dirac operator (arXiv:1706.05843, Eqn. 6). | ||||
|     // It also relates the preconditioned and unpreconditioned systems described in Appendix B.2. | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::Dtilde(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls    = this->Ls; | ||||
|       RealD b   = 0.5 * ( 1.0 + this->alpha ); | ||||
|       RealD c   = 0.5 * ( 1.0 - this->alpha ); | ||||
|       RealD mq1 = this->mq1; | ||||
|  | ||||
|       for(int s=0; s<Ls; ++s){ | ||||
|         if(s == 0) { | ||||
|           axpby_ssp_pminus(chi, b, psi, -c, psi, s, s+1); | ||||
|           axpby_ssp_pplus (chi, 1.0, chi, mq1*c, psi, s, Ls-1); | ||||
|         } else if(s == (Ls-1)) { | ||||
|           axpby_ssp_pminus(chi, b, psi, mq1*c, psi, s, 0); | ||||
|           axpby_ssp_pplus (chi, 1.0, chi, -c, psi, s, s-1); | ||||
|         } else { | ||||
|           axpby_ssp_pminus(chi, b, psi, -c, psi, s, s+1); | ||||
|           axpby_ssp_pplus (chi, 1.0, chi, -c, psi, s, s-1); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::DtildeInv(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|       RealD m = this->mq1; | ||||
|       RealD c = 0.5 * this->alpha; | ||||
|       RealD d = 0.5; | ||||
|  | ||||
|       RealD DtInv_p(0.0), DtInv_m(0.0); | ||||
|       RealD N = std::pow(c+d,Ls) + m*std::pow(c-d,Ls); | ||||
|       FermionField tmp(this->FermionGrid()); | ||||
|  | ||||
|       for(int s=0; s<Ls; ++s){ | ||||
|       for(int sp=0; sp<Ls; ++sp){ | ||||
|  | ||||
|         DtInv_p = m * std::pow(-1.0,s-sp+1) * std::pow(c-d,Ls+s-sp) / std::pow(c+d,s-sp+1) / N; | ||||
|         DtInv_p += (s < sp) ? 0.0 : std::pow(-1.0,s-sp) * std::pow(c-d,s-sp) / std::pow(c+d,s-sp+1); | ||||
|         DtInv_m = m * std::pow(-1.0,sp-s+1) * std::pow(c-d,Ls+sp-s) / std::pow(c+d,sp-s+1) / N; | ||||
|         DtInv_m += (s > sp) ? 0.0 : std::pow(-1.0,sp-s) * std::pow(c-d,sp-s) / std::pow(c+d,sp-s+1); | ||||
|  | ||||
|         if(sp == 0){ | ||||
|           axpby_ssp_pplus (tmp, 0.0, tmp, DtInv_p, psi, s, sp); | ||||
|           axpby_ssp_pminus(tmp, 0.0, tmp, DtInv_m, psi, s, sp); | ||||
|         } else { | ||||
|           axpby_ssp_pplus (tmp, 1.0, tmp, DtInv_p, psi, s, sp); | ||||
|           axpby_ssp_pminus(tmp, 1.0, tmp, DtInv_m, psi, s, sp); | ||||
|         } | ||||
|  | ||||
|       }} | ||||
|     } | ||||
|  | ||||
|     /*****************************************************************************************************/ | ||||
|  | ||||
|     template<class Impl> | ||||
|     RealD MobiusEOFAFermion<Impl>::M(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       FermionField Din(psi._grid); | ||||
|  | ||||
|       this->Meooe5D(psi, Din); | ||||
|       this->DW(Din, chi, DaggerNo); | ||||
|       axpby(chi, 1.0, 1.0, chi, psi); | ||||
|       this->M5D(psi, chi); | ||||
|       return(norm2(chi)); | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     RealD MobiusEOFAFermion<Impl>::Mdag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       FermionField Din(psi._grid); | ||||
|  | ||||
|       this->DW(psi, Din, DaggerYes); | ||||
|       this->MeooeDag5D(Din, chi); | ||||
|       this->M5Ddag(psi, chi); | ||||
|       axpby(chi, 1.0, 1.0, chi, psi); | ||||
|       return(norm2(chi)); | ||||
|     } | ||||
|  | ||||
|     /******************************************************************** | ||||
|      * Performance critical fermion operators called inside the inverter | ||||
|      ********************************************************************/ | ||||
|  | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::M5D(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       std::vector<Coeff_t> diag(Ls,1.0); | ||||
|       std::vector<Coeff_t> upper(Ls,-1.0);  upper[Ls-1] = this->mq1; | ||||
|       std::vector<Coeff_t> lower(Ls,-1.0);  lower[0]    = this->mq1; | ||||
|  | ||||
|       // no shift term | ||||
|       if(this->shift == 0.0){ this->M5D(psi, chi, chi, lower, diag, upper); } | ||||
|  | ||||
|       // fused M + shift operation | ||||
|       else{ this->M5D_shift(psi, chi, chi, lower, diag, upper, Mooee_shift); } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::M5Ddag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       std::vector<Coeff_t> diag(Ls,1.0); | ||||
|       std::vector<Coeff_t> upper(Ls,-1.0);  upper[Ls-1] = this->mq1; | ||||
|       std::vector<Coeff_t> lower(Ls,-1.0);  lower[0]    = this->mq1; | ||||
|  | ||||
|       // no shift term | ||||
|       if(this->shift == 0.0){ this->M5Ddag(psi, chi, chi, lower, diag, upper); } | ||||
|  | ||||
|       // fused M + shift operation | ||||
|       else{ this->M5Ddag_shift(psi, chi, chi, lower, diag, upper, Mooee_shift); } | ||||
|     } | ||||
|  | ||||
|     // half checkerboard operations | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::Mooee(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       // coefficients of Mooee | ||||
|       std::vector<Coeff_t> diag = this->bee; | ||||
|       std::vector<Coeff_t> upper(Ls); | ||||
|       std::vector<Coeff_t> lower(Ls); | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         upper[s] = -this->cee[s]; | ||||
|         lower[s] = -this->cee[s]; | ||||
|       } | ||||
|       upper[Ls-1] *= -this->mq1; | ||||
|       lower[0]    *= -this->mq1; | ||||
|  | ||||
|       // no shift term | ||||
|       if(this->shift == 0.0){ this->M5D(psi, psi, chi, lower, diag, upper); } | ||||
|  | ||||
|       // fused M + shift operation | ||||
|       else { this->M5D_shift(psi, psi, chi, lower, diag, upper, Mooee_shift); } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::MooeeDag(const FermionField& psi, FermionField& chi) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       // coefficients of MooeeDag | ||||
|       std::vector<Coeff_t> diag = this->bee; | ||||
|       std::vector<Coeff_t> upper(Ls); | ||||
|       std::vector<Coeff_t> lower(Ls); | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         if(s==0) { | ||||
|           upper[s] = -this->cee[s+1]; | ||||
|           lower[s] = this->mq1*this->cee[Ls-1]; | ||||
|         } else if(s==(Ls-1)) { | ||||
|           upper[s] = this->mq1*this->cee[0]; | ||||
|           lower[s] = -this->cee[s-1]; | ||||
|         } else { | ||||
|           upper[s] = -this->cee[s+1]; | ||||
|           lower[s] = -this->cee[s-1]; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // no shift term | ||||
|       if(this->shift == 0.0){ this->M5Ddag(psi, psi, chi, lower, diag, upper); } | ||||
|  | ||||
|       // fused M + shift operation | ||||
|       else{ this->M5Ddag_shift(psi, psi, chi, lower, diag, upper, Mooee_shift); } | ||||
|     } | ||||
|  | ||||
|     /****************************************************************************************/ | ||||
|  | ||||
|     // Computes coefficients for applying Cayley preconditioned shift operators | ||||
|     //  (Mooee + \Delta) --> Mooee_shift | ||||
|     //  (Mooee + \Delta)^{-1} --> MooeeInv_shift_lc, MooeeInv_shift_norm | ||||
|     //  (Mooee + \Delta)^{-dag} --> MooeeInvDag_shift_lc, MooeeInvDag_shift_norm | ||||
|     // For the latter two cases, the operation takes the form | ||||
|     //  [ (Mooee + \Delta)^{-1} \psi ]_{i} = Mooee_{ij} \psi_{j} + | ||||
|     //      ( MooeeInv_shift_norm )_{i} ( \sum_{j} [ MooeeInv_shift_lc ]_{j} P_{pm} \psi_{j} ) | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::SetCoefficientsPrecondShiftOps() | ||||
|     { | ||||
|       int   Ls    = this->Ls; | ||||
|       int   pm    = this->pm; | ||||
|       RealD alpha = this->alpha; | ||||
|       RealD k     = this->k; | ||||
|       RealD mq1   = this->mq1; | ||||
|       RealD shift = this->shift; | ||||
|  | ||||
|       // Initialize | ||||
|       Mooee_shift.resize(Ls); | ||||
|       MooeeInv_shift_lc.resize(Ls); | ||||
|       MooeeInv_shift_norm.resize(Ls); | ||||
|       MooeeInvDag_shift_lc.resize(Ls); | ||||
|       MooeeInvDag_shift_norm.resize(Ls); | ||||
|  | ||||
|       // Construct Mooee_shift | ||||
|       int idx(0); | ||||
|       Coeff_t N = ( (pm == 1) ? 1.0 : -1.0 ) * (2.0*shift*k) * | ||||
|                   ( std::pow(alpha+1.0,Ls) + mq1*std::pow(alpha-1.0,Ls) ); | ||||
|       for(int s=0; s<Ls; ++s){ | ||||
|         idx = (pm == 1) ? (s) : (Ls-1-s); | ||||
|         Mooee_shift[idx] = N * std::pow(-1.0,s) * std::pow(alpha-1.0,s) / std::pow(alpha+1.0,Ls+s+1); | ||||
|       } | ||||
|  | ||||
|       // Tridiagonal solve for MooeeInvDag_shift_lc | ||||
|       { | ||||
|         Coeff_t m(0.0); | ||||
|         std::vector<Coeff_t> d = Mooee_shift; | ||||
|         std::vector<Coeff_t> u(Ls,0.0); | ||||
|         std::vector<Coeff_t> y(Ls,0.0); | ||||
|         std::vector<Coeff_t> q(Ls,0.0); | ||||
|         if(pm == 1){ u[0] = 1.0; } | ||||
|         else{ u[Ls-1] = 1.0; } | ||||
|  | ||||
|         // Tridiagonal matrix algorithm + Sherman-Morrison formula | ||||
|         // | ||||
|         // We solve | ||||
|         //  ( Mooee' + u \otimes v ) MooeeInvDag_shift_lc = Mooee_shift | ||||
|         // where Mooee' is the tridiagonal part of Mooee_{+}, and | ||||
|         // u = (1,0,...,0) and v = (0,...,0,mq1*cee[0]) are chosen | ||||
|         // so that the outer-product u \otimes v gives the (0,Ls-1) | ||||
|         // entry of Mooee_{+}. | ||||
|         // | ||||
|         // We do this as two solves: Mooee'*y = d and Mooee'*q = u, | ||||
|         // and then construct the solution to the original system | ||||
|         //  MooeeInvDag_shift_lc = y - <v,y> / ( 1 + <v,q> ) q | ||||
|         if(pm == 1){ | ||||
|           for(int s=1; s<Ls; ++s){ | ||||
|             m = -this->cee[s] / this->bee[s-1]; | ||||
|             d[s] -= m*d[s-1]; | ||||
|             u[s] -= m*u[s-1]; | ||||
|           } | ||||
|         } | ||||
|         y[Ls-1] = d[Ls-1] / this->bee[Ls-1]; | ||||
|         q[Ls-1] = u[Ls-1] / this->bee[Ls-1]; | ||||
|         for(int s=Ls-2; s>=0; --s){ | ||||
|           if(pm == 1){ | ||||
|             y[s] = d[s] / this->bee[s]; | ||||
|             q[s] = u[s] / this->bee[s]; | ||||
|           } else { | ||||
|             y[s] = ( d[s] + this->cee[s]*y[s+1] ) / this->bee[s]; | ||||
|             q[s] = ( u[s] + this->cee[s]*q[s+1] ) / this->bee[s]; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         // Construct MooeeInvDag_shift_lc | ||||
|         for(int s=0; s<Ls; ++s){ | ||||
|           if(pm == 1){ | ||||
|             MooeeInvDag_shift_lc[s] = y[s] - mq1*this->cee[0]*y[Ls-1] / | ||||
|               (1.0+mq1*this->cee[0]*q[Ls-1]) * q[s]; | ||||
|           } else { | ||||
|             MooeeInvDag_shift_lc[s] = y[s] - mq1*this->cee[Ls-1]*y[0] / | ||||
|               (1.0+mq1*this->cee[Ls-1]*q[0]) * q[s]; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         // Compute remaining coefficients | ||||
|         N = (pm == 1) ? (1.0 + MooeeInvDag_shift_lc[Ls-1]) : (1.0 + MooeeInvDag_shift_lc[0]); | ||||
|         for(int s=0; s<Ls; ++s){ | ||||
|  | ||||
|           // MooeeInv_shift_lc | ||||
|           if(pm == 1){ MooeeInv_shift_lc[s] = std::pow(this->bee[s],s) * std::pow(this->cee[s],Ls-1-s); } | ||||
|           else{ MooeeInv_shift_lc[s] = std::pow(this->bee[s],Ls-1-s) * std::pow(this->cee[s],s); } | ||||
|  | ||||
|           // MooeeInv_shift_norm | ||||
|           MooeeInv_shift_norm[s] = -MooeeInvDag_shift_lc[s] / | ||||
|             ( std::pow(this->bee[s],Ls) + mq1*std::pow(this->cee[s],Ls) ) / N; | ||||
|  | ||||
|           // MooeeInvDag_shift_norm | ||||
|           if(pm == 1){ MooeeInvDag_shift_norm[s] = -std::pow(this->bee[s],s) * std::pow(this->cee[s],Ls-1-s) / | ||||
|             ( std::pow(this->bee[s],Ls) + mq1*std::pow(this->cee[s],Ls) ) / N; } | ||||
|           else{ MooeeInvDag_shift_norm[s] = -std::pow(this->bee[s],Ls-1-s) * std::pow(this->cee[s],s) / | ||||
|             ( std::pow(this->bee[s],Ls) + mq1*std::pow(this->cee[s],Ls) ) / N; } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Recompute coefficients for a different value of shift constant | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::RefreshShiftCoefficients(RealD new_shift) | ||||
|     { | ||||
|       this->shift = new_shift; | ||||
|       if(new_shift != 0.0){ | ||||
|         SetCoefficientsPrecondShiftOps(); | ||||
|       } else { | ||||
|         int Ls = this->Ls; | ||||
|         Mooee_shift.resize(Ls,0.0); | ||||
|         MooeeInv_shift_lc.resize(Ls,0.0); | ||||
|         MooeeInv_shift_norm.resize(Ls,0.0); | ||||
|         MooeeInvDag_shift_lc.resize(Ls,0.0); | ||||
|         MooeeInvDag_shift_norm.resize(Ls,0.0); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     template<class Impl> | ||||
|     void MobiusEOFAFermion<Impl>::MooeeInternalCompute(int dag, int inv, | ||||
|       Vector<iSinglet<Simd> >& Matp, Vector<iSinglet<Simd> >& Matm) | ||||
|     { | ||||
|       int Ls = this->Ls; | ||||
|  | ||||
|       GridBase* grid = this->FermionRedBlackGrid(); | ||||
|       int LLs = grid->_rdimensions[0]; | ||||
|  | ||||
|       if(LLs == Ls){ return; } // Not vectorised in 5th direction | ||||
|  | ||||
|       Eigen::MatrixXcd Pplus  = Eigen::MatrixXcd::Zero(Ls,Ls); | ||||
|       Eigen::MatrixXcd Pminus = Eigen::MatrixXcd::Zero(Ls,Ls); | ||||
|  | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         Pplus(s,s)  = this->bee[s]; | ||||
|         Pminus(s,s) = this->bee[s]; | ||||
|       } | ||||
|  | ||||
|       for(int s=0; s<Ls-1; s++){ | ||||
|         Pminus(s,s+1) = -this->cee[s]; | ||||
|         Pplus(s+1,s) = -this->cee[s+1]; | ||||
|       } | ||||
|  | ||||
|       Pplus (0,Ls-1) = this->mq1*this->cee[0]; | ||||
|       Pminus(Ls-1,0) = this->mq1*this->cee[Ls-1]; | ||||
|  | ||||
|       if(this->shift != 0.0){ | ||||
|         RealD c = 0.5 * this->alpha; | ||||
|         RealD d = 0.5; | ||||
|         RealD N = this->shift * this->k * ( std::pow(c+d,Ls) + this->mq1*std::pow(c-d,Ls) ); | ||||
|         if(this->pm == 1) { | ||||
|           for(int s=0; s<Ls; ++s){ | ||||
|             Pplus(s,Ls-1) += N * std::pow(-1.0,s) * std::pow(c-d,s) / std::pow(c+d,Ls+s+1); | ||||
|           } | ||||
|         } else { | ||||
|           for(int s=0; s<Ls; ++s){ | ||||
|             Pminus(s,0) += N * std::pow(-1.0,s+1) * std::pow(c-d,Ls-1-s) / std::pow(c+d,2*Ls-s); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       Eigen::MatrixXcd PplusMat ; | ||||
|       Eigen::MatrixXcd PminusMat; | ||||
|  | ||||
|       if(inv) { | ||||
|         PplusMat  = Pplus.inverse(); | ||||
|         PminusMat = Pminus.inverse(); | ||||
|       } else { | ||||
|         PplusMat  = Pplus; | ||||
|         PminusMat = Pminus; | ||||
|       } | ||||
|  | ||||
|       if(dag){ | ||||
|         PplusMat.adjointInPlace(); | ||||
|         PminusMat.adjointInPlace(); | ||||
|       } | ||||
|  | ||||
|       typedef typename SiteHalfSpinor::scalar_type scalar_type; | ||||
|       const int Nsimd = Simd::Nsimd(); | ||||
|       Matp.resize(Ls*LLs); | ||||
|       Matm.resize(Ls*LLs); | ||||
|  | ||||
|       for(int s2=0; s2<Ls; s2++){ | ||||
|       for(int s1=0; s1<LLs; s1++){ | ||||
|         int istride = LLs; | ||||
|         int ostride = 1; | ||||
|         Simd Vp; | ||||
|         Simd Vm; | ||||
|         scalar_type *sp = (scalar_type*) &Vp; | ||||
|         scalar_type *sm = (scalar_type*) &Vm; | ||||
|         for(int l=0; l<Nsimd; l++){ | ||||
|           if(switcheroo<Coeff_t>::iscomplex()) { | ||||
|             sp[l] = PplusMat (l*istride+s1*ostride,s2); | ||||
|             sm[l] = PminusMat(l*istride+s1*ostride,s2); | ||||
|           } else { | ||||
|             // if real | ||||
|             scalar_type tmp; | ||||
|             tmp = PplusMat (l*istride+s1*ostride,s2); | ||||
|             sp[l] = scalar_type(tmp.real(),tmp.real()); | ||||
|             tmp = PminusMat(l*istride+s1*ostride,s2); | ||||
|             sm[l] = scalar_type(tmp.real(),tmp.real()); | ||||
|           } | ||||
|         } | ||||
|         Matp[LLs*s2+s1] = Vp; | ||||
|         Matm[LLs*s2+s1] = Vm; | ||||
|       }} | ||||
|   } | ||||
|  | ||||
|   FermOpTemplateInstantiate(MobiusEOFAFermion); | ||||
|   GparityFermOpTemplateInstantiate(MobiusEOFAFermion); | ||||
|  | ||||
| }} | ||||
							
								
								
									
										133
									
								
								lib/qcd/action/fermion/MobiusEOFAFermion.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								lib/qcd/action/fermion/MobiusEOFAFermion.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/MobiusEOFAFermion.h | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| 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 */ | ||||
| #ifndef  GRID_QCD_MOBIUS_EOFA_FERMION_H | ||||
| #define  GRID_QCD_MOBIUS_EOFA_FERMION_H | ||||
|  | ||||
| #include <Grid/qcd/action/fermion/AbstractEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   template<class Impl> | ||||
|   class MobiusEOFAFermion : public AbstractEOFAFermion<Impl> | ||||
|   { | ||||
|     public: | ||||
|       INHERIT_IMPL_TYPES(Impl); | ||||
|  | ||||
|     public: | ||||
|       // Shift operator coefficients for red-black preconditioned Mobius EOFA | ||||
|       std::vector<Coeff_t> Mooee_shift; | ||||
|       std::vector<Coeff_t> MooeeInv_shift_lc; | ||||
|       std::vector<Coeff_t> MooeeInv_shift_norm; | ||||
|       std::vector<Coeff_t> MooeeInvDag_shift_lc; | ||||
|       std::vector<Coeff_t> MooeeInvDag_shift_norm; | ||||
|  | ||||
|       virtual void Instantiatable(void) {}; | ||||
|  | ||||
|       // EOFA-specific operations | ||||
|       virtual void  Omega            (const FermionField& in, FermionField& out, int sign, int dag); | ||||
|       virtual void  Dtilde           (const FermionField& in, FermionField& out); | ||||
|       virtual void  DtildeInv        (const FermionField& in, FermionField& out); | ||||
|  | ||||
|       // override multiply | ||||
|       virtual RealD M                (const FermionField& in, FermionField& out); | ||||
|       virtual RealD Mdag             (const FermionField& in, FermionField& out); | ||||
|  | ||||
|       // half checkerboard operations | ||||
|       virtual void  Mooee            (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeDag         (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeInv         (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeInv_shift   (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeInvDag      (const FermionField& in, FermionField& out); | ||||
|       virtual void  MooeeInvDag_shift(const FermionField& in, FermionField& out); | ||||
|  | ||||
|       virtual void   M5D             (const FermionField& psi, FermionField& chi); | ||||
|       virtual void   M5Ddag          (const FermionField& psi, FermionField& chi); | ||||
|  | ||||
|       ///////////////////////////////////////////////////// | ||||
|       // Instantiate different versions depending on Impl | ||||
|       ///////////////////////////////////////////////////// | ||||
|       void M5D(const FermionField& psi, const FermionField& phi, FermionField& chi, | ||||
|         std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); | ||||
|  | ||||
|       void M5D_shift(const FermionField& psi, const FermionField& phi, FermionField& chi, | ||||
|         std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, | ||||
|         std::vector<Coeff_t>& shift_coeffs); | ||||
|  | ||||
|       void M5Ddag(const FermionField& psi, const FermionField& phi, FermionField& chi, | ||||
|         std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); | ||||
|  | ||||
|       void M5Ddag_shift(const FermionField& psi, const FermionField& phi, FermionField& chi, | ||||
|         std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, | ||||
|         std::vector<Coeff_t>& shift_coeffs); | ||||
|  | ||||
|       void MooeeInternal(const FermionField& in, FermionField& out, int dag, int inv); | ||||
|  | ||||
|       void MooeeInternalCompute(int dag, int inv, Vector<iSinglet<Simd>>& Matp, Vector<iSinglet<Simd>>& Matm); | ||||
|  | ||||
|       void MooeeInternalAsm(const FermionField& in, FermionField& out, int LLs, int site, | ||||
|         Vector<iSinglet<Simd>>& Matp, Vector<iSinglet<Simd>>& Matm); | ||||
|  | ||||
|       void MooeeInternalZAsm(const FermionField& in, FermionField& out, int LLs, int site, | ||||
|         Vector<iSinglet<Simd>>& Matp, Vector<iSinglet<Simd>>& Matm); | ||||
|  | ||||
|       virtual void RefreshShiftCoefficients(RealD new_shift); | ||||
|  | ||||
|       // Constructors | ||||
|       MobiusEOFAFermion(GaugeField& _Umu, GridCartesian& FiveDimGrid, GridRedBlackCartesian& FiveDimRedBlackGrid, | ||||
|         GridCartesian& FourDimGrid, GridRedBlackCartesian& FourDimRedBlackGrid, | ||||
|         RealD _mq1, RealD _mq2, RealD _mq3, RealD _shift, int pm, | ||||
|         RealD _M5, RealD _b, RealD _c, const ImplParams& p=ImplParams()); | ||||
|  | ||||
|     protected: | ||||
|       void SetCoefficientsPrecondShiftOps(void); | ||||
|   }; | ||||
| }} | ||||
|  | ||||
| #define INSTANTIATE_DPERP_MOBIUS_EOFA(A)\ | ||||
| template void MobiusEOFAFermion<A>::M5D(const FermionField& psi, const FermionField& phi, FermionField& chi, \ | ||||
|   std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); \ | ||||
| template void MobiusEOFAFermion<A>::M5D_shift(const FermionField& psi, const FermionField& phi, FermionField& chi, \ | ||||
|   std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, std::vector<Coeff_t>& shift_coeffs); \ | ||||
| template void MobiusEOFAFermion<A>::M5Ddag(const FermionField& psi, const FermionField& phi, FermionField& chi, \ | ||||
|   std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper); \ | ||||
| template void MobiusEOFAFermion<A>::M5Ddag_shift(const FermionField& psi, const FermionField& phi, FermionField& chi, \ | ||||
|   std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, std::vector<Coeff_t>& shift_coeffs); \ | ||||
| template void MobiusEOFAFermion<A>::MooeeInv(const FermionField& psi, FermionField& chi); \ | ||||
| template void MobiusEOFAFermion<A>::MooeeInv_shift(const FermionField& psi, FermionField& chi); \ | ||||
| template void MobiusEOFAFermion<A>::MooeeInvDag(const FermionField& psi, FermionField& chi); \ | ||||
| template void MobiusEOFAFermion<A>::MooeeInvDag_shift(const FermionField& psi, FermionField& chi); | ||||
|  | ||||
| #undef  MOBIUS_EOFA_DPERP_DENSE | ||||
| #define MOBIUS_EOFA_DPERP_CACHE | ||||
| #undef  MOBIUS_EOFA_DPERP_LINALG | ||||
| #define MOBIUS_EOFA_DPERP_VEC | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										429
									
								
								lib/qcd/action/fermion/MobiusEOFAFermioncache.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								lib/qcd/action/fermion/MobiusEOFAFermioncache.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,429 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/MobiusEOFAFermioncache.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   // FIXME -- make a version of these routines with site loop outermost for cache reuse. | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5D(const FermionField &psi, const FermionField &phi, FermionField &chi, | ||||
|     std::vector<Coeff_t> &lower, std::vector<Coeff_t> &diag, std::vector<Coeff_t> &upper) | ||||
|   { | ||||
|     int Ls = this->Ls; | ||||
|     GridBase *grid = psi._grid; | ||||
|  | ||||
|     assert(phi.checkerboard == psi.checkerboard); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     // Flops = 6.0*(Nc*Ns) *Ls*vol | ||||
|     this->M5Dcalls++; | ||||
|     this->M5Dtime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         auto tmp = psi._odata[0]; | ||||
|         if(s==0){ | ||||
|           spProj5m(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5p(tmp, psi._odata[ss+Ls-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else if(s==(Ls-1)) { | ||||
|           spProj5m(tmp, psi._odata[ss+0]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5p(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else { | ||||
|           spProj5m(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5p(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->M5Dtime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5D_shift(const FermionField &psi, const FermionField &phi, FermionField &chi, | ||||
|     std::vector<Coeff_t> &lower, std::vector<Coeff_t> &diag, std::vector<Coeff_t> &upper, | ||||
|     std::vector<Coeff_t> &shift_coeffs) | ||||
|   { | ||||
|     int Ls = this->Ls; | ||||
|     int shift_s = (this->pm == 1) ? (Ls-1) : 0; // s-component modified by shift operator | ||||
|     GridBase *grid = psi._grid; | ||||
|  | ||||
|     assert(phi.checkerboard == psi.checkerboard); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     // Flops = 6.0*(Nc*Ns) *Ls*vol | ||||
|     this->M5Dcalls++; | ||||
|     this->M5Dtime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         auto tmp = psi._odata[0]; | ||||
|         if(s==0){ | ||||
|           spProj5m(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5p(tmp, psi._odata[ss+Ls-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else if(s==(Ls-1)) { | ||||
|           spProj5m(tmp, psi._odata[ss+0]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5p(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else { | ||||
|           spProj5m(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5p(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } | ||||
|         if(this->pm == 1){ spProj5p(tmp, psi._odata[ss+shift_s]); } | ||||
|         else{ spProj5m(tmp, psi._odata[ss+shift_s]); } | ||||
|         chi[ss+s] = chi[ss+s] + shift_coeffs[s]*tmp; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->M5Dtime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5Ddag(const FermionField &psi, const FermionField &phi, FermionField &chi, | ||||
|     std::vector<Coeff_t> &lower, std::vector<Coeff_t> &diag, std::vector<Coeff_t> &upper) | ||||
|   { | ||||
|     int Ls = this->Ls; | ||||
|     GridBase *grid = psi._grid; | ||||
|  | ||||
|     assert(phi.checkerboard == psi.checkerboard); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     // Flops = 6.0*(Nc*Ns) *Ls*vol | ||||
|     this->M5Dcalls++; | ||||
|     this->M5Dtime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|       auto tmp = psi._odata[0]; | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         if(s==0) { | ||||
|           spProj5p(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5m(tmp, psi._odata[ss+Ls-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else if(s==(Ls-1)) { | ||||
|           spProj5p(tmp, psi._odata[ss+0]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5m(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else { | ||||
|           spProj5p(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5m(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->M5Dtime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5Ddag_shift(const FermionField &psi, const FermionField &phi, FermionField &chi, | ||||
|     std::vector<Coeff_t> &lower, std::vector<Coeff_t> &diag, std::vector<Coeff_t> &upper, | ||||
|     std::vector<Coeff_t> &shift_coeffs) | ||||
|   { | ||||
|     int Ls = this->Ls; | ||||
|     int shift_s = (this->pm == 1) ? (Ls-1) : 0; // s-component modified by shift operator | ||||
|     GridBase *grid = psi._grid; | ||||
|  | ||||
|     assert(phi.checkerboard == psi.checkerboard); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     // Flops = 6.0*(Nc*Ns) *Ls*vol | ||||
|     this->M5Dcalls++; | ||||
|     this->M5Dtime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|       chi[ss+Ls-1] = zero; | ||||
|       auto tmp = psi._odata[0]; | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         if(s==0) { | ||||
|           spProj5p(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5m(tmp, psi._odata[ss+Ls-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else if(s==(Ls-1)) { | ||||
|           spProj5p(tmp, psi._odata[ss+0]); | ||||
|           chi[ss+s] = chi[ss+s] + diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5m(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } else { | ||||
|           spProj5p(tmp, psi._odata[ss+s+1]); | ||||
|           chi[ss+s] = diag[s]*phi[ss+s] + upper[s]*tmp; | ||||
|           spProj5m(tmp, psi._odata[ss+s-1]); | ||||
|           chi[ss+s] = chi[ss+s] + lower[s]*tmp; | ||||
|         } | ||||
|         if(this->pm == 1){ spProj5p(tmp, psi._odata[ss+s]); } | ||||
|         else{ spProj5m(tmp, psi._odata[ss+s]); } | ||||
|         chi[ss+shift_s] = chi[ss+shift_s] + shift_coeffs[s]*tmp; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->M5Dtime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv(const FermionField &psi, FermionField &chi) | ||||
|   { | ||||
|     if(this->shift != 0.0){ MooeeInv_shift(psi,chi); return; } | ||||
|  | ||||
|     GridBase *grid = psi._grid; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     this->MooeeInvCalls++; | ||||
|     this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|  | ||||
|       auto tmp = psi._odata[0]; | ||||
|  | ||||
|       // Apply (L^{\prime})^{-1} | ||||
|       chi[ss] = psi[ss]; // chi[0]=psi[0] | ||||
|       for(int s=1; s<Ls; s++){ | ||||
|         spProj5p(tmp, chi[ss+s-1]); | ||||
|         chi[ss+s] = psi[ss+s] - this->lee[s-1]*tmp; | ||||
|       } | ||||
|  | ||||
|       // L_m^{-1} | ||||
|       for(int s=0; s<Ls-1; s++){ // Chi[ee] = 1 - sum[s<Ls-1] -leem[s]P_- chi | ||||
|         spProj5m(tmp, chi[ss+s]); | ||||
|         chi[ss+Ls-1] = chi[ss+Ls-1] - this->leem[s]*tmp; | ||||
|       } | ||||
|  | ||||
|       // U_m^{-1} D^{-1} | ||||
|       for(int s=0; s<Ls-1; s++){ // Chi[s] + 1/d chi[s] | ||||
|         spProj5p(tmp, chi[ss+Ls-1]); | ||||
|         chi[ss+s] = (1.0/this->dee[s])*chi[ss+s] - (this->ueem[s]/this->dee[Ls-1])*tmp; | ||||
|       } | ||||
|       chi[ss+Ls-1] = (1.0/this->dee[Ls-1])*chi[ss+Ls-1]; | ||||
|  | ||||
|       // Apply U^{-1} | ||||
|       for(int s=Ls-2; s>=0; s--){ | ||||
|         spProj5m(tmp, chi[ss+s+1]); | ||||
|         chi[ss+s] = chi[ss+s] - this->uee[s]*tmp; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->MooeeInvTime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv_shift(const FermionField &psi, FermionField &chi) | ||||
|   { | ||||
|     GridBase *grid = psi._grid; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     this->MooeeInvCalls++; | ||||
|     this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|  | ||||
|       auto tmp1        = psi._odata[0]; | ||||
|       auto tmp2        = psi._odata[0]; | ||||
|       auto tmp2_spProj = psi._odata[0]; | ||||
|  | ||||
|       // Apply (L^{\prime})^{-1} and accumulate MooeeInv_shift_lc[j]*psi[j] in tmp2 | ||||
|       chi[ss] = psi[ss]; // chi[0]=psi[0] | ||||
|       tmp2 = MooeeInv_shift_lc[0]*psi[ss]; | ||||
|       for(int s=1; s<Ls; s++){ | ||||
|         spProj5p(tmp1, chi[ss+s-1]); | ||||
|         chi[ss+s] = psi[ss+s] - this->lee[s-1]*tmp1; | ||||
|         tmp2 = tmp2 + MooeeInv_shift_lc[s]*psi[ss+s]; | ||||
|       } | ||||
|       if(this->pm == 1){ spProj5p(tmp2_spProj, tmp2);} | ||||
|       else{ spProj5m(tmp2_spProj, tmp2); } | ||||
|  | ||||
|       // L_m^{-1} | ||||
|       for(int s=0; s<Ls-1; s++){ // Chi[ee] = 1 - sum[s<Ls-1] -leem[s]P_- chi | ||||
|         spProj5m(tmp1, chi[ss+s]); | ||||
|         chi[ss+Ls-1] = chi[ss+Ls-1] - this->leem[s]*tmp1; | ||||
|       } | ||||
|  | ||||
|       // U_m^{-1} D^{-1} | ||||
|       for(int s=0; s<Ls-1; s++){ // Chi[s] + 1/d chi[s] | ||||
|         spProj5p(tmp1, chi[ss+Ls-1]); | ||||
|         chi[ss+s] = (1.0/this->dee[s])*chi[ss+s] - (this->ueem[s]/this->dee[Ls-1])*tmp1; | ||||
|       } | ||||
|       // chi[ss+Ls-1] = (1.0/this->dee[Ls-1])*chi[ss+Ls-1] + MooeeInv_shift_norm[Ls-1]*tmp2_spProj; | ||||
|       chi[ss+Ls-1] = (1.0/this->dee[Ls-1])*chi[ss+Ls-1]; | ||||
|       spProj5m(tmp1, chi[ss+Ls-1]); | ||||
|       chi[ss+Ls-1] = chi[ss+Ls-1] + MooeeInv_shift_norm[Ls-1]*tmp2_spProj; | ||||
|  | ||||
|       // Apply U^{-1} and add shift term | ||||
|       for(int s=Ls-2; s>=0; s--){ | ||||
|         chi[ss+s] = chi[ss+s] - this->uee[s]*tmp1; | ||||
|         spProj5m(tmp1, chi[ss+s]); | ||||
|         chi[ss+s] = chi[ss+s] + MooeeInv_shift_norm[s]*tmp2_spProj; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->MooeeInvTime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag(const FermionField &psi, FermionField &chi) | ||||
|   { | ||||
|     if(this->shift != 0.0){ MooeeInvDag_shift(psi,chi); return; } | ||||
|  | ||||
|     GridBase *grid = psi._grid; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     this->MooeeInvCalls++; | ||||
|     this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|  | ||||
|       auto tmp = psi._odata[0]; | ||||
|  | ||||
|       // Apply (U^{\prime})^{-dag} | ||||
|       chi[ss] = psi[ss]; | ||||
|       for(int s=1; s<Ls; s++){ | ||||
|         spProj5m(tmp, chi[ss+s-1]); | ||||
|         chi[ss+s] = psi[ss+s] - this->uee[s-1]*tmp; | ||||
|       } | ||||
|  | ||||
|       // U_m^{-\dag} | ||||
|       for(int s=0; s<Ls-1; s++){ | ||||
|         spProj5p(tmp, chi[ss+s]); | ||||
|         chi[ss+Ls-1] = chi[ss+Ls-1] - this->ueem[s]*tmp; | ||||
|       } | ||||
|  | ||||
|       // L_m^{-\dag} D^{-dag} | ||||
|       for(int s=0; s<Ls-1; s++){ | ||||
|         spProj5m(tmp, chi[ss+Ls-1]); | ||||
|         chi[ss+s] = (1.0/this->dee[s])*chi[ss+s] - (this->leem[s]/this->dee[Ls-1])*tmp; | ||||
|       } | ||||
|       chi[ss+Ls-1] = (1.0/this->dee[Ls-1])*chi[ss+Ls-1]; | ||||
|  | ||||
|       // Apply L^{-dag} | ||||
|       for(int s=Ls-2; s>=0; s--){ | ||||
|         spProj5p(tmp, chi[ss+s+1]); | ||||
|         chi[ss+s] = chi[ss+s] - this->lee[s]*tmp; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->MooeeInvTime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag_shift(const FermionField &psi, FermionField &chi) | ||||
|   { | ||||
|     GridBase *grid = psi._grid; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     this->MooeeInvCalls++; | ||||
|     this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=Ls){ | ||||
|  | ||||
|       auto tmp1        = psi._odata[0]; | ||||
|       auto tmp2        = psi._odata[0]; | ||||
|       auto tmp2_spProj = psi._odata[0]; | ||||
|  | ||||
|       // Apply (U^{\prime})^{-dag} and accumulate MooeeInvDag_shift_lc[j]*psi[j] in tmp2 | ||||
|       chi[ss] = psi[ss]; | ||||
|       tmp2 = MooeeInvDag_shift_lc[0]*psi[ss]; | ||||
|       for(int s=1; s<Ls; s++){ | ||||
|         spProj5m(tmp1, chi[ss+s-1]); | ||||
|         chi[ss+s] = psi[ss+s] - this->uee[s-1]*tmp1; | ||||
|         tmp2 = tmp2 + MooeeInvDag_shift_lc[s]*psi[ss+s]; | ||||
|       } | ||||
|       if(this->pm == 1){ spProj5p(tmp2_spProj, tmp2);} | ||||
|       else{ spProj5m(tmp2_spProj, tmp2); } | ||||
|  | ||||
|       // U_m^{-\dag} | ||||
|       for(int s=0; s<Ls-1; s++){ | ||||
|         spProj5p(tmp1, chi[ss+s]); | ||||
|         chi[ss+Ls-1] = chi[ss+Ls-1] - this->ueem[s]*tmp1; | ||||
|       } | ||||
|  | ||||
|       // L_m^{-\dag} D^{-dag} | ||||
|       for(int s=0; s<Ls-1; s++){ | ||||
|         spProj5m(tmp1, chi[ss+Ls-1]); | ||||
|         chi[ss+s] = (1.0/this->dee[s])*chi[ss+s] - (this->leem[s]/this->dee[Ls-1])*tmp1; | ||||
|       } | ||||
|       chi[ss+Ls-1] = (1.0/this->dee[Ls-1])*chi[ss+Ls-1]; | ||||
|       spProj5p(tmp1, chi[ss+Ls-1]); | ||||
|       chi[ss+Ls-1] = chi[ss+Ls-1] + MooeeInvDag_shift_norm[Ls-1]*tmp2_spProj; | ||||
|  | ||||
|       // Apply L^{-dag} | ||||
|       for(int s=Ls-2; s>=0; s--){ | ||||
|         chi[ss+s] = chi[ss+s] - this->lee[s]*tmp1; | ||||
|         spProj5p(tmp1, chi[ss+s]); | ||||
|         chi[ss+s] = chi[ss+s] + MooeeInvDag_shift_norm[s]*tmp2_spProj; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->MooeeInvTime += usecond(); | ||||
|   } | ||||
|  | ||||
|   #ifdef MOBIUS_EOFA_DPERP_CACHE | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplD); | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplDF); | ||||
|  | ||||
|   #endif | ||||
|  | ||||
| }} | ||||
							
								
								
									
										184
									
								
								lib/qcd/action/fermion/MobiusEOFAFermiondense.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								lib/qcd/action/fermion/MobiusEOFAFermiondense.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/MobiusEOFAFermiondense.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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_Eigen_Dense.h> | ||||
| #include <Grid/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   /* | ||||
|   * Dense matrix versions of routines | ||||
|   */ | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerNo, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv_shift(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerNo, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerYes, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag_shift(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerYes, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv) | ||||
|   { | ||||
|     int Ls = this->Ls; | ||||
|     int LLs = psi._grid->_rdimensions[0]; | ||||
|     int vol = psi._grid->oSites()/LLs; | ||||
|  | ||||
|     int pm      = this->pm; | ||||
|     RealD shift = this->shift; | ||||
|     RealD alpha = this->alpha; | ||||
|     RealD k     = this->k; | ||||
|     RealD mq1   = this->mq1; | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     assert(Ls==LLs); | ||||
|  | ||||
|     Eigen::MatrixXd Pplus  = Eigen::MatrixXd::Zero(Ls,Ls); | ||||
|     Eigen::MatrixXd Pminus = Eigen::MatrixXd::Zero(Ls,Ls); | ||||
|  | ||||
|     for(int s=0;s<Ls;s++){ | ||||
|         Pplus(s,s)  = this->bee[s]; | ||||
|         Pminus(s,s) = this->bee[s]; | ||||
|     } | ||||
|  | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|         Pminus(s,s+1) = -this->cee[s]; | ||||
|     } | ||||
|  | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|         Pplus(s+1,s) = -this->cee[s+1]; | ||||
|     } | ||||
|     Pplus (0,Ls-1) = mq1*this->cee[0]; | ||||
|     Pminus(Ls-1,0) = mq1*this->cee[Ls-1]; | ||||
|  | ||||
|     if(shift != 0.0){ | ||||
|       Coeff_t N = 2.0 * ( std::pow(alpha+1.0,Ls) + mq1*std::pow(alpha-1.0,Ls) ); | ||||
|       for(int s=0; s<Ls; ++s){ | ||||
|         if(pm == 1){ Pplus(s,Ls-1) += shift * k * N * std::pow(-1.0,s) * std::pow(alpha-1.0,s) / std::pow(alpha+1.0,Ls+s+1); } | ||||
|         else{ Pminus(Ls-1-s,Ls-1) -= shift * k * N * std::pow(-1.0,s) * std::pow(alpha-1.0,s) / std::pow(alpha+1.0,Ls+s+1); } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     Eigen::MatrixXd PplusMat ; | ||||
|     Eigen::MatrixXd PminusMat; | ||||
|  | ||||
|     if(inv){ | ||||
|       PplusMat  = Pplus.inverse(); | ||||
|       PminusMat = Pminus.inverse(); | ||||
|     } else { | ||||
|       PplusMat  = Pplus; | ||||
|       PminusMat = Pminus; | ||||
|     } | ||||
|  | ||||
|     if(dag){ | ||||
|       PplusMat.adjointInPlace(); | ||||
|       PminusMat.adjointInPlace(); | ||||
|     } | ||||
|  | ||||
|     // For the non-vectorised s-direction this is simple | ||||
|  | ||||
|     for(auto site=0; site<vol; site++){ | ||||
|  | ||||
|         SiteSpinor     SiteChi; | ||||
|         SiteHalfSpinor SitePplus; | ||||
|         SiteHalfSpinor SitePminus; | ||||
|  | ||||
|         for(int s1=0; s1<Ls; s1++){ | ||||
|             SiteChi = zero; | ||||
|             for(int s2=0; s2<Ls; s2++){ | ||||
|                 int lex2 = s2 + Ls*site; | ||||
|                 if(PplusMat(s1,s2) != 0.0){ | ||||
|                     spProj5p(SitePplus,psi[lex2]); | ||||
|                     accumRecon5p(SiteChi, PplusMat(s1,s2)*SitePplus); | ||||
|                 } | ||||
|                 if(PminusMat(s1,s2) != 0.0){ | ||||
|                     spProj5m(SitePminus, psi[lex2]); | ||||
|                     accumRecon5m(SiteChi, PminusMat(s1,s2)*SitePminus); | ||||
|                 } | ||||
|             } | ||||
|             chi[s1+Ls*site] = SiteChi*0.5; | ||||
|         } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   #ifdef MOBIUS_EOFA_DPERP_DENSE | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplD); | ||||
|  | ||||
|     template void MobiusEOFAFermion<GparityWilsonImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<GparityWilsonImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<WilsonImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<WilsonImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZWilsonImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZWilsonImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplDF); | ||||
|  | ||||
|     template void MobiusEOFAFermion<GparityWilsonImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<GparityWilsonImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<WilsonImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<WilsonImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZWilsonImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZWilsonImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|   #endif | ||||
|  | ||||
| }} | ||||
							
								
								
									
										290
									
								
								lib/qcd/action/fermion/MobiusEOFAFermionssp.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								lib/qcd/action/fermion/MobiusEOFAFermionssp.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/MobiusEOFAFermionssp.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   // FIXME -- make a version of these routines with site loop outermost for cache reuse. | ||||
|   // Pminus fowards | ||||
|   // Pplus  backwards | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5D(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|   { | ||||
|     Coeff_t one(1.0); | ||||
|     int Ls = this->Ls; | ||||
|     for(int s=0; s<Ls; s++){ | ||||
|       if(s==0) { | ||||
|         axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pplus (chi, one, chi, lower[s], psi, s, Ls-1); | ||||
|       } else if (s==(Ls-1)) { | ||||
|         axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, 0); | ||||
|         axpby_ssp_pplus (chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } else { | ||||
|         axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pplus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5D_shift(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, | ||||
|     std::vector<Coeff_t>& shift_coeffs) | ||||
|   { | ||||
|     Coeff_t one(1.0); | ||||
|     int Ls = this->Ls; | ||||
|     for(int s=0; s<Ls; s++){ | ||||
|       if(s==0) { | ||||
|         axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pplus (chi, one, chi, lower[s], psi, s, Ls-1); | ||||
|       } else if (s==(Ls-1)) { | ||||
|         axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, 0); | ||||
|         axpby_ssp_pplus (chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } else { | ||||
|         axpby_ssp_pminus(chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pplus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } | ||||
|       if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, shift_coeffs[s], psi, s, Ls-1); } | ||||
|       else{ axpby_ssp_pminus(chi, one, chi, shift_coeffs[s], psi, s, 0); } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5Ddag(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|   { | ||||
|     Coeff_t one(1.0); | ||||
|     int Ls = this->Ls; | ||||
|     for(int s=0; s<Ls; s++){ | ||||
|       if(s==0) { | ||||
|         axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, Ls-1); | ||||
|       } else if (s==(Ls-1)) { | ||||
|         axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, 0); | ||||
|         axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } else { | ||||
|         axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5Ddag_shift(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, | ||||
|     std::vector<Coeff_t>& shift_coeffs) | ||||
|   { | ||||
|     Coeff_t one(1.0); | ||||
|     int Ls = this->Ls; | ||||
|     for(int s=0; s<Ls; s++){ | ||||
|       if(s==0) { | ||||
|         axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, Ls-1); | ||||
|       } else if (s==(Ls-1)) { | ||||
|         axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, 0); | ||||
|         axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } else { | ||||
|         axpby_ssp_pplus (chi, diag[s], phi, upper[s], psi, s, s+1); | ||||
|         axpby_ssp_pminus(chi, one, chi, lower[s], psi, s, s-1); | ||||
|       } | ||||
|       if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, shift_coeffs[s], psi, Ls-1, s); } | ||||
|       else{ axpby_ssp_pminus(chi, one, chi, shift_coeffs[s], psi, 0, s); } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     if(this->shift != 0.0){ MooeeInv_shift(psi,chi); return; } | ||||
|  | ||||
|     Coeff_t one(1.0); | ||||
|     Coeff_t czero(0.0); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     // Apply (L^{\prime})^{-1} | ||||
|     axpby_ssp(chi, one, psi, czero, psi, 0, 0);      // chi[0]=psi[0] | ||||
|     for(int s=1; s<Ls; s++){ | ||||
|       axpby_ssp_pplus(chi, one, psi, -this->lee[s-1], chi, s, s-1);// recursion Psi[s] -lee P_+ chi[s-1] | ||||
|     } | ||||
|  | ||||
|     // L_m^{-1} | ||||
|     for(int s=0; s<Ls-1; s++){ // Chi[ee] = 1 - sum[s<Ls-1] -leem[s]P_- chi | ||||
|       axpby_ssp_pminus(chi, one, chi, -this->leem[s], chi, Ls-1, s); | ||||
|     } | ||||
|  | ||||
|     // U_m^{-1} D^{-1} | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|       axpby_ssp_pplus(chi, one/this->dee[s], chi, -this->ueem[s]/this->dee[Ls-1], chi, s, Ls-1); | ||||
|     } | ||||
|     axpby_ssp(chi, one/this->dee[Ls-1], chi, czero, chi, Ls-1, Ls-1); | ||||
|  | ||||
|     // Apply U^{-1} | ||||
|     for(int s=Ls-2; s>=0; s--){ | ||||
|       axpby_ssp_pminus(chi, one, chi, -this->uee[s], chi, s, s+1);  // chi[Ls] | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv_shift(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     Coeff_t one(1.0); | ||||
|     Coeff_t czero(0.0); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     FermionField tmp(psi._grid); | ||||
|  | ||||
|     // Apply (L^{\prime})^{-1} | ||||
|     axpby_ssp(chi, one, psi, czero, psi, 0, 0);      // chi[0]=psi[0] | ||||
|     axpby_ssp(tmp, czero, tmp, this->MooeeInv_shift_lc[0], psi, 0, 0); | ||||
|     for(int s=1; s<Ls; s++){ | ||||
|       axpby_ssp_pplus(chi, one, psi, -this->lee[s-1], chi, s, s-1);// recursion Psi[s] -lee P_+ chi[s-1] | ||||
|       axpby_ssp(tmp, one, tmp, this->MooeeInv_shift_lc[s], psi, 0, s); | ||||
|     } | ||||
|  | ||||
|     // L_m^{-1} | ||||
|     for(int s=0; s<Ls-1; s++){ // Chi[ee] = 1 - sum[s<Ls-1] -leem[s]P_- chi | ||||
|       axpby_ssp_pminus(chi, one, chi, -this->leem[s], chi, Ls-1, s); | ||||
|     } | ||||
|  | ||||
|     // U_m^{-1} D^{-1} | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|       axpby_ssp_pplus(chi, one/this->dee[s], chi, -this->ueem[s]/this->dee[Ls-1], chi, s, Ls-1); | ||||
|     } | ||||
|     axpby_ssp(chi, one/this->dee[Ls-1], chi, czero, chi, Ls-1, Ls-1); | ||||
|  | ||||
|     // Apply U^{-1} and add shift term | ||||
|     if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, this->MooeeInv_shift_norm[Ls-1], tmp, Ls-1, 0); } | ||||
|     else{ axpby_ssp_pminus(chi, one, chi, this->MooeeInv_shift_norm[Ls-1], tmp, Ls-1, 0); } | ||||
|     for(int s=Ls-2; s>=0; s--){ | ||||
|       axpby_ssp_pminus(chi, one, chi, -this->uee[s], chi, s, s+1);  // chi[Ls] | ||||
|       if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, this->MooeeInv_shift_norm[s], tmp, s, 0); } | ||||
|       else{ axpby_ssp_pminus(chi, one, chi, this->MooeeInv_shift_norm[s], tmp, s, 0); } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     if(this->shift != 0.0){ MooeeInvDag_shift(psi,chi); return; } | ||||
|  | ||||
|     Coeff_t one(1.0); | ||||
|     Coeff_t czero(0.0); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     // Apply (U^{\prime})^{-dagger} | ||||
|     axpby_ssp(chi, one, psi, czero, psi, 0, 0);      // chi[0]=psi[0] | ||||
|     for(int s=1; s<Ls; s++){ | ||||
|       axpby_ssp_pminus(chi, one, psi, -conjugate(this->uee[s-1]), chi, s, s-1); | ||||
|     } | ||||
|  | ||||
|     // U_m^{-\dagger} | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|       axpby_ssp_pplus(chi, one, chi, -conjugate(this->ueem[s]), chi, Ls-1, s); | ||||
|     } | ||||
|  | ||||
|     // L_m^{-\dagger} D^{-dagger} | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|       axpby_ssp_pminus(chi, one/conjugate(this->dee[s]), chi, -conjugate(this->leem[s]/this->dee[Ls-1]), chi, s, Ls-1); | ||||
|     } | ||||
|     axpby_ssp(chi, one/conjugate(this->dee[Ls-1]), chi, czero, chi, Ls-1, Ls-1); | ||||
|  | ||||
|     // Apply L^{-dagger} | ||||
|     for(int s=Ls-2; s>=0; s--){ | ||||
|       axpby_ssp_pplus(chi, one, chi, -conjugate(this->lee[s]), chi, s, s+1);  // chi[Ls] | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag_shift(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     Coeff_t one(1.0); | ||||
|     Coeff_t czero(0.0); | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|     int Ls = this->Ls; | ||||
|  | ||||
|     FermionField tmp(psi._grid); | ||||
|  | ||||
|     // Apply (U^{\prime})^{-dagger} and accumulate (MooeeInvDag_shift_lc)_{j} \psi_{j} in tmp[0] | ||||
|     axpby_ssp(chi, one, psi, czero, psi, 0, 0);      // chi[0]=psi[0] | ||||
|     axpby_ssp(tmp, czero, tmp, this->MooeeInvDag_shift_lc[0], psi, 0, 0); | ||||
|     for(int s=1; s<Ls; s++){ | ||||
|       axpby_ssp_pminus(chi, one, psi, -conjugate(this->uee[s-1]), chi, s, s-1); | ||||
|       axpby_ssp(tmp, one, tmp, this->MooeeInvDag_shift_lc[s], psi, 0, s); | ||||
|     } | ||||
|  | ||||
|     // U_m^{-\dagger} | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|       axpby_ssp_pplus(chi, one, chi, -conjugate(this->ueem[s]), chi, Ls-1, s); | ||||
|     } | ||||
|  | ||||
|     // L_m^{-\dagger} D^{-dagger} | ||||
|     for(int s=0; s<Ls-1; s++){ | ||||
|       axpby_ssp_pminus(chi, one/conjugate(this->dee[s]), chi, -conjugate(this->leem[s]/this->dee[Ls-1]), chi, s, Ls-1); | ||||
|     } | ||||
|     axpby_ssp(chi, one/conjugate(this->dee[Ls-1]), chi, czero, chi, Ls-1, Ls-1); | ||||
|  | ||||
|     // Apply L^{-dagger} and add shift | ||||
|     if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, this->MooeeInvDag_shift_norm[Ls-1], tmp, Ls-1, 0); } | ||||
|     else{ axpby_ssp_pminus(chi, one, chi, this->MooeeInvDag_shift_norm[Ls-1], tmp, Ls-1, 0); } | ||||
|     for(int s=Ls-2; s>=0; s--){ | ||||
|       axpby_ssp_pplus(chi, one, chi, -conjugate(this->lee[s]), chi, s, s+1);  // chi[Ls] | ||||
|       if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, this->MooeeInvDag_shift_norm[s], tmp, s, 0); } | ||||
|       else{ axpby_ssp_pminus(chi, one, chi, this->MooeeInvDag_shift_norm[s], tmp, s, 0); } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   #ifdef MOBIUS_EOFA_DPERP_LINALG | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplD); | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(WilsonImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(GparityWilsonImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZWilsonImplDF); | ||||
|  | ||||
|   #endif | ||||
|  | ||||
| }} | ||||
							
								
								
									
										983
									
								
								lib/qcd/action/fermion/MobiusEOFAFermionvec.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										983
									
								
								lib/qcd/action/fermion/MobiusEOFAFermionvec.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,983 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/fermion/MobiusEOFAFermionvec.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <pabobyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local> | ||||
| Author: paboyle <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/qcd/action/fermion/FermionCore.h> | ||||
| #include <Grid/qcd/action/fermion/MobiusEOFAFermion.h> | ||||
|  | ||||
| namespace Grid { | ||||
| namespace QCD { | ||||
|  | ||||
|   /* | ||||
|   * Dense matrix versions of routines | ||||
|   */ | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerNo, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInv_shift(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerNo, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerYes, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInvDag_shift(const FermionField& psi, FermionField& chi) | ||||
|   { | ||||
|     this->MooeeInternal(psi, chi, DaggerYes, InverseYes); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5D(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|   { | ||||
|     GridBase* grid  = psi._grid; | ||||
|     int Ls          = this->Ls; | ||||
|     int LLs         = grid->_rdimensions[0]; | ||||
|     const int nsimd = Simd::Nsimd(); | ||||
|  | ||||
|     Vector<iSinglet<Simd>> u(LLs); | ||||
|     Vector<iSinglet<Simd>> l(LLs); | ||||
|     Vector<iSinglet<Simd>> d(LLs); | ||||
|  | ||||
|     assert(Ls/LLs == nsimd); | ||||
|     assert(phi.checkerboard == psi.checkerboard); | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     // just directly address via type pun | ||||
|     typedef typename Simd::scalar_type scalar_type; | ||||
|     scalar_type* u_p = (scalar_type*) &u[0]; | ||||
|     scalar_type* l_p = (scalar_type*) &l[0]; | ||||
|     scalar_type* d_p = (scalar_type*) &d[0]; | ||||
|  | ||||
|     for(int o=0; o<LLs; o++){ // outer | ||||
|     for(int i=0; i<nsimd; i++){ //inner | ||||
|       int s   = o + i*LLs; | ||||
|       int ss  = o*nsimd + i; | ||||
|       u_p[ss] = upper[s]; | ||||
|       l_p[ss] = lower[s]; | ||||
|       d_p[ss] = diag[s]; | ||||
|     }} | ||||
|  | ||||
|     this->M5Dcalls++; | ||||
|     this->M5Dtime -= usecond(); | ||||
|  | ||||
|     assert(Nc == 3); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=LLs){ // adds LLs | ||||
|  | ||||
|       #if 0 | ||||
|  | ||||
|         alignas(64) SiteHalfSpinor hp; | ||||
|         alignas(64) SiteHalfSpinor hm; | ||||
|         alignas(64) SiteSpinor fp; | ||||
|         alignas(64) SiteSpinor fm; | ||||
|  | ||||
|         for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|           int vp = (v+1)%LLs; | ||||
|           int vm = (v+LLs-1)%LLs; | ||||
|  | ||||
|           spProj5m(hp, psi[ss+vp]); | ||||
|           spProj5p(hm, psi[ss+vm]); | ||||
|  | ||||
|           if (vp <= v){ rotate(hp, hp, 1); } | ||||
|           if (vm >= v){ rotate(hm, hm, nsimd-1); } | ||||
|  | ||||
|           hp = 0.5*hp; | ||||
|           hm = 0.5*hm; | ||||
|  | ||||
|           spRecon5m(fp, hp); | ||||
|           spRecon5p(fm, hm); | ||||
|  | ||||
|           chi[ss+v] = d[v]*phi[ss+v]; | ||||
|           chi[ss+v] = chi[ss+v] + u[v]*fp; | ||||
|           chi[ss+v] = chi[ss+v] + l[v]*fm; | ||||
|  | ||||
|         } | ||||
|  | ||||
|       #else | ||||
|  | ||||
|         for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|           vprefetch(psi[ss+v+LLs]); | ||||
|  | ||||
|           int vp = (v == LLs-1) ? 0     : v+1; | ||||
|           int vm = (v == 0)     ? LLs-1 : v-1; | ||||
|  | ||||
|           Simd hp_00 = psi[ss+vp]()(2)(0); | ||||
|           Simd hp_01 = psi[ss+vp]()(2)(1); | ||||
|           Simd hp_02 = psi[ss+vp]()(2)(2); | ||||
|           Simd hp_10 = psi[ss+vp]()(3)(0); | ||||
|           Simd hp_11 = psi[ss+vp]()(3)(1); | ||||
|           Simd hp_12 = psi[ss+vp]()(3)(2); | ||||
|  | ||||
|           Simd hm_00 = psi[ss+vm]()(0)(0); | ||||
|           Simd hm_01 = psi[ss+vm]()(0)(1); | ||||
|           Simd hm_02 = psi[ss+vm]()(0)(2); | ||||
|           Simd hm_10 = psi[ss+vm]()(1)(0); | ||||
|           Simd hm_11 = psi[ss+vm]()(1)(1); | ||||
|           Simd hm_12 = psi[ss+vm]()(1)(2); | ||||
|  | ||||
|           if(vp <= v){ | ||||
|             hp_00.v = Optimization::Rotate::tRotate<2>(hp_00.v); | ||||
|             hp_01.v = Optimization::Rotate::tRotate<2>(hp_01.v); | ||||
|             hp_02.v = Optimization::Rotate::tRotate<2>(hp_02.v); | ||||
|             hp_10.v = Optimization::Rotate::tRotate<2>(hp_10.v); | ||||
|             hp_11.v = Optimization::Rotate::tRotate<2>(hp_11.v); | ||||
|             hp_12.v = Optimization::Rotate::tRotate<2>(hp_12.v); | ||||
|           } | ||||
|  | ||||
|           if(vm >= v){ | ||||
|             hm_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_00.v); | ||||
|             hm_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_01.v); | ||||
|             hm_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_02.v); | ||||
|             hm_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_10.v); | ||||
|             hm_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_11.v); | ||||
|             hm_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_12.v); | ||||
|           } | ||||
|  | ||||
|           // Can force these to real arithmetic and save 2x. | ||||
|           Simd p_00 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00); | ||||
|           Simd p_01 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01); | ||||
|           Simd p_02 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02); | ||||
|           Simd p_10 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10); | ||||
|           Simd p_11 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11); | ||||
|           Simd p_12 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12); | ||||
|           Simd p_20 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00); | ||||
|           Simd p_21 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01); | ||||
|           Simd p_22 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02); | ||||
|           Simd p_30 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10); | ||||
|           Simd p_31 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11); | ||||
|           Simd p_32 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12); | ||||
|  | ||||
|           vstream(chi[ss+v]()(0)(0), p_00); | ||||
|           vstream(chi[ss+v]()(0)(1), p_01); | ||||
|           vstream(chi[ss+v]()(0)(2), p_02); | ||||
|           vstream(chi[ss+v]()(1)(0), p_10); | ||||
|           vstream(chi[ss+v]()(1)(1), p_11); | ||||
|           vstream(chi[ss+v]()(1)(2), p_12); | ||||
|           vstream(chi[ss+v]()(2)(0), p_20); | ||||
|           vstream(chi[ss+v]()(2)(1), p_21); | ||||
|           vstream(chi[ss+v]()(2)(2), p_22); | ||||
|           vstream(chi[ss+v]()(3)(0), p_30); | ||||
|           vstream(chi[ss+v]()(3)(1), p_31); | ||||
|           vstream(chi[ss+v]()(3)(2), p_32); | ||||
|         } | ||||
|  | ||||
|       #endif | ||||
|     } | ||||
|  | ||||
|     this->M5Dtime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5D_shift(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, | ||||
|     std::vector<Coeff_t>& shift_coeffs) | ||||
|   { | ||||
|     #if 0 | ||||
|  | ||||
|       this->M5D(psi, phi, chi, lower, diag, upper); | ||||
|  | ||||
|       // FIXME: possible gain from vectorizing shift operation as well? | ||||
|       Coeff_t one(1.0); | ||||
|       int Ls = this->Ls; | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, shift_coeffs[s], psi, s, Ls-1); } | ||||
|         else{ axpby_ssp_pminus(chi, one, chi, shift_coeffs[s], psi, s, 0); } | ||||
|       } | ||||
|  | ||||
|     #else | ||||
|  | ||||
|       GridBase* grid  = psi._grid; | ||||
|       int Ls          = this->Ls; | ||||
|       int LLs         = grid->_rdimensions[0]; | ||||
|       const int nsimd = Simd::Nsimd(); | ||||
|  | ||||
|       Vector<iSinglet<Simd>> u(LLs); | ||||
|       Vector<iSinglet<Simd>> l(LLs); | ||||
|       Vector<iSinglet<Simd>> d(LLs); | ||||
|       Vector<iSinglet<Simd>> s(LLs); | ||||
|  | ||||
|       assert(Ls/LLs == nsimd); | ||||
|       assert(phi.checkerboard == psi.checkerboard); | ||||
|  | ||||
|       chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|       // just directly address via type pun | ||||
|       typedef typename Simd::scalar_type scalar_type; | ||||
|       scalar_type* u_p = (scalar_type*) &u[0]; | ||||
|       scalar_type* l_p = (scalar_type*) &l[0]; | ||||
|       scalar_type* d_p = (scalar_type*) &d[0]; | ||||
|       scalar_type* s_p = (scalar_type*) &s[0]; | ||||
|  | ||||
|       for(int o=0; o<LLs; o++){ // outer | ||||
|       for(int i=0; i<nsimd; i++){ //inner | ||||
|         int s   = o + i*LLs; | ||||
|         int ss  = o*nsimd + i; | ||||
|         u_p[ss] = upper[s]; | ||||
|         l_p[ss] = lower[s]; | ||||
|         d_p[ss] = diag[s]; | ||||
|         s_p[ss] = shift_coeffs[s]; | ||||
|       }} | ||||
|  | ||||
|       this->M5Dcalls++; | ||||
|       this->M5Dtime -= usecond(); | ||||
|  | ||||
|       assert(Nc == 3); | ||||
|  | ||||
|       parallel_for(int ss=0; ss<grid->oSites(); ss+=LLs){ // adds LLs | ||||
|  | ||||
|         int vs     = (this->pm == 1) ? LLs-1 : 0; | ||||
|         Simd hs_00 = (this->pm == 1) ? psi[ss+vs]()(2)(0) : psi[ss+vs]()(0)(0); | ||||
|         Simd hs_01 = (this->pm == 1) ? psi[ss+vs]()(2)(1) : psi[ss+vs]()(0)(1); | ||||
|         Simd hs_02 = (this->pm == 1) ? psi[ss+vs]()(2)(2) : psi[ss+vs]()(0)(2); | ||||
|         Simd hs_10 = (this->pm == 1) ? psi[ss+vs]()(3)(0) : psi[ss+vs]()(1)(0); | ||||
|         Simd hs_11 = (this->pm == 1) ? psi[ss+vs]()(3)(1) : psi[ss+vs]()(1)(1); | ||||
|         Simd hs_12 = (this->pm == 1) ? psi[ss+vs]()(3)(2) : psi[ss+vs]()(1)(2); | ||||
|  | ||||
|         for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|           vprefetch(psi[ss+v+LLs]); | ||||
|  | ||||
|           int vp = (v == LLs-1) ? 0     : v+1; | ||||
|           int vm = (v == 0)     ? LLs-1 : v-1; | ||||
|  | ||||
|           Simd hp_00 = psi[ss+vp]()(2)(0); | ||||
|           Simd hp_01 = psi[ss+vp]()(2)(1); | ||||
|           Simd hp_02 = psi[ss+vp]()(2)(2); | ||||
|           Simd hp_10 = psi[ss+vp]()(3)(0); | ||||
|           Simd hp_11 = psi[ss+vp]()(3)(1); | ||||
|           Simd hp_12 = psi[ss+vp]()(3)(2); | ||||
|  | ||||
|           Simd hm_00 = psi[ss+vm]()(0)(0); | ||||
|           Simd hm_01 = psi[ss+vm]()(0)(1); | ||||
|           Simd hm_02 = psi[ss+vm]()(0)(2); | ||||
|           Simd hm_10 = psi[ss+vm]()(1)(0); | ||||
|           Simd hm_11 = psi[ss+vm]()(1)(1); | ||||
|           Simd hm_12 = psi[ss+vm]()(1)(2); | ||||
|  | ||||
|           if(vp <= v){ | ||||
|             hp_00.v = Optimization::Rotate::tRotate<2>(hp_00.v); | ||||
|             hp_01.v = Optimization::Rotate::tRotate<2>(hp_01.v); | ||||
|             hp_02.v = Optimization::Rotate::tRotate<2>(hp_02.v); | ||||
|             hp_10.v = Optimization::Rotate::tRotate<2>(hp_10.v); | ||||
|             hp_11.v = Optimization::Rotate::tRotate<2>(hp_11.v); | ||||
|             hp_12.v = Optimization::Rotate::tRotate<2>(hp_12.v); | ||||
|           } | ||||
|  | ||||
|           if(this->pm == 1 && vs <= v){ | ||||
|             hs_00.v = Optimization::Rotate::tRotate<2>(hs_00.v); | ||||
|             hs_01.v = Optimization::Rotate::tRotate<2>(hs_01.v); | ||||
|             hs_02.v = Optimization::Rotate::tRotate<2>(hs_02.v); | ||||
|             hs_10.v = Optimization::Rotate::tRotate<2>(hs_10.v); | ||||
|             hs_11.v = Optimization::Rotate::tRotate<2>(hs_11.v); | ||||
|             hs_12.v = Optimization::Rotate::tRotate<2>(hs_12.v); | ||||
|           } | ||||
|  | ||||
|           if(vm >= v){ | ||||
|             hm_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_00.v); | ||||
|             hm_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_01.v); | ||||
|             hm_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_02.v); | ||||
|             hm_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_10.v); | ||||
|             hm_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_11.v); | ||||
|             hm_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_12.v); | ||||
|           } | ||||
|  | ||||
|           if(this->pm == -1 && vs >= v){ | ||||
|             hs_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_00.v); | ||||
|             hs_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_01.v); | ||||
|             hs_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_02.v); | ||||
|             hs_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_10.v); | ||||
|             hs_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_11.v); | ||||
|             hs_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_12.v); | ||||
|           } | ||||
|  | ||||
|           // Can force these to real arithmetic and save 2x. | ||||
|           Simd p_00 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_00); | ||||
|           Simd p_01 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_01); | ||||
|           Simd p_02 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_02); | ||||
|           Simd p_10 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_10); | ||||
|           Simd p_11 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_11); | ||||
|           Simd p_12 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_12); | ||||
|           Simd p_20 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_00) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00); | ||||
|           Simd p_21 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_01) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01); | ||||
|           Simd p_22 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_02) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02); | ||||
|           Simd p_30 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_10) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10); | ||||
|           Simd p_31 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_11) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11); | ||||
|           Simd p_32 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_12) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12); | ||||
|  | ||||
|           vstream(chi[ss+v]()(0)(0), p_00); | ||||
|           vstream(chi[ss+v]()(0)(1), p_01); | ||||
|           vstream(chi[ss+v]()(0)(2), p_02); | ||||
|           vstream(chi[ss+v]()(1)(0), p_10); | ||||
|           vstream(chi[ss+v]()(1)(1), p_11); | ||||
|           vstream(chi[ss+v]()(1)(2), p_12); | ||||
|           vstream(chi[ss+v]()(2)(0), p_20); | ||||
|           vstream(chi[ss+v]()(2)(1), p_21); | ||||
|           vstream(chi[ss+v]()(2)(2), p_22); | ||||
|           vstream(chi[ss+v]()(3)(0), p_30); | ||||
|           vstream(chi[ss+v]()(3)(1), p_31); | ||||
|           vstream(chi[ss+v]()(3)(2), p_32); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       this->M5Dtime += usecond(); | ||||
|  | ||||
|     #endif | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5Ddag(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper) | ||||
|   { | ||||
|     GridBase* grid = psi._grid; | ||||
|     int Ls  = this->Ls; | ||||
|     int LLs = grid->_rdimensions[0]; | ||||
|     int nsimd = Simd::Nsimd(); | ||||
|  | ||||
|     Vector<iSinglet<Simd>> u(LLs); | ||||
|     Vector<iSinglet<Simd>> l(LLs); | ||||
|     Vector<iSinglet<Simd>> d(LLs); | ||||
|  | ||||
|     assert(Ls/LLs == nsimd); | ||||
|     assert(phi.checkerboard == psi.checkerboard); | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     // just directly address via type pun | ||||
|     typedef typename Simd::scalar_type scalar_type; | ||||
|     scalar_type* u_p = (scalar_type*) &u[0]; | ||||
|     scalar_type* l_p = (scalar_type*) &l[0]; | ||||
|     scalar_type* d_p = (scalar_type*) &d[0]; | ||||
|  | ||||
|     for(int o=0; o<LLs; o++){ // outer | ||||
|     for(int i=0; i<nsimd; i++){ //inner | ||||
|       int s  = o + i*LLs; | ||||
|       int ss = o*nsimd + i; | ||||
|       u_p[ss] = upper[s]; | ||||
|       l_p[ss] = lower[s]; | ||||
|       d_p[ss] = diag[s]; | ||||
|     }} | ||||
|  | ||||
|     this->M5Dcalls++; | ||||
|     this->M5Dtime -= usecond(); | ||||
|  | ||||
|     parallel_for(int ss=0; ss<grid->oSites(); ss+=LLs){ // adds LLs | ||||
|  | ||||
|       #if 0 | ||||
|  | ||||
|         alignas(64) SiteHalfSpinor hp; | ||||
|         alignas(64) SiteHalfSpinor hm; | ||||
|         alignas(64) SiteSpinor fp; | ||||
|         alignas(64) SiteSpinor fm; | ||||
|  | ||||
|         for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|           int vp = (v+1)%LLs; | ||||
|           int vm = (v+LLs-1)%LLs; | ||||
|  | ||||
|           spProj5p(hp, psi[ss+vp]); | ||||
|           spProj5m(hm, psi[ss+vm]); | ||||
|  | ||||
|           if(vp <= v){ rotate(hp, hp, 1); } | ||||
|           if(vm >= v){ rotate(hm, hm, nsimd-1); } | ||||
|  | ||||
|           hp = hp*0.5; | ||||
|           hm = hm*0.5; | ||||
|           spRecon5p(fp, hp); | ||||
|           spRecon5m(fm, hm); | ||||
|  | ||||
|           chi[ss+v] = d[v]*phi[ss+v]+u[v]*fp; | ||||
|           chi[ss+v] = chi[ss+v]     +l[v]*fm; | ||||
|  | ||||
|         } | ||||
|  | ||||
|       #else | ||||
|  | ||||
|         for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|           vprefetch(psi[ss+v+LLs]); | ||||
|  | ||||
|           int vp = (v == LLs-1) ? 0     : v+1; | ||||
|           int vm = (v == 0    ) ? LLs-1 : v-1; | ||||
|  | ||||
|           Simd hp_00 = psi[ss+vp]()(0)(0); | ||||
|           Simd hp_01 = psi[ss+vp]()(0)(1); | ||||
|           Simd hp_02 = psi[ss+vp]()(0)(2); | ||||
|           Simd hp_10 = psi[ss+vp]()(1)(0); | ||||
|           Simd hp_11 = psi[ss+vp]()(1)(1); | ||||
|           Simd hp_12 = psi[ss+vp]()(1)(2); | ||||
|  | ||||
|           Simd hm_00 = psi[ss+vm]()(2)(0); | ||||
|           Simd hm_01 = psi[ss+vm]()(2)(1); | ||||
|           Simd hm_02 = psi[ss+vm]()(2)(2); | ||||
|           Simd hm_10 = psi[ss+vm]()(3)(0); | ||||
|           Simd hm_11 = psi[ss+vm]()(3)(1); | ||||
|           Simd hm_12 = psi[ss+vm]()(3)(2); | ||||
|  | ||||
|           if (vp <= v){ | ||||
|             hp_00.v = Optimization::Rotate::tRotate<2>(hp_00.v); | ||||
|             hp_01.v = Optimization::Rotate::tRotate<2>(hp_01.v); | ||||
|             hp_02.v = Optimization::Rotate::tRotate<2>(hp_02.v); | ||||
|             hp_10.v = Optimization::Rotate::tRotate<2>(hp_10.v); | ||||
|             hp_11.v = Optimization::Rotate::tRotate<2>(hp_11.v); | ||||
|             hp_12.v = Optimization::Rotate::tRotate<2>(hp_12.v); | ||||
|           } | ||||
|  | ||||
|           if(vm >= v){ | ||||
|             hm_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_00.v); | ||||
|             hm_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_01.v); | ||||
|             hm_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_02.v); | ||||
|             hm_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_10.v); | ||||
|             hm_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_11.v); | ||||
|             hm_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_12.v); | ||||
|           } | ||||
|  | ||||
|           Simd p_00 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00); | ||||
|           Simd p_01 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01); | ||||
|           Simd p_02 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02); | ||||
|           Simd p_10 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10); | ||||
|           Simd p_11 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11); | ||||
|           Simd p_12 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12); | ||||
|           Simd p_20 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00); | ||||
|           Simd p_21 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01); | ||||
|           Simd p_22 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02); | ||||
|           Simd p_30 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10); | ||||
|           Simd p_31 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11); | ||||
|           Simd p_32 = switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12); | ||||
|  | ||||
|           vstream(chi[ss+v]()(0)(0), p_00); | ||||
|           vstream(chi[ss+v]()(0)(1), p_01); | ||||
|           vstream(chi[ss+v]()(0)(2), p_02); | ||||
|           vstream(chi[ss+v]()(1)(0), p_10); | ||||
|           vstream(chi[ss+v]()(1)(1), p_11); | ||||
|           vstream(chi[ss+v]()(1)(2), p_12); | ||||
|           vstream(chi[ss+v]()(2)(0), p_20); | ||||
|           vstream(chi[ss+v]()(2)(1), p_21); | ||||
|           vstream(chi[ss+v]()(2)(2), p_22); | ||||
|           vstream(chi[ss+v]()(3)(0), p_30); | ||||
|           vstream(chi[ss+v]()(3)(1), p_31); | ||||
|           vstream(chi[ss+v]()(3)(2), p_32); | ||||
|  | ||||
|         } | ||||
|  | ||||
|       #endif | ||||
|  | ||||
|     } | ||||
|  | ||||
|     this->M5Dtime += usecond(); | ||||
|   } | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::M5Ddag_shift(const FermionField& psi, const FermionField& phi, | ||||
|     FermionField& chi, std::vector<Coeff_t>& lower, std::vector<Coeff_t>& diag, std::vector<Coeff_t>& upper, | ||||
|     std::vector<Coeff_t>& shift_coeffs) | ||||
|   { | ||||
|     #if 0 | ||||
|  | ||||
|       this->M5Ddag(psi, phi, chi, lower, diag, upper); | ||||
|  | ||||
|       // FIXME: possible gain from vectorizing shift operation as well? | ||||
|       Coeff_t one(1.0); | ||||
|       int Ls = this->Ls; | ||||
|       for(int s=0; s<Ls; s++){ | ||||
|         if(this->pm == 1){ axpby_ssp_pplus(chi, one, chi, shift_coeffs[s], psi, Ls-1, s); } | ||||
|         else{ axpby_ssp_pminus(chi, one, chi, shift_coeffs[s], psi, 0, s); } | ||||
|       } | ||||
|  | ||||
|     #else | ||||
|  | ||||
|       GridBase* grid = psi._grid; | ||||
|       int Ls  = this->Ls; | ||||
|       int LLs = grid->_rdimensions[0]; | ||||
|       int nsimd = Simd::Nsimd(); | ||||
|  | ||||
|       Vector<iSinglet<Simd>> u(LLs); | ||||
|       Vector<iSinglet<Simd>> l(LLs); | ||||
|       Vector<iSinglet<Simd>> d(LLs); | ||||
|       Vector<iSinglet<Simd>> s(LLs); | ||||
|  | ||||
|       assert(Ls/LLs == nsimd); | ||||
|       assert(phi.checkerboard == psi.checkerboard); | ||||
|  | ||||
|       chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|       // just directly address via type pun | ||||
|       typedef typename Simd::scalar_type scalar_type; | ||||
|       scalar_type* u_p = (scalar_type*) &u[0]; | ||||
|       scalar_type* l_p = (scalar_type*) &l[0]; | ||||
|       scalar_type* d_p = (scalar_type*) &d[0]; | ||||
|       scalar_type* s_p = (scalar_type*) &s[0]; | ||||
|  | ||||
|       for(int o=0; o<LLs; o++){ // outer | ||||
|       for(int i=0; i<nsimd; i++){ //inner | ||||
|         int s  = o + i*LLs; | ||||
|         int ss = o*nsimd + i; | ||||
|         u_p[ss] = upper[s]; | ||||
|         l_p[ss] = lower[s]; | ||||
|         d_p[ss] = diag[s]; | ||||
|         s_p[ss] = shift_coeffs[s]; | ||||
|       }} | ||||
|  | ||||
|       this->M5Dcalls++; | ||||
|       this->M5Dtime -= usecond(); | ||||
|  | ||||
|       parallel_for(int ss=0; ss<grid->oSites(); ss+=LLs){ // adds LLs | ||||
|  | ||||
|         int vs     = (this->pm == 1) ? LLs-1 : 0; | ||||
|         Simd hs_00 = (this->pm == 1) ? psi[ss+vs]()(0)(0) : psi[ss+vs]()(2)(0); | ||||
|         Simd hs_01 = (this->pm == 1) ? psi[ss+vs]()(0)(1) : psi[ss+vs]()(2)(1); | ||||
|         Simd hs_02 = (this->pm == 1) ? psi[ss+vs]()(0)(2) : psi[ss+vs]()(2)(2); | ||||
|         Simd hs_10 = (this->pm == 1) ? psi[ss+vs]()(1)(0) : psi[ss+vs]()(3)(0); | ||||
|         Simd hs_11 = (this->pm == 1) ? psi[ss+vs]()(1)(1) : psi[ss+vs]()(3)(1); | ||||
|         Simd hs_12 = (this->pm == 1) ? psi[ss+vs]()(1)(2) : psi[ss+vs]()(3)(2); | ||||
|  | ||||
|         for(int v=0; v<LLs; v++){ | ||||
|  | ||||
|           vprefetch(psi[ss+v+LLs]); | ||||
|  | ||||
|           int vp = (v == LLs-1) ? 0     : v+1; | ||||
|           int vm = (v == 0    ) ? LLs-1 : v-1; | ||||
|  | ||||
|           Simd hp_00 = psi[ss+vp]()(0)(0); | ||||
|           Simd hp_01 = psi[ss+vp]()(0)(1); | ||||
|           Simd hp_02 = psi[ss+vp]()(0)(2); | ||||
|           Simd hp_10 = psi[ss+vp]()(1)(0); | ||||
|           Simd hp_11 = psi[ss+vp]()(1)(1); | ||||
|           Simd hp_12 = psi[ss+vp]()(1)(2); | ||||
|  | ||||
|           Simd hm_00 = psi[ss+vm]()(2)(0); | ||||
|           Simd hm_01 = psi[ss+vm]()(2)(1); | ||||
|           Simd hm_02 = psi[ss+vm]()(2)(2); | ||||
|           Simd hm_10 = psi[ss+vm]()(3)(0); | ||||
|           Simd hm_11 = psi[ss+vm]()(3)(1); | ||||
|           Simd hm_12 = psi[ss+vm]()(3)(2); | ||||
|  | ||||
|           if (vp <= v){ | ||||
|             hp_00.v = Optimization::Rotate::tRotate<2>(hp_00.v); | ||||
|             hp_01.v = Optimization::Rotate::tRotate<2>(hp_01.v); | ||||
|             hp_02.v = Optimization::Rotate::tRotate<2>(hp_02.v); | ||||
|             hp_10.v = Optimization::Rotate::tRotate<2>(hp_10.v); | ||||
|             hp_11.v = Optimization::Rotate::tRotate<2>(hp_11.v); | ||||
|             hp_12.v = Optimization::Rotate::tRotate<2>(hp_12.v); | ||||
|           } | ||||
|  | ||||
|           if(this->pm == 1 && vs <= v){ | ||||
|             hs_00.v = Optimization::Rotate::tRotate<2>(hs_00.v); | ||||
|             hs_01.v = Optimization::Rotate::tRotate<2>(hs_01.v); | ||||
|             hs_02.v = Optimization::Rotate::tRotate<2>(hs_02.v); | ||||
|             hs_10.v = Optimization::Rotate::tRotate<2>(hs_10.v); | ||||
|             hs_11.v = Optimization::Rotate::tRotate<2>(hs_11.v); | ||||
|             hs_12.v = Optimization::Rotate::tRotate<2>(hs_12.v); | ||||
|           } | ||||
|  | ||||
|           if(vm >= v){ | ||||
|             hm_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_00.v); | ||||
|             hm_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_01.v); | ||||
|             hm_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_02.v); | ||||
|             hm_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_10.v); | ||||
|             hm_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_11.v); | ||||
|             hm_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hm_12.v); | ||||
|           } | ||||
|  | ||||
|           if(this->pm == -1 && vs >= v){ | ||||
|             hs_00.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_00.v); | ||||
|             hs_01.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_01.v); | ||||
|             hs_02.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_02.v); | ||||
|             hs_10.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_10.v); | ||||
|             hs_11.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_11.v); | ||||
|             hs_12.v = Optimization::Rotate::tRotate<2*Simd::Nsimd()-2>(hs_12.v); | ||||
|           } | ||||
|  | ||||
|           Simd p_00 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_00) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_00); | ||||
|           Simd p_01 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_01) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_01); | ||||
|           Simd p_02 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_02) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(0)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_02); | ||||
|           Simd p_10 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_10) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(0)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_10); | ||||
|           Simd p_11 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_11) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(1)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_11); | ||||
|           Simd p_12 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_12) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(1)(2)) + switcheroo<Coeff_t>::mult(u[v]()()(), hp_12); | ||||
|           Simd p_20 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_00) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_00); | ||||
|           Simd p_21 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_01) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_01); | ||||
|           Simd p_22 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(2)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_02) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_02); | ||||
|           Simd p_30 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(0)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_10) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_10); | ||||
|           Simd p_31 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(1)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_11) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_11); | ||||
|           Simd p_32 = (this->pm == 1) ? switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12) | ||||
|                                       : switcheroo<Coeff_t>::mult(d[v]()()(), phi[ss+v]()(3)(2)) + switcheroo<Coeff_t>::mult(l[v]()()(), hm_12) | ||||
|                                                                                                  + switcheroo<Coeff_t>::mult(s[v]()()(), hs_12); | ||||
|  | ||||
|           vstream(chi[ss+v]()(0)(0), p_00); | ||||
|           vstream(chi[ss+v]()(0)(1), p_01); | ||||
|           vstream(chi[ss+v]()(0)(2), p_02); | ||||
|           vstream(chi[ss+v]()(1)(0), p_10); | ||||
|           vstream(chi[ss+v]()(1)(1), p_11); | ||||
|           vstream(chi[ss+v]()(1)(2), p_12); | ||||
|           vstream(chi[ss+v]()(2)(0), p_20); | ||||
|           vstream(chi[ss+v]()(2)(1), p_21); | ||||
|           vstream(chi[ss+v]()(2)(2), p_22); | ||||
|           vstream(chi[ss+v]()(3)(0), p_30); | ||||
|           vstream(chi[ss+v]()(3)(1), p_31); | ||||
|           vstream(chi[ss+v]()(3)(2), p_32); | ||||
|  | ||||
|         } | ||||
|  | ||||
|       } | ||||
|  | ||||
|       this->M5Dtime += usecond(); | ||||
|  | ||||
|     #endif | ||||
|   } | ||||
|  | ||||
|   #ifdef AVX512 | ||||
|     #include<simd/Intel512common.h> | ||||
|     #include<simd/Intel512avx.h> | ||||
|     #include<simd/Intel512single.h> | ||||
|   #endif | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInternalAsm(const FermionField& psi, FermionField& chi, | ||||
|     int LLs, int site, Vector<iSinglet<Simd> >& Matp, Vector<iSinglet<Simd> >& Matm) | ||||
|   { | ||||
|     #ifndef AVX512 | ||||
|       { | ||||
|         SiteHalfSpinor BcastP; | ||||
|         SiteHalfSpinor BcastM; | ||||
|         SiteHalfSpinor SiteChiP; | ||||
|         SiteHalfSpinor SiteChiM; | ||||
|  | ||||
|         // Ls*Ls * 2 * 12 * vol flops | ||||
|         for(int s1=0; s1<LLs; s1++){ | ||||
|  | ||||
|           for(int s2=0; s2<LLs; s2++){ | ||||
|           for(int l=0; l < Simd::Nsimd(); l++){ // simd lane | ||||
|  | ||||
|             int s = s2 + l*LLs; | ||||
|             int lex = s2 + LLs*site; | ||||
|  | ||||
|             if( s2==0 && l==0 ){ | ||||
|               SiteChiP=zero; | ||||
|               SiteChiM=zero; | ||||
|             } | ||||
|  | ||||
|             for(int sp=0; sp<2;  sp++){ | ||||
|             for(int co=0; co<Nc; co++){ | ||||
|               vbroadcast(BcastP()(sp)(co), psi[lex]()(sp)(co), l); | ||||
|             }} | ||||
|  | ||||
|             for(int sp=0; sp<2;  sp++){ | ||||
|             for(int co=0; co<Nc; co++){ | ||||
|               vbroadcast(BcastM()(sp)(co), psi[lex]()(sp+2)(co), l); | ||||
|             }} | ||||
|  | ||||
|             for(int sp=0; sp<2;  sp++){ | ||||
|             for(int co=0; co<Nc; co++){ | ||||
|               SiteChiP()(sp)(co) = real_madd(Matp[LLs*s+s1]()()(), BcastP()(sp)(co), SiteChiP()(sp)(co)); // 1100 us. | ||||
|               SiteChiM()(sp)(co) = real_madd(Matm[LLs*s+s1]()()(), BcastM()(sp)(co), SiteChiM()(sp)(co)); // each found by commenting out | ||||
|             }} | ||||
|           }} | ||||
|  | ||||
|           { | ||||
|             int lex = s1 + LLs*site; | ||||
|             for(int sp=0; sp<2;  sp++){ | ||||
|             for(int co=0; co<Nc; co++){ | ||||
|               vstream(chi[lex]()(sp)(co),   SiteChiP()(sp)(co)); | ||||
|               vstream(chi[lex]()(sp+2)(co), SiteChiM()(sp)(co)); | ||||
|             }} | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     #else | ||||
|       { | ||||
|         // pointers | ||||
|         //  MASK_REGS; | ||||
|         #define Chi_00 %%zmm1 | ||||
|         #define Chi_01 %%zmm2 | ||||
|         #define Chi_02 %%zmm3 | ||||
|         #define Chi_10 %%zmm4 | ||||
|         #define Chi_11 %%zmm5 | ||||
|         #define Chi_12 %%zmm6 | ||||
|         #define Chi_20 %%zmm7 | ||||
|         #define Chi_21 %%zmm8 | ||||
|         #define Chi_22 %%zmm9 | ||||
|         #define Chi_30 %%zmm10 | ||||
|         #define Chi_31 %%zmm11 | ||||
|         #define Chi_32 %%zmm12 | ||||
|  | ||||
|         #define BCAST0  %%zmm13 | ||||
|         #define BCAST1  %%zmm14 | ||||
|         #define BCAST2  %%zmm15 | ||||
|         #define BCAST3  %%zmm16 | ||||
|         #define BCAST4  %%zmm17 | ||||
|         #define BCAST5  %%zmm18 | ||||
|         #define BCAST6  %%zmm19 | ||||
|         #define BCAST7  %%zmm20 | ||||
|         #define BCAST8  %%zmm21 | ||||
|         #define BCAST9  %%zmm22 | ||||
|         #define BCAST10 %%zmm23 | ||||
|         #define BCAST11 %%zmm24 | ||||
|  | ||||
|         int incr = LLs*LLs*sizeof(iSinglet<Simd>); | ||||
|  | ||||
|         for(int s1=0; s1<LLs; s1++){ | ||||
|  | ||||
|           for(int s2=0; s2<LLs; s2++){ | ||||
|  | ||||
|             int lex = s2 + LLs*site; | ||||
|             uint64_t a0 = (uint64_t) &Matp[LLs*s2+s1]; // should be cacheable | ||||
|             uint64_t a1 = (uint64_t) &Matm[LLs*s2+s1]; | ||||
|             uint64_t a2 = (uint64_t) &psi[lex]; | ||||
|  | ||||
|             for(int l=0; l<Simd::Nsimd(); l++){ // simd lane | ||||
|  | ||||
|               if((s2+l)==0) { | ||||
|                 asm( | ||||
|                       VPREFETCH1(0,%2)              VPREFETCH1(0,%1) | ||||
|                       VPREFETCH1(12,%2)  	          VPREFETCH1(13,%2) | ||||
|                       VPREFETCH1(14,%2)  	          VPREFETCH1(15,%2) | ||||
|                       VBCASTCDUP(0,%2,BCAST0) | ||||
|                       VBCASTCDUP(1,%2,BCAST1) | ||||
|                       VBCASTCDUP(2,%2,BCAST2) | ||||
|                       VBCASTCDUP(3,%2,BCAST3) | ||||
|                       VBCASTCDUP(4,%2,BCAST4)       VMULMEM(0,%0,BCAST0,Chi_00) | ||||
|                       VBCASTCDUP(5,%2,BCAST5)       VMULMEM(0,%0,BCAST1,Chi_01) | ||||
|                       VBCASTCDUP(6,%2,BCAST6)       VMULMEM(0,%0,BCAST2,Chi_02) | ||||
|                       VBCASTCDUP(7,%2,BCAST7)       VMULMEM(0,%0,BCAST3,Chi_10) | ||||
|                       VBCASTCDUP(8,%2,BCAST8)       VMULMEM(0,%0,BCAST4,Chi_11) | ||||
|                       VBCASTCDUP(9,%2,BCAST9)       VMULMEM(0,%0,BCAST5,Chi_12) | ||||
|                       VBCASTCDUP(10,%2,BCAST10)     VMULMEM(0,%1,BCAST6,Chi_20) | ||||
|                       VBCASTCDUP(11,%2,BCAST11)     VMULMEM(0,%1,BCAST7,Chi_21) | ||||
|                       VMULMEM(0,%1,BCAST8,Chi_22) | ||||
|                       VMULMEM(0,%1,BCAST9,Chi_30) | ||||
|                       VMULMEM(0,%1,BCAST10,Chi_31) | ||||
|                       VMULMEM(0,%1,BCAST11,Chi_32) | ||||
|                       : : "r" (a0), "r" (a1), "r" (a2)                            ); | ||||
|               } else { | ||||
|                 asm( | ||||
|                       VBCASTCDUP(0,%2,BCAST0)   VMADDMEM(0,%0,BCAST0,Chi_00) | ||||
|                       VBCASTCDUP(1,%2,BCAST1)   VMADDMEM(0,%0,BCAST1,Chi_01) | ||||
|                       VBCASTCDUP(2,%2,BCAST2)   VMADDMEM(0,%0,BCAST2,Chi_02) | ||||
|                       VBCASTCDUP(3,%2,BCAST3)   VMADDMEM(0,%0,BCAST3,Chi_10) | ||||
|                       VBCASTCDUP(4,%2,BCAST4)   VMADDMEM(0,%0,BCAST4,Chi_11) | ||||
|                       VBCASTCDUP(5,%2,BCAST5)   VMADDMEM(0,%0,BCAST5,Chi_12) | ||||
|                       VBCASTCDUP(6,%2,BCAST6)   VMADDMEM(0,%1,BCAST6,Chi_20) | ||||
|                       VBCASTCDUP(7,%2,BCAST7)   VMADDMEM(0,%1,BCAST7,Chi_21) | ||||
|                       VBCASTCDUP(8,%2,BCAST8)   VMADDMEM(0,%1,BCAST8,Chi_22) | ||||
|                       VBCASTCDUP(9,%2,BCAST9)   VMADDMEM(0,%1,BCAST9,Chi_30) | ||||
|                       VBCASTCDUP(10,%2,BCAST10) VMADDMEM(0,%1,BCAST10,Chi_31) | ||||
|                       VBCASTCDUP(11,%2,BCAST11) VMADDMEM(0,%1,BCAST11,Chi_32) | ||||
|                       : : "r" (a0), "r" (a1), "r" (a2)                            ); | ||||
|               } | ||||
|  | ||||
|               a0 = a0 + incr; | ||||
|               a1 = a1 + incr; | ||||
|               a2 = a2 + sizeof(Simd::scalar_type); | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           { | ||||
|             int lexa = s1+LLs*site; | ||||
|             asm ( | ||||
|                VSTORE(0,%0,Chi_00) VSTORE(1 ,%0,Chi_01)  VSTORE(2 ,%0,Chi_02) | ||||
|                VSTORE(3,%0,Chi_10) VSTORE(4 ,%0,Chi_11)  VSTORE(5 ,%0,Chi_12) | ||||
|                VSTORE(6,%0,Chi_20) VSTORE(7 ,%0,Chi_21)  VSTORE(8 ,%0,Chi_22) | ||||
|                VSTORE(9,%0,Chi_30) VSTORE(10,%0,Chi_31)  VSTORE(11,%0,Chi_32) | ||||
|                : : "r" ((uint64_t)&chi[lexa]) : "memory" ); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       #undef Chi_00 | ||||
|       #undef Chi_01 | ||||
|       #undef Chi_02 | ||||
|       #undef Chi_10 | ||||
|       #undef Chi_11 | ||||
|       #undef Chi_12 | ||||
|       #undef Chi_20 | ||||
|       #undef Chi_21 | ||||
|       #undef Chi_22 | ||||
|       #undef Chi_30 | ||||
|       #undef Chi_31 | ||||
|       #undef Chi_32 | ||||
|  | ||||
|       #undef BCAST0 | ||||
|       #undef BCAST1 | ||||
|       #undef BCAST2 | ||||
|       #undef BCAST3 | ||||
|       #undef BCAST4 | ||||
|       #undef BCAST5 | ||||
|       #undef BCAST6 | ||||
|       #undef BCAST7 | ||||
|       #undef BCAST8 | ||||
|       #undef BCAST9 | ||||
|       #undef BCAST10 | ||||
|       #undef BCAST11 | ||||
|  | ||||
|     #endif | ||||
|   }; | ||||
|  | ||||
|   // Z-mobius version | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInternalZAsm(const FermionField& psi, FermionField& chi, | ||||
|     int LLs, int site, Vector<iSinglet<Simd> >& Matp, Vector<iSinglet<Simd> >& Matm) | ||||
|   { | ||||
|     std::cout << "Error: zMobius not implemented for EOFA" << std::endl; | ||||
|     exit(-1); | ||||
|   }; | ||||
|  | ||||
|   template<class Impl> | ||||
|   void MobiusEOFAFermion<Impl>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv) | ||||
|   { | ||||
|     int Ls  = this->Ls; | ||||
|     int LLs = psi._grid->_rdimensions[0]; | ||||
|     int vol = psi._grid->oSites()/LLs; | ||||
|  | ||||
|     chi.checkerboard = psi.checkerboard; | ||||
|  | ||||
|     Vector<iSinglet<Simd>>   Matp; | ||||
|     Vector<iSinglet<Simd>>   Matm; | ||||
|     Vector<iSinglet<Simd>>* _Matp; | ||||
|     Vector<iSinglet<Simd>>* _Matm; | ||||
|  | ||||
|     //  MooeeInternalCompute(dag,inv,Matp,Matm); | ||||
|     if(inv && dag){ | ||||
|       _Matp = &this->MatpInvDag; | ||||
|       _Matm = &this->MatmInvDag; | ||||
|     } | ||||
|  | ||||
|     if(inv && (!dag)){ | ||||
|       _Matp = &this->MatpInv; | ||||
|       _Matm = &this->MatmInv; | ||||
|     } | ||||
|  | ||||
|     if(!inv){ | ||||
|       MooeeInternalCompute(dag, inv, Matp, Matm); | ||||
|       _Matp = &Matp; | ||||
|       _Matm = &Matm; | ||||
|     } | ||||
|  | ||||
|     assert(_Matp->size() == Ls*LLs); | ||||
|  | ||||
|     this->MooeeInvCalls++; | ||||
|     this->MooeeInvTime -= usecond(); | ||||
|  | ||||
|     if(switcheroo<Coeff_t>::iscomplex()){ | ||||
|       parallel_for(auto site=0; site<vol; site++){ | ||||
|         MooeeInternalZAsm(psi, chi, LLs, site, *_Matp, *_Matm); | ||||
|       } | ||||
|     } else { | ||||
|       parallel_for(auto site=0; site<vol; site++){ | ||||
|         MooeeInternalAsm(psi, chi, LLs, site, *_Matp, *_Matm); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this->MooeeInvTime += usecond(); | ||||
|   } | ||||
|  | ||||
|   #ifdef MOBIUS_EOFA_DPERP_VEC | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(DomainWallVec5dImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(DomainWallVec5dImplF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZDomainWallVec5dImplD); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZDomainWallVec5dImplF); | ||||
|  | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(DomainWallVec5dImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(DomainWallVec5dImplFH); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZDomainWallVec5dImplDF); | ||||
|     INSTANTIATE_DPERP_MOBIUS_EOFA(ZDomainWallVec5dImplFH); | ||||
|  | ||||
|     template void MobiusEOFAFermion<DomainWallVec5dImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<DomainWallVec5dImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZDomainWallVec5dImplF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZDomainWallVec5dImplD>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|     template void MobiusEOFAFermion<DomainWallVec5dImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<DomainWallVec5dImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZDomainWallVec5dImplFH>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|     template void MobiusEOFAFermion<ZDomainWallVec5dImplDF>::MooeeInternal(const FermionField& psi, FermionField& chi, int dag, int inv); | ||||
|  | ||||
|   #endif | ||||
|  | ||||
| }} | ||||
| @@ -30,60 +30,181 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|  | ||||
| #define REGISTER | ||||
|  | ||||
| #define LOAD_CHIMU \ | ||||
|   {const SiteSpinor & ref (in._odata[offset]);	\ | ||||
|     Chimu_00=ref()(0)(0);\ | ||||
|     Chimu_01=ref()(0)(1);\ | ||||
|     Chimu_02=ref()(0)(2);\ | ||||
|     Chimu_10=ref()(1)(0);\ | ||||
|     Chimu_11=ref()(1)(1);\ | ||||
|     Chimu_12=ref()(1)(2);\ | ||||
|     Chimu_20=ref()(2)(0);\ | ||||
|     Chimu_21=ref()(2)(1);\ | ||||
|     Chimu_22=ref()(2)(2);\ | ||||
|     Chimu_30=ref()(3)(0);\ | ||||
|     Chimu_31=ref()(3)(1);\ | ||||
|     Chimu_32=ref()(3)(2);} | ||||
| #define LOAD_CHIMU_BODY(F)			\ | ||||
|   Chimu_00=ref(F)(0)(0);			\ | ||||
|   Chimu_01=ref(F)(0)(1);			\ | ||||
|   Chimu_02=ref(F)(0)(2);			\ | ||||
|   Chimu_10=ref(F)(1)(0);			\ | ||||
|   Chimu_11=ref(F)(1)(1);			\ | ||||
|   Chimu_12=ref(F)(1)(2);			\ | ||||
|   Chimu_20=ref(F)(2)(0);			\ | ||||
|   Chimu_21=ref(F)(2)(1);			\ | ||||
|   Chimu_22=ref(F)(2)(2);			\ | ||||
|   Chimu_30=ref(F)(3)(0);			\ | ||||
|   Chimu_31=ref(F)(3)(1);			\ | ||||
|   Chimu_32=ref(F)(3)(2) | ||||
|  | ||||
| #define LOAD_CHI\ | ||||
|   {const SiteHalfSpinor &ref(buf[offset]);	\ | ||||
|     Chi_00 = ref()(0)(0);\ | ||||
|     Chi_01 = ref()(0)(1);\ | ||||
|     Chi_02 = ref()(0)(2);\ | ||||
|     Chi_10 = ref()(1)(0);\ | ||||
|     Chi_11 = ref()(1)(1);\ | ||||
|     Chi_12 = ref()(1)(2);} | ||||
| #define LOAD_CHIMU(DIR,F,PERM)						\ | ||||
|   { const SiteSpinor & ref (in._odata[offset]); LOAD_CHIMU_BODY(F); } | ||||
|  | ||||
| #define LOAD_CHI_BODY(F)				\ | ||||
|     Chi_00 = ref(F)(0)(0);\ | ||||
|     Chi_01 = ref(F)(0)(1);\ | ||||
|     Chi_02 = ref(F)(0)(2);\ | ||||
|     Chi_10 = ref(F)(1)(0);\ | ||||
|     Chi_11 = ref(F)(1)(1);\ | ||||
|     Chi_12 = ref(F)(1)(2) | ||||
|  | ||||
| #define LOAD_CHI(DIR,F,PERM)					\ | ||||
|   {const SiteHalfSpinor &ref(buf[offset]); LOAD_CHI_BODY(F); } | ||||
|  | ||||
|  | ||||
| //G-parity implementations using in-place intrinsic ops | ||||
|  | ||||
| //1l 1h -> 1h 1l | ||||
| //0l 0h , 1h 1l -> 0l 1h 0h,1l | ||||
| //0h,1l -> 1l,0h | ||||
| //if( (distance == 1 && !perm_will_occur) || (distance == -1 && perm_will_occur) ) | ||||
| //Pulled fermion through forwards face, GPBC on upper component | ||||
| //Need 0= 0l 1h   1= 1l 0h | ||||
| //else if( (distance == -1 && !perm) || (distance == 1 && perm) ) | ||||
| //Pulled fermion through backwards face, GPBC on lower component | ||||
| //Need 0= 1l 0h   1= 0l 1h | ||||
|  | ||||
| //1l 1h -> 1h 1l | ||||
| //0l 0h , 1h 1l -> 0l 1h 0h,1l | ||||
| #define DO_TWIST_0L_1H(INTO,S,C,F, PERM, tmp1, tmp2, tmp3)			\ | ||||
|   permute##PERM(tmp1, ref(1)(S)(C));				\ | ||||
|   exchange##PERM(tmp2,tmp3, ref(0)(S)(C), tmp1);		\ | ||||
|   INTO = tmp2; | ||||
|  | ||||
| //0l 0h -> 0h 0l | ||||
| //1l 1h, 0h 0l -> 1l 0h, 1h 0l | ||||
| #define DO_TWIST_1L_0H(INTO,S,C,F, PERM, tmp1, tmp2, tmp3)			\ | ||||
|   permute##PERM(tmp1, ref(0)(S)(C));				\ | ||||
|   exchange##PERM(tmp2,tmp3, ref(1)(S)(C), tmp1);		\ | ||||
|   INTO = tmp2; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #define LOAD_CHI_SETUP(DIR,F)						\ | ||||
|   g = F;								\ | ||||
|   direction = st._directions[DIR];				\ | ||||
|   distance = st._distances[DIR];				\ | ||||
|   sl = st._grid->_simd_layout[direction];			\ | ||||
|   inplace_twist = 0;						\ | ||||
|   if(SE->_around_the_world && this->Params.twists[DIR % 4]){		\ | ||||
|     if(sl == 1){							\ | ||||
|       g = (F+1) % 2;							\ | ||||
|     }else{								\ | ||||
|       inplace_twist = 1;						\ | ||||
|     }									\ | ||||
|   }   | ||||
|  | ||||
| #define LOAD_CHIMU_GPARITY_INPLACE_TWIST(DIR,F,PERM)			\ | ||||
|   { const SiteSpinor &ref(in._odata[offset]);				\ | ||||
|     LOAD_CHI_SETUP(DIR,F);						\ | ||||
|     if(!inplace_twist){							\ | ||||
|       LOAD_CHIMU_BODY(g);						\ | ||||
|     }else{								\ | ||||
|       if(  ( F==0 && ((distance == 1 && !perm) || (distance == -1 && perm)) ) || \ | ||||
| 	   ( F==1 && ((distance == -1 && !perm) || (distance == 1 && perm)) ) ){ \ | ||||
| 	DO_TWIST_0L_1H(Chimu_00,0,0,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_01,0,1,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_02,0,2,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_10,1,0,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_11,1,1,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_12,1,2,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_20,2,0,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_21,2,1,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_22,2,2,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_30,3,0,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_31,3,1,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_0L_1H(Chimu_32,3,2,F,PERM,  U_11,U_20,U_21);		\ | ||||
|       }else{								\ | ||||
| 	DO_TWIST_1L_0H(Chimu_00,0,0,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_01,0,1,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_02,0,2,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_10,1,0,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_11,1,1,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_12,1,2,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_20,2,0,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_21,2,1,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_22,2,2,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_30,3,0,F,PERM,  U_11,U_20,U_21);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_31,3,1,F,PERM,  U_00,U_01,U_10);		\ | ||||
| 	DO_TWIST_1L_0H(Chimu_32,3,2,F,PERM,  U_11,U_20,U_21);		\ | ||||
|       } \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|  | ||||
| #define LOAD_CHI_GPARITY_INPLACE_TWIST(DIR,F,PERM)				\ | ||||
|   { const SiteHalfSpinor &ref(buf[offset]);				\ | ||||
|     LOAD_CHI_SETUP(DIR,F);						\ | ||||
|     if(!inplace_twist){							\ | ||||
|       LOAD_CHI_BODY(g);							\ | ||||
|     }else{								\ | ||||
|       if(  ( F==0 && ((distance == 1 && !perm) || (distance == -1 && perm)) ) || \ | ||||
| 	   ( F==1 && ((distance == -1 && !perm) || (distance == 1 && perm)) ) ){ \ | ||||
| 	DO_TWIST_0L_1H(Chi_00,0,0,F,PERM,  U_00,U_01,U_10);			\ | ||||
| 	DO_TWIST_0L_1H(Chi_01,0,1,F,PERM,  U_11,U_20,U_21);			\ | ||||
| 	DO_TWIST_0L_1H(Chi_02,0,2,F,PERM,  UChi_00,UChi_01,UChi_02);		\ | ||||
| 	DO_TWIST_0L_1H(Chi_10,1,0,F,PERM,  UChi_10,UChi_11,UChi_12);		\ | ||||
| 	DO_TWIST_0L_1H(Chi_11,1,1,F,PERM,  U_00,U_01,U_10);			\ | ||||
| 	DO_TWIST_0L_1H(Chi_12,1,2,F,PERM,  U_11,U_20,U_21);			\ | ||||
|       }else{								\ | ||||
| 	DO_TWIST_1L_0H(Chi_00,0,0,F,PERM,  U_00,U_01,U_10);			\ | ||||
| 	DO_TWIST_1L_0H(Chi_01,0,1,F,PERM,  U_11,U_20,U_21);			\ | ||||
| 	DO_TWIST_1L_0H(Chi_02,0,2,F,PERM,  UChi_00,UChi_01,UChi_02);		\ | ||||
| 	DO_TWIST_1L_0H(Chi_10,1,0,F,PERM,  UChi_10,UChi_11,UChi_12);		\ | ||||
| 	DO_TWIST_1L_0H(Chi_11,1,1,F,PERM,  U_00,U_01,U_10);			\ | ||||
| 	DO_TWIST_1L_0H(Chi_12,1,2,F,PERM,  U_11,U_20,U_21);			\ | ||||
|       }									\ | ||||
|     }									\ | ||||
|   } | ||||
|  | ||||
|  | ||||
| #define LOAD_CHI_GPARITY(DIR,F,PERM) LOAD_CHI_GPARITY_INPLACE_TWIST(DIR,F,PERM) | ||||
| #define LOAD_CHIMU_GPARITY(DIR,F,PERM) LOAD_CHIMU_GPARITY_INPLACE_TWIST(DIR,F,PERM) | ||||
|  | ||||
| // To splat or not to splat depends on the implementation | ||||
| #define MULT_2SPIN(A)\ | ||||
|   {auto & ref(U._odata[sU](A));			\ | ||||
|    Impl::loadLinkElement(U_00,ref()(0,0));	\ | ||||
|    Impl::loadLinkElement(U_10,ref()(1,0));	\ | ||||
|    Impl::loadLinkElement(U_20,ref()(2,0));	\ | ||||
|    Impl::loadLinkElement(U_01,ref()(0,1));	\ | ||||
|    Impl::loadLinkElement(U_11,ref()(1,1));	\ | ||||
|    Impl::loadLinkElement(U_21,ref()(2,1));	\ | ||||
|     UChi_00 = U_00*Chi_00;\ | ||||
|     UChi_10 = U_00*Chi_10;\ | ||||
|     UChi_01 = U_10*Chi_00;\ | ||||
|     UChi_11 = U_10*Chi_10;\ | ||||
|     UChi_02 = U_20*Chi_00;\ | ||||
|     UChi_12 = U_20*Chi_10;\ | ||||
|     UChi_00+= U_01*Chi_01;\ | ||||
|     UChi_10+= U_01*Chi_11;\ | ||||
|     UChi_01+= U_11*Chi_01;\ | ||||
|     UChi_11+= U_11*Chi_11;\ | ||||
|     UChi_02+= U_21*Chi_01;\ | ||||
|     UChi_12+= U_21*Chi_11;\ | ||||
|     Impl::loadLinkElement(U_00,ref()(0,2));	\ | ||||
|     Impl::loadLinkElement(U_10,ref()(1,2));	\ | ||||
|     Impl::loadLinkElement(U_20,ref()(2,2));	\ | ||||
|     UChi_00+= U_00*Chi_02;\ | ||||
|     UChi_10+= U_00*Chi_12;\ | ||||
|     UChi_01+= U_10*Chi_02;\ | ||||
|     UChi_11+= U_10*Chi_12;\ | ||||
|     UChi_02+= U_20*Chi_02;\ | ||||
|     UChi_12+= U_20*Chi_12;} | ||||
| #define MULT_2SPIN_BODY \ | ||||
|   Impl::loadLinkElement(U_00,ref()(0,0));	\ | ||||
|   Impl::loadLinkElement(U_10,ref()(1,0));	\ | ||||
|   Impl::loadLinkElement(U_20,ref()(2,0));	\ | ||||
|   Impl::loadLinkElement(U_01,ref()(0,1));	\ | ||||
|   Impl::loadLinkElement(U_11,ref()(1,1));	\ | ||||
|   Impl::loadLinkElement(U_21,ref()(2,1));	\ | ||||
|   UChi_00 = U_00*Chi_00;			\ | ||||
|   UChi_10 = U_00*Chi_10;			\ | ||||
|   UChi_01 = U_10*Chi_00;			\ | ||||
|   UChi_11 = U_10*Chi_10;			\ | ||||
|   UChi_02 = U_20*Chi_00;			\ | ||||
|   UChi_12 = U_20*Chi_10;			\ | ||||
|   UChi_00+= U_01*Chi_01;			\ | ||||
|   UChi_10+= U_01*Chi_11;			\ | ||||
|   UChi_01+= U_11*Chi_01;			\ | ||||
|   UChi_11+= U_11*Chi_11;			\ | ||||
|   UChi_02+= U_21*Chi_01;			\ | ||||
|   UChi_12+= U_21*Chi_11;			\ | ||||
|   Impl::loadLinkElement(U_00,ref()(0,2));	\ | ||||
|   Impl::loadLinkElement(U_10,ref()(1,2));	\ | ||||
|   Impl::loadLinkElement(U_20,ref()(2,2));	\ | ||||
|   UChi_00+= U_00*Chi_02;			\ | ||||
|   UChi_10+= U_00*Chi_12;			\ | ||||
|   UChi_01+= U_10*Chi_02;			\ | ||||
|   UChi_11+= U_10*Chi_12;			\ | ||||
|   UChi_02+= U_20*Chi_02;			\ | ||||
|   UChi_12+= U_20*Chi_12 | ||||
|  | ||||
|  | ||||
| #define MULT_2SPIN(A,F)					\ | ||||
|   {auto & ref(U._odata[sU](A)); MULT_2SPIN_BODY; } | ||||
|  | ||||
| #define MULT_2SPIN_GPARITY(A,F)				\ | ||||
|   {auto & ref(U._odata[sU](F)(A)); MULT_2SPIN_BODY; } | ||||
|  | ||||
|  | ||||
| #define PERMUTE_DIR(dir)			\ | ||||
| @@ -307,84 +428,87 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
|   result_31-= UChi_11;	\ | ||||
|   result_32-= UChi_12; | ||||
|  | ||||
| #define HAND_STENCIL_LEG(PROJ,PERM,DIR,RECON)	\ | ||||
| #define HAND_STENCIL_LEG(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ | ||||
|   SE=st.GetEntry(ptype,DIR,ss);			\ | ||||
|   offset = SE->_offset;				\ | ||||
|   local  = SE->_is_local;			\ | ||||
|   perm   = SE->_permute;			\ | ||||
|   if ( local ) {				\ | ||||
|     LOAD_CHIMU;					\ | ||||
|     LOAD_CHIMU_IMPL(DIR,F,PERM);			\ | ||||
|     PROJ;					\ | ||||
|     if ( perm) {				\ | ||||
|       PERMUTE_DIR(PERM);			\ | ||||
|     }						\ | ||||
|   } else {					\ | ||||
|     LOAD_CHI;					\ | ||||
|     LOAD_CHI_IMPL(DIR,F,PERM);			\ | ||||
|   }						\ | ||||
|   MULT_2SPIN(DIR);				\ | ||||
|   MULT_2SPIN_IMPL(DIR,F);			\ | ||||
|   RECON;					 | ||||
|  | ||||
| #define HAND_STENCIL_LEG_INT(PROJ,PERM,DIR,RECON)	\ | ||||
|  | ||||
| #define HAND_STENCIL_LEG_INT(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL)	\ | ||||
|   SE=st.GetEntry(ptype,DIR,ss);			\ | ||||
|   offset = SE->_offset;				\ | ||||
|   local  = SE->_is_local;			\ | ||||
|   perm   = SE->_permute;			\ | ||||
|   if ( local ) {				\ | ||||
|     LOAD_CHIMU;					\ | ||||
|     LOAD_CHIMU_IMPL(DIR,F,PERM);			\ | ||||
|     PROJ;					\ | ||||
|     if ( perm) {				\ | ||||
|       PERMUTE_DIR(PERM);			\ | ||||
|     }						\ | ||||
|   } else if ( st.same_node[DIR] ) {		\ | ||||
|     LOAD_CHI;					\ | ||||
|     LOAD_CHI_IMPL(DIR,F,PERM);			\ | ||||
|   }						\ | ||||
|   if (local || st.same_node[DIR] ) {		\ | ||||
|     MULT_2SPIN(DIR);				\ | ||||
|     MULT_2SPIN_IMPL(DIR,F);			\ | ||||
|     RECON;					\ | ||||
|   } | ||||
|  | ||||
| #define HAND_STENCIL_LEG_EXT(PROJ,PERM,DIR,RECON)	\ | ||||
| #define HAND_STENCIL_LEG_EXT(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL)	\ | ||||
|   SE=st.GetEntry(ptype,DIR,ss);			\ | ||||
|   offset = SE->_offset;				\ | ||||
|   local  = SE->_is_local;			\ | ||||
|   perm   = SE->_permute;			\ | ||||
|   if((!SE->_is_local)&&(!st.same_node[DIR]) ) {	\ | ||||
|     LOAD_CHI;					\ | ||||
|     MULT_2SPIN(DIR);				\ | ||||
|     LOAD_CHI_IMPL(DIR,F,PERM);			\ | ||||
|     MULT_2SPIN_IMPL(DIR,F);			\ | ||||
|     RECON;					\ | ||||
|     nmu++;					\ | ||||
|   } | ||||
|  | ||||
| #define HAND_RESULT(ss)				\ | ||||
| #define HAND_RESULT(ss,F)			\ | ||||
|   {						\ | ||||
|     SiteSpinor & ref (out._odata[ss]);		\ | ||||
|     vstream(ref()(0)(0),result_00);		\ | ||||
|     vstream(ref()(0)(1),result_01);		\ | ||||
|     vstream(ref()(0)(2),result_02);		\ | ||||
|     vstream(ref()(1)(0),result_10);		\ | ||||
|     vstream(ref()(1)(1),result_11);		\ | ||||
|     vstream(ref()(1)(2),result_12);		\ | ||||
|     vstream(ref()(2)(0),result_20);		\ | ||||
|     vstream(ref()(2)(1),result_21);		\ | ||||
|     vstream(ref()(2)(2),result_22);		\ | ||||
|     vstream(ref()(3)(0),result_30);		\ | ||||
|     vstream(ref()(3)(1),result_31);		\ | ||||
|     vstream(ref()(3)(2),result_32);		\ | ||||
|     vstream(ref(F)(0)(0),result_00);		\ | ||||
|     vstream(ref(F)(0)(1),result_01);		\ | ||||
|     vstream(ref(F)(0)(2),result_02);		\ | ||||
|     vstream(ref(F)(1)(0),result_10);		\ | ||||
|     vstream(ref(F)(1)(1),result_11);		\ | ||||
|     vstream(ref(F)(1)(2),result_12);		\ | ||||
|     vstream(ref(F)(2)(0),result_20);		\ | ||||
|     vstream(ref(F)(2)(1),result_21);		\ | ||||
|     vstream(ref(F)(2)(2),result_22);		\ | ||||
|     vstream(ref(F)(3)(0),result_30);		\ | ||||
|     vstream(ref(F)(3)(1),result_31);		\ | ||||
|     vstream(ref(F)(3)(2),result_32);		\ | ||||
|   } | ||||
|  | ||||
| #define HAND_RESULT_EXT(ss)			\ | ||||
| #define HAND_RESULT_EXT(ss,F)			\ | ||||
|   if (nmu){					\ | ||||
|     SiteSpinor & ref (out._odata[ss]);		\ | ||||
|     ref()(0)(0)+=result_00;		\ | ||||
|     ref()(0)(1)+=result_01;		\ | ||||
|     ref()(0)(2)+=result_02;		\ | ||||
|     ref()(1)(0)+=result_10;		\ | ||||
|     ref()(1)(1)+=result_11;		\ | ||||
|     ref()(1)(2)+=result_12;		\ | ||||
|     ref()(2)(0)+=result_20;		\ | ||||
|     ref()(2)(1)+=result_21;		\ | ||||
|     ref()(2)(2)+=result_22;		\ | ||||
|     ref()(3)(0)+=result_30;		\ | ||||
|     ref()(3)(1)+=result_31;		\ | ||||
|     ref()(3)(2)+=result_32;		\ | ||||
|     ref(F)(0)(0)+=result_00;		\ | ||||
|     ref(F)(0)(1)+=result_01;		\ | ||||
|     ref(F)(0)(2)+=result_02;		\ | ||||
|     ref(F)(1)(0)+=result_10;		\ | ||||
|     ref(F)(1)(1)+=result_11;		\ | ||||
|     ref(F)(1)(2)+=result_12;		\ | ||||
|     ref(F)(2)(0)+=result_20;		\ | ||||
|     ref(F)(2)(1)+=result_21;		\ | ||||
|     ref(F)(2)(2)+=result_22;		\ | ||||
|     ref(F)(3)(0)+=result_30;		\ | ||||
|     ref(F)(3)(1)+=result_31;		\ | ||||
|     ref(F)(3)(2)+=result_32;		\ | ||||
|   } | ||||
|  | ||||
|  | ||||
| @@ -463,15 +587,18 @@ WilsonKernels<Impl>::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGauge | ||||
|   int offset,local,perm, ptype; | ||||
|   StencilEntry *SE; | ||||
|  | ||||
|   HAND_STENCIL_LEG(XM_PROJ,3,Xp,XM_RECON); | ||||
|   HAND_STENCIL_LEG(YM_PROJ,2,Yp,YM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(ZM_PROJ,1,Zp,ZM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(TM_PROJ,0,Tp,TM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(XP_PROJ,3,Xm,XP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(YP_PROJ,2,Ym,YP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(ZP_PROJ,1,Zm,ZP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(TP_PROJ,0,Tm,TP_RECON_ACCUM); | ||||
|   HAND_RESULT(ss); | ||||
| #define HAND_DOP_SITE(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ | ||||
|   HAND_STENCIL_LEG(XM_PROJ,3,Xp,XM_RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);	\ | ||||
|   HAND_STENCIL_LEG(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_RESULT(ss,F) | ||||
|  | ||||
|   HAND_DOP_SITE(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); | ||||
| } | ||||
|  | ||||
| template<class Impl> | ||||
| @@ -486,15 +613,18 @@ void WilsonKernels<Impl>::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,Doub | ||||
|   StencilEntry *SE; | ||||
|   int offset,local,perm, ptype; | ||||
|  | ||||
|   HAND_STENCIL_LEG(XP_PROJ,3,Xp,XP_RECON); | ||||
|   HAND_STENCIL_LEG(YP_PROJ,2,Yp,YP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(ZP_PROJ,1,Zp,ZP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(TP_PROJ,0,Tp,TP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(XM_PROJ,3,Xm,XM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(YM_PROJ,2,Ym,YM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(ZM_PROJ,1,Zm,ZM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG(TM_PROJ,0,Tm,TM_RECON_ACCUM); | ||||
|   HAND_RESULT(ss); | ||||
| #define HAND_DOP_SITE_DAG(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ | ||||
|   HAND_STENCIL_LEG(XP_PROJ,3,Xp,XP_RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_RESULT(ss,F) | ||||
|  | ||||
|   HAND_DOP_SITE_DAG(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); | ||||
| } | ||||
|  | ||||
| template<class Impl> void  | ||||
| @@ -509,16 +639,20 @@ WilsonKernels<Impl>::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGa | ||||
|  | ||||
|   int offset,local,perm, ptype; | ||||
|   StencilEntry *SE; | ||||
|   ZERO_RESULT; | ||||
|   HAND_STENCIL_LEG_INT(XM_PROJ,3,Xp,XM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(YM_PROJ,2,Yp,YM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(TM_PROJ,0,Tp,TM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(XP_PROJ,3,Xm,XP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(YP_PROJ,2,Ym,YP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(TP_PROJ,0,Tm,TP_RECON_ACCUM); | ||||
|   HAND_RESULT(ss); | ||||
|  | ||||
| #define HAND_DOP_SITE_INT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ | ||||
|   ZERO_RESULT; \ | ||||
|   HAND_STENCIL_LEG_INT(XM_PROJ,3,Xp,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_INT(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_RESULT(ss,F) | ||||
|  | ||||
|   HAND_DOP_SITE_INT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); | ||||
| } | ||||
|  | ||||
| template<class Impl> | ||||
| @@ -532,16 +666,20 @@ void WilsonKernels<Impl>::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,D | ||||
|  | ||||
|   StencilEntry *SE; | ||||
|   int offset,local,perm, ptype; | ||||
|   ZERO_RESULT; | ||||
|   HAND_STENCIL_LEG_INT(XP_PROJ,3,Xp,XP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(YP_PROJ,2,Yp,YP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(TP_PROJ,0,Tp,TP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(XM_PROJ,3,Xm,XM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(YM_PROJ,2,Ym,YM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_INT(TM_PROJ,0,Tm,TM_RECON_ACCUM); | ||||
|   HAND_RESULT(ss); | ||||
|  | ||||
| #define HAND_DOP_SITE_DAG_INT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL)				\ | ||||
|   ZERO_RESULT;							\ | ||||
|   HAND_STENCIL_LEG_INT(XP_PROJ,3,Xp,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_STENCIL_LEG_INT(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL);		\ | ||||
|   HAND_RESULT(ss,F) | ||||
|    | ||||
|   HAND_DOP_SITE_DAG_INT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); | ||||
| } | ||||
|  | ||||
| template<class Impl> void  | ||||
| @@ -557,16 +695,20 @@ WilsonKernels<Impl>::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGa | ||||
|   int offset,local,perm, ptype; | ||||
|   StencilEntry *SE; | ||||
|   int nmu=0; | ||||
|   ZERO_RESULT; | ||||
|   HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xp,XM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(YM_PROJ,2,Yp,YM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tp,TM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xm,XP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(YP_PROJ,2,Ym,YP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tm,TP_RECON_ACCUM); | ||||
|   HAND_RESULT_EXT(ss); | ||||
|  | ||||
| #define HAND_DOP_SITE_EXT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ | ||||
|   ZERO_RESULT; \ | ||||
|   HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xp,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_RESULT_EXT(ss,F) | ||||
|  | ||||
|   HAND_DOP_SITE_EXT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); | ||||
| } | ||||
|  | ||||
| template<class Impl> | ||||
| @@ -581,16 +723,20 @@ void WilsonKernels<Impl>::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,D | ||||
|   StencilEntry *SE; | ||||
|   int offset,local,perm, ptype; | ||||
|   int nmu=0; | ||||
|   ZERO_RESULT; | ||||
|   HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xp,XP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(YP_PROJ,2,Yp,YP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tp,TP_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xm,XM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(YM_PROJ,2,Ym,YM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM); | ||||
|   HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tm,TM_RECON_ACCUM); | ||||
|   HAND_RESULT_EXT(ss); | ||||
|  | ||||
| #define HAND_DOP_SITE_DAG_EXT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ | ||||
|   ZERO_RESULT; \ | ||||
|   HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xp,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ | ||||
|   HAND_RESULT_EXT(ss,F) | ||||
|  | ||||
|   HAND_DOP_SITE_DAG_EXT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); | ||||
| } | ||||
|  | ||||
|   //////////////////////////////////////////////// | ||||
| @@ -646,10 +792,123 @@ void WilsonKernels<Impl>::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,D | ||||
| 				    const FermionField &in,		\ | ||||
| 				    FermionField &out){ assert(0); }	\ | ||||
|  | ||||
|   HAND_SPECIALISE_EMPTY(GparityWilsonImplF); | ||||
|   HAND_SPECIALISE_EMPTY(GparityWilsonImplD); | ||||
|   HAND_SPECIALISE_EMPTY(GparityWilsonImplFH); | ||||
|   HAND_SPECIALISE_EMPTY(GparityWilsonImplDF); | ||||
|  | ||||
|  | ||||
| #define HAND_SPECIALISE_GPARITY(IMPL)					\ | ||||
|   template<> void							\ | ||||
|   WilsonKernels<IMPL>::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor  *buf, \ | ||||
| 				    int ss,int sU,const FermionField &in, FermionField &out) \ | ||||
|   {									\ | ||||
|     typedef IMPL Impl;							\ | ||||
|     typedef typename Simd::scalar_type S;				\ | ||||
|     typedef typename Simd::vector_type V;				\ | ||||
| 									\ | ||||
|     HAND_DECLARATIONS(ignore);						\ | ||||
| 									\ | ||||
|     int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ | ||||
|     StencilEntry *SE;							\ | ||||
|     HAND_DOP_SITE(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|     HAND_DOP_SITE(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|   }									\ | ||||
| 									\ | ||||
|   template<>								\ | ||||
|   void WilsonKernels<IMPL>::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ | ||||
| 					    int ss,int sU,const FermionField &in, FermionField &out) \ | ||||
|   {									\ | ||||
|     typedef IMPL Impl;							\ | ||||
|     typedef typename Simd::scalar_type S;				\ | ||||
|     typedef typename Simd::vector_type V;				\ | ||||
| 									\ | ||||
|     HAND_DECLARATIONS(ignore);						\ | ||||
| 									\ | ||||
|     StencilEntry *SE;							\ | ||||
|     int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist;					\ | ||||
|     HAND_DOP_SITE_DAG(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|     HAND_DOP_SITE_DAG(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|   }									\ | ||||
| 									\ | ||||
|   template<> void							\ | ||||
|   WilsonKernels<IMPL>::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor  *buf, \ | ||||
| 						     int ss,int sU,const FermionField &in, FermionField &out) \ | ||||
|   {									\ | ||||
|     typedef IMPL Impl;							\ | ||||
|     typedef typename Simd::scalar_type S;				\ | ||||
|     typedef typename Simd::vector_type V;				\ | ||||
| 									\ | ||||
|     HAND_DECLARATIONS(ignore);						\ | ||||
| 									\ | ||||
|     int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist;					\ | ||||
|     StencilEntry *SE;							\ | ||||
|     HAND_DOP_SITE_INT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|     HAND_DOP_SITE_INT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|   }									\ | ||||
| 									\ | ||||
|   template<>								\ | ||||
|   void WilsonKernels<IMPL>::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ | ||||
| 							     int ss,int sU,const FermionField &in, FermionField &out) \ | ||||
|   {									\ | ||||
|     typedef IMPL Impl;							\ | ||||
|     typedef typename Simd::scalar_type S;				\ | ||||
|     typedef typename Simd::vector_type V;				\ | ||||
| 									\ | ||||
|     HAND_DECLARATIONS(ignore);						\ | ||||
| 									\ | ||||
|     StencilEntry *SE;							\ | ||||
|     int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ | ||||
|     HAND_DOP_SITE_DAG_INT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|     HAND_DOP_SITE_DAG_INT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|   }									\ | ||||
| 									\ | ||||
|   template<> void							\ | ||||
|   WilsonKernels<IMPL>::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor  *buf, \ | ||||
| 						     int ss,int sU,const FermionField &in, FermionField &out) \ | ||||
|   {									\ | ||||
|     typedef IMPL Impl;							\ | ||||
|     typedef typename Simd::scalar_type S;				\ | ||||
|     typedef typename Simd::vector_type V;				\ | ||||
| 									\ | ||||
|     HAND_DECLARATIONS(ignore);						\ | ||||
| 									\ | ||||
|     int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ | ||||
|     StencilEntry *SE;							\ | ||||
|     int nmu=0;								\ | ||||
|     HAND_DOP_SITE_EXT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|     nmu = 0;								\ | ||||
|     HAND_DOP_SITE_EXT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|   }									\ | ||||
|   template<>								\ | ||||
|   void WilsonKernels<IMPL>::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ | ||||
| 							     int ss,int sU,const FermionField &in, FermionField &out) \ | ||||
|   {									\ | ||||
|     typedef IMPL Impl;							\ | ||||
|     typedef typename Simd::scalar_type S;				\ | ||||
|     typedef typename Simd::vector_type V;				\ | ||||
| 									\ | ||||
|     HAND_DECLARATIONS(ignore);						\ | ||||
| 									\ | ||||
|     StencilEntry *SE;							\ | ||||
|     int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ | ||||
|     int nmu=0;								\ | ||||
|     HAND_DOP_SITE_DAG_EXT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|     nmu = 0;								\ | ||||
|     HAND_DOP_SITE_DAG_EXT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ | ||||
|   } | ||||
|  | ||||
|  | ||||
| HAND_SPECIALISE_GPARITY(GparityWilsonImplF); | ||||
| HAND_SPECIALISE_GPARITY(GparityWilsonImplD); | ||||
| HAND_SPECIALISE_GPARITY(GparityWilsonImplFH); | ||||
| HAND_SPECIALISE_GPARITY(GparityWilsonImplDF); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|    | ||||
| ////////////// Wilson ; uses this implementation ///////////////////// | ||||
|  | ||||
|   | ||||
							
								
								
									
										264
									
								
								lib/qcd/action/pseudofermion/ExactOneFlavourRatio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								lib/qcd/action/pseudofermion/ExactOneFlavourRatio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,264 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./lib/qcd/action/pseudofermion/ExactOneFlavourRatio.h | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| 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 */ | ||||
|  | ||||
| ///////////////////////////////////////////////////////////////// | ||||
| // Implementation of exact one flavour algorithm (EOFA)         // | ||||
| // using fermion classes defined in:                           // | ||||
| //    Grid/qcd/action/fermion/DomainWallEOFAFermion.h (Shamir) // | ||||
| //    Grid/qcd/action/fermion/MobiusEOFAFermion.h (Mobius)     // | ||||
| // arXiv: 1403.1683, 1706.05843                                // | ||||
| ///////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #ifndef QCD_PSEUDOFERMION_EXACT_ONE_FLAVOUR_RATIO_H | ||||
| #define QCD_PSEUDOFERMION_EXACT_ONE_FLAVOUR_RATIO_H | ||||
|  | ||||
| namespace Grid{ | ||||
| namespace QCD{ | ||||
|  | ||||
|   /////////////////////////////////////////////////////////////// | ||||
|   // Exact one flavour implementation of DWF determinant ratio // | ||||
|   /////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   template<class Impl> | ||||
|   class ExactOneFlavourRatioPseudoFermionAction : public Action<typename Impl::GaugeField> | ||||
|   { | ||||
|     public: | ||||
|       INHERIT_IMPL_TYPES(Impl); | ||||
|       typedef OneFlavourRationalParams Params; | ||||
|       Params param; | ||||
|       MultiShiftFunction PowerNegHalf; | ||||
|  | ||||
|     private: | ||||
|       bool use_heatbath_forecasting; | ||||
|       AbstractEOFAFermion<Impl>& Lop; // the basic LH operator | ||||
|       AbstractEOFAFermion<Impl>& Rop; // the basic RH operator | ||||
|       SchurRedBlackDiagMooeeSolve<FermionField> Solver; | ||||
|       FermionField Phi; // the pseudofermion field for this trajectory | ||||
|  | ||||
|     public: | ||||
|       ExactOneFlavourRatioPseudoFermionAction(AbstractEOFAFermion<Impl>& _Lop, AbstractEOFAFermion<Impl>& _Rop, | ||||
|         OperatorFunction<FermionField>& S, Params& p, bool use_fc=false) : Lop(_Lop), Rop(_Rop), Solver(S), | ||||
|         Phi(_Lop.FermionGrid()), param(p), use_heatbath_forecasting(use_fc) | ||||
|       { | ||||
|         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); | ||||
|         PowerNegHalf.Init(remez, param.tolerance, true); | ||||
|       }; | ||||
|  | ||||
|       virtual std::string action_name() { return "ExactOneFlavourRatioPseudoFermionAction"; } | ||||
|  | ||||
|       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(); | ||||
|       } | ||||
|  | ||||
|       // Spin projection | ||||
|       void spProj(const FermionField& in, FermionField& out, int sign, int Ls) | ||||
|       { | ||||
|         if(sign == 1){ for(int s=0; s<Ls; ++s){ axpby_ssp_pplus(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); } } | ||||
|       } | ||||
|  | ||||
|       // EOFA heatbath: see Eqn. (29) of arXiv:1706.05843 | ||||
|       // We generate a Gaussian noise vector \eta, and then compute | ||||
|       //  \Phi = M_{\rm EOFA}^{-1/2} * \eta | ||||
|       // using a rational approximation to the inverse square root | ||||
|       virtual void refresh(const GaugeField& U, GridParallelRNG& pRNG) | ||||
|       { | ||||
|         Lop.ImportGauge(U); | ||||
|         Rop.ImportGauge(U); | ||||
|  | ||||
|         FermionField eta         (Lop.FermionGrid()); | ||||
|         FermionField CG_src      (Lop.FermionGrid()); | ||||
|         FermionField CG_soln     (Lop.FermionGrid()); | ||||
|         FermionField Forecast_src(Lop.FermionGrid()); | ||||
|         std::vector<FermionField> tmp(2, Lop.FermionGrid()); | ||||
|  | ||||
|         // Use chronological inverter to forecast solutions across poles | ||||
|         std::vector<FermionField> prev_solns; | ||||
|         if(use_heatbath_forecasting){ prev_solns.reserve(param.degree); } | ||||
|         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; | ||||
|         printf("Heatbath source vector: <\\eta|\\eta> = %1.15e\n", norm2(eta)); | ||||
|  | ||||
|         // \Phi = ( \alpha_{0} + \sum_{k=1}^{N_{p}} \alpha_{l} * \gamma_{l} ) * \eta | ||||
|         RealD N(PowerNegHalf.norm); | ||||
|         for(int k=0; k<param.degree; ++k){ N += PowerNegHalf.residues[k] / ( 1.0 + PowerNegHalf.poles[k] ); } | ||||
|         Phi = eta * N; | ||||
|  | ||||
|         // 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 | ||||
|         RealD gamma_l(0.0); | ||||
|         spProj(eta, tmp[0], -1, Lop.Ls); | ||||
|         Lop.Omega(tmp[0], tmp[1], -1, 0); | ||||
|         G5R5(CG_src, tmp[1]); | ||||
|         tmp[1] = zero; | ||||
|         for(int k=0; k<param.degree; ++k){ | ||||
|           gamma_l = 1.0 / ( 1.0 + PowerNegHalf.poles[k] ); | ||||
|           Lop.RefreshShiftCoefficients(-gamma_l); | ||||
|           if(use_heatbath_forecasting){ // Forecast CG guess using solutions from previous poles | ||||
|             Lop.Mdag(CG_src, Forecast_src); | ||||
|             CG_soln = Forecast(Lop, Forecast_src, prev_solns); | ||||
|             Solver(Lop, CG_src, CG_soln); | ||||
|             prev_solns.push_back(CG_soln); | ||||
|           } else { | ||||
|             CG_soln = zero; // Just use zero as the initial guess | ||||
|             Solver(Lop, CG_src, CG_soln); | ||||
|           } | ||||
|           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]; | ||||
|         } | ||||
|         Lop.Omega(tmp[1], tmp[0], -1, 1); | ||||
|         spProj(tmp[0], tmp[1], -1, Lop.Ls); | ||||
|         Phi = Phi + tmp[1]; | ||||
|  | ||||
|         // RH terms: | ||||
|         // \Phi = \Phi - k \sum_{k=1}^{N_{p}} P_{+} \Omega_{+}^{\dagger} ( H(mb) | ||||
|         //          + \gamma_{l} \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{+} P_{+} \eta | ||||
|         spProj(eta, tmp[0], 1, Rop.Ls); | ||||
|         Rop.Omega(tmp[0], tmp[1], 1, 0); | ||||
|         G5R5(CG_src, tmp[1]); | ||||
|         tmp[1] = zero; | ||||
|         if(use_heatbath_forecasting){ prev_solns.clear(); } // empirically, LH solns don't help for RH solves | ||||
|         for(int k=0; k<param.degree; ++k){ | ||||
|           gamma_l = 1.0 / ( 1.0 + PowerNegHalf.poles[k] ); | ||||
|           Rop.RefreshShiftCoefficients(-gamma_l*PowerNegHalf.poles[k]); | ||||
|           if(use_heatbath_forecasting){ | ||||
|             Rop.Mdag(CG_src, Forecast_src); | ||||
|             CG_soln = Forecast(Rop, Forecast_src, prev_solns); | ||||
|             Solver(Rop, CG_src, CG_soln); | ||||
|             prev_solns.push_back(CG_soln); | ||||
|           } else { | ||||
|             CG_soln = zero; | ||||
|             Solver(Rop, CG_src, CG_soln); | ||||
|           } | ||||
|           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]; | ||||
|         } | ||||
|         Rop.Omega(tmp[1], tmp[0], 1, 1); | ||||
|         spProj(tmp[0], tmp[1], 1, Rop.Ls); | ||||
|         Phi = Phi + tmp[1]; | ||||
|  | ||||
|         // Reset shift coefficients for energy and force evals | ||||
|         Lop.RefreshShiftCoefficients(0.0); | ||||
|         Rop.RefreshShiftCoefficients(-1.0); | ||||
|       }; | ||||
|  | ||||
|       // EOFA action: see Eqn. (10) of arXiv:1706.05843 | ||||
|       virtual RealD S(const GaugeField& U) | ||||
|       { | ||||
|         Lop.ImportGauge(U); | ||||
|         Rop.ImportGauge(U); | ||||
|  | ||||
|         FermionField spProj_Phi(Lop.FermionGrid()); | ||||
|         std::vector<FermionField> tmp(2, Lop.FermionGrid()); | ||||
|  | ||||
|         // S = <\Phi|\Phi> | ||||
|         RealD action(norm2(Phi)); | ||||
|  | ||||
|         // LH term: S = S - k <\Phi| P_{-} \Omega_{-}^{\dagger} H(mf)^{-1} \Omega_{-} P_{-} |\Phi> | ||||
|         spProj(Phi, spProj_Phi, -1, Lop.Ls); | ||||
|         Lop.Omega(spProj_Phi, tmp[0], -1, 0); | ||||
|         G5R5(tmp[1], tmp[0]); | ||||
|         tmp[0] = zero; | ||||
|         Solver(Lop, tmp[1], tmp[0]); | ||||
|         Lop.Dtilde(tmp[0], tmp[1]); // We actually solved Cayley preconditioned system: transform back | ||||
|         Lop.Omega(tmp[1], tmp[0], -1, 1); | ||||
|         action -= Lop.k * innerProduct(spProj_Phi, tmp[0]).real(); | ||||
|  | ||||
|         // RH term: S = S + k <\Phi| P_{+} \Omega_{+}^{\dagger} ( H(mb) | ||||
|         //               - \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{-} P_{-} |\Phi> | ||||
|         spProj(Phi, spProj_Phi, 1, Rop.Ls); | ||||
|         Rop.Omega(spProj_Phi, tmp[0], 1, 0); | ||||
|         G5R5(tmp[1], tmp[0]); | ||||
|         tmp[0] = zero; | ||||
|         Solver(Rop, tmp[1], tmp[0]); | ||||
|         Rop.Dtilde(tmp[0], tmp[1]); | ||||
|         Rop.Omega(tmp[1], tmp[0], 1, 1); | ||||
|         action += Rop.k * innerProduct(spProj_Phi, tmp[0]).real(); | ||||
|  | ||||
|         return action; | ||||
|       }; | ||||
|  | ||||
|       // EOFA pseudofermion force: see Eqns. (34)-(36) of arXiv:1706.05843 | ||||
|       virtual void deriv(const GaugeField& U, GaugeField& dSdU) | ||||
|       { | ||||
|         Lop.ImportGauge(U); | ||||
|         Rop.ImportGauge(U); | ||||
|  | ||||
|         FermionField spProj_Phi      (Lop.FermionGrid()); | ||||
|         FermionField Omega_spProj_Phi(Lop.FermionGrid()); | ||||
|         FermionField CG_src          (Lop.FermionGrid()); | ||||
|         FermionField Chi             (Lop.FermionGrid()); | ||||
|         FermionField g5_R5_Chi       (Lop.FermionGrid()); | ||||
|  | ||||
|         GaugeField force(Lop.GaugeGrid()); | ||||
|  | ||||
|         // LH: dSdU = k \chi_{L}^{\dagger} \gamma_{5} R_{5} ( \partial_{x,\mu} D_{w} ) \chi_{L} | ||||
|         //     \chi_{L} = H(mf)^{-1} \Omega_{-} P_{-} \Phi | ||||
|         spProj(Phi, spProj_Phi, -1, Lop.Ls); | ||||
|         Lop.Omega(spProj_Phi, Omega_spProj_Phi, -1, 0); | ||||
|         G5R5(CG_src, Omega_spProj_Phi); | ||||
|         spProj_Phi = zero; | ||||
|         Solver(Lop, CG_src, spProj_Phi); | ||||
|         Lop.Dtilde(spProj_Phi, Chi); | ||||
|         G5R5(g5_R5_Chi, Chi); | ||||
|         Lop.MDeriv(force, g5_R5_Chi, Chi, DaggerNo); | ||||
|         dSdU = Lop.k * force; | ||||
|  | ||||
|         // RH: dSdU = dSdU - k \chi_{R}^{\dagger} \gamma_{5} R_{5} ( \partial_{x,\mu} D_{w} ) \chi_{} | ||||
|         //     \chi_{R} = ( H(mb) - \Delta_{+}(mf,mb) P_{+} )^{-1} \Omega_{+} P_{+} \Phi | ||||
|         spProj(Phi, spProj_Phi, 1, Rop.Ls); | ||||
|         Rop.Omega(spProj_Phi, Omega_spProj_Phi, 1, 0); | ||||
|         G5R5(CG_src, Omega_spProj_Phi); | ||||
|         spProj_Phi = zero; | ||||
|         Solver(Rop, CG_src, spProj_Phi); | ||||
|         Rop.Dtilde(spProj_Phi, Chi); | ||||
|         G5R5(g5_R5_Chi, Chi); | ||||
|         Lop.MDeriv(force, g5_R5_Chi, Chi, DaggerNo); | ||||
|         dSdU = dSdU - Rop.k * force; | ||||
|       }; | ||||
|   }; | ||||
| }} | ||||
|  | ||||
| #endif | ||||
| @@ -38,5 +38,6 @@ directory | ||||
| #include <Grid/qcd/action/pseudofermion/OneFlavourRationalRatio.h> | ||||
| #include <Grid/qcd/action/pseudofermion/OneFlavourEvenOddRational.h> | ||||
| #include <Grid/qcd/action/pseudofermion/OneFlavourEvenOddRationalRatio.h> | ||||
| #include <Grid/qcd/action/pseudofermion/ExactOneFlavourRatio.h> | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -231,7 +231,7 @@ class ForceGradient : public Integrator<FieldImplementation, SmearingPolicy, | ||||
|     Field Pfg(U._grid); | ||||
|     Ufg = U; | ||||
|     Pfg = zero; | ||||
|     std::cout << GridLogMessage << "FG update " << fg_dt << " " << ep | ||||
|     std::cout << GridLogIntegrator << "FG update " << fg_dt << " " << ep | ||||
|               << std::endl; | ||||
|     // prepare_fg; no prediction/result cache for now | ||||
|     // could relax CG stopping conditions for the | ||||
|   | ||||
| @@ -202,6 +202,39 @@ class DomainWallFermionModule: public FermionOperatorModule<DomainWallFermion, F | ||||
| }; | ||||
|  | ||||
|  | ||||
| class DomainWallEOFAFermionParameters : Serializable { | ||||
|  public: | ||||
|   GRID_SERIALIZABLE_CLASS_MEMBERS(DomainWallEOFAFermionParameters, | ||||
|     RealD, mq1, | ||||
|     RealD, mq2, | ||||
|     RealD, mq3, | ||||
|     RealD, shift, | ||||
|     int, pm, | ||||
|     RealD, M5, | ||||
|     unsigned int, Ls); | ||||
| }; | ||||
|  | ||||
| template <class FermionImpl > | ||||
| class DomainWallEOFAFermionModule: public FermionOperatorModule<DomainWallEOFAFermion, FermionImpl, DomainWallEOFAFermionParameters> { | ||||
|   typedef FermionOperatorModule<DomainWallEOFAFermion, FermionImpl, DomainWallEOFAFermionParameters> FermBase; | ||||
|   using FermBase::FermBase; // for constructors | ||||
|  | ||||
|   virtual unsigned int Ls(){ | ||||
|     return this->Par_.Ls; | ||||
|   } | ||||
|  | ||||
|   // acquire resource | ||||
|   virtual void initialize(){ | ||||
|     auto GridMod = this->GridRefs[0]; | ||||
|     auto GridMod5d = this->GridRefs[1]; | ||||
|     typename FermionImpl::GaugeField U(GridMod->get_full()); | ||||
|     this->FOPtr.reset(new DomainWallEOFAFermion<FermionImpl>( U, *(GridMod->get_full()), *(GridMod->get_rb()), | ||||
|                                                       *(GridMod5d->get_full()), *(GridMod5d->get_rb()), | ||||
|                                                       this->Par_.mq1, this->Par_.mq2, this->Par_.mq3, | ||||
|                                                       this->Par_.shift, this->Par_.pm, this->Par_.M5)); | ||||
|   } | ||||
| }; | ||||
|  | ||||
|  | ||||
| } // QCD | ||||
| } // Grid | ||||
|   | ||||
| @@ -60,7 +60,7 @@ GridCartesian         *SpaceTimeGrid::makeFiveDimGrid(int Ls,const GridCartesian | ||||
|     simd5.push_back(FourDimGrid->_simd_layout[d]); | ||||
|      mpi5.push_back(FourDimGrid->_processors[d]); | ||||
|   } | ||||
|   return new GridCartesian(latt5,simd5,mpi5);  | ||||
|   return new GridCartesian(latt5,simd5,mpi5,*FourDimGrid);  | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -68,18 +68,14 @@ GridRedBlackCartesian *SpaceTimeGrid::makeFiveDimRedBlackGrid(int Ls,const GridC | ||||
| { | ||||
|   int N4=FourDimGrid->_ndimension; | ||||
|   int cbd=1; | ||||
|   std::vector<int> latt5(1,Ls); | ||||
|   std::vector<int> simd5(1,1); | ||||
|   std::vector<int>  mpi5(1,1); | ||||
|   std::vector<int>   cb5(1,0); | ||||
|      | ||||
|   for(int d=0;d<N4;d++){ | ||||
|     latt5.push_back(FourDimGrid->_fdimensions[d]); | ||||
|     simd5.push_back(FourDimGrid->_simd_layout[d]); | ||||
|      mpi5.push_back(FourDimGrid->_processors[d]); | ||||
|       cb5.push_back(  1); | ||||
|     } | ||||
|   return new GridRedBlackCartesian(latt5,simd5,mpi5,cb5,cbd);  | ||||
|   } | ||||
|   GridCartesian *tmp = makeFiveDimGrid(Ls,FourDimGrid); | ||||
|   GridRedBlackCartesian *ret = new GridRedBlackCartesian(tmp,cb5,cbd);  | ||||
|   delete tmp; | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -97,26 +93,24 @@ GridCartesian         *SpaceTimeGrid::makeFiveDimDWFGrid(int Ls,const GridCartes | ||||
|     simd5.push_back(1); | ||||
|      mpi5.push_back(FourDimGrid->_processors[d]); | ||||
|   } | ||||
|   return new GridCartesian(latt5,simd5,mpi5);  | ||||
|   return new GridCartesian(latt5,simd5,mpi5,*FourDimGrid);  | ||||
| } | ||||
|  | ||||
| /////////////////////////////////////////////////// | ||||
| // Interface is inefficient and forces the deletion | ||||
| // Pass in the non-redblack grid | ||||
| /////////////////////////////////////////////////// | ||||
| GridRedBlackCartesian *SpaceTimeGrid::makeFiveDimDWFRedBlackGrid(int Ls,const GridCartesian *FourDimGrid) | ||||
| { | ||||
|   int N4=FourDimGrid->_ndimension; | ||||
|   int nsimd = FourDimGrid->Nsimd(); | ||||
|   int cbd=1; | ||||
|   std::vector<int> latt5(1,Ls); | ||||
|   std::vector<int> simd5(1,nsimd); | ||||
|   std::vector<int>  mpi5(1,1); | ||||
|   std::vector<int>   cb5(1,0); | ||||
|      | ||||
|   for(int d=0;d<N4;d++){ | ||||
|     latt5.push_back(FourDimGrid->_fdimensions[d]); | ||||
|     simd5.push_back(1); | ||||
|      mpi5.push_back(FourDimGrid->_processors[d]); | ||||
|       cb5.push_back(1); | ||||
|     } | ||||
|   return new GridRedBlackCartesian(latt5,simd5,mpi5,cb5,cbd);  | ||||
|   } | ||||
|   GridCartesian *tmp         = makeFiveDimDWFGrid(Ls,FourDimGrid); | ||||
|   GridRedBlackCartesian *ret = new GridRedBlackCartesian(tmp,cb5,cbd);  | ||||
|   delete tmp; | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -86,7 +86,7 @@ namespace Grid { | ||||
|                                       or element<T>::is_number; | ||||
|   }; | ||||
|    | ||||
|   // Vector flatening utility class //////////////////////////////////////////// | ||||
|   // Vector flattening utility class //////////////////////////////////////////// | ||||
|   // Class to flatten a multidimensional std::vector | ||||
|   template <typename V> | ||||
|   class Flatten | ||||
|   | ||||
| @@ -42,6 +42,7 @@ JSONWriter::~JSONWriter(void) | ||||
|  | ||||
|   // write prettified JSON to file | ||||
|   std::ofstream os(fileName_); | ||||
|   //std::cout << "JSONWriter::~JSONWriter" << std::endl; | ||||
|   os << std::setw(2) << json::parse(ss_.str()) << std::endl; | ||||
| } | ||||
|  | ||||
| @@ -56,6 +57,7 @@ void JSONWriter::push(const string &s) | ||||
|  | ||||
| void JSONWriter::pop(void) | ||||
| { | ||||
|   //std::cout << "JSONWriter::pop" << std::endl; | ||||
|   delete_comma(); | ||||
|   ss_ << "},"; | ||||
| } | ||||
| @@ -67,20 +69,22 @@ void JSONWriter::delete_comma() | ||||
|   ss_.str(dlast); | ||||
| } | ||||
|  | ||||
|  | ||||
| // here we are hitting a g++ bug (Bug 56480) | ||||
| // compiles fine with clang | ||||
| // have to wrap in the Grid namespace | ||||
| // annoying, but necessary for TravisCI | ||||
| namespace Grid | ||||
| { | ||||
|   template<> | ||||
|   void JSONWriter::writeDefault(const std::string &s, | ||||
| 				const std::string &x) | ||||
|   void JSONWriter::writeDefault(const std::string &s,	const std::string &x) | ||||
|   { | ||||
|     //std::cout << "JSONWriter::writeDefault(string) : " << s <<  std::endl; | ||||
|     std::ostringstream os; | ||||
|     os << std::boolalpha << x; | ||||
|     if (s.size()) | ||||
|       ss_ << "\""<< s << "\" : \"" << x << "\" ," ;  | ||||
|       ss_ << "\""<< s << "\" : \"" << os.str() << "\" ," ; | ||||
|     else | ||||
|       ss_ << "\"" << x << "\" ," ; | ||||
|      ss_ << os.str() << " ," ; | ||||
|   } | ||||
| }// namespace Grid  | ||||
|  | ||||
| @@ -138,6 +142,7 @@ void JSONReader::pop(void) | ||||
|  | ||||
| bool JSONReader::nextElement(const std::string &s) | ||||
| { | ||||
|   // Work in progress | ||||
|   // JSON dictionaries do not support multiple names  | ||||
|   // Same name objects must be packed in vectors | ||||
|   ++it_; | ||||
|   | ||||
| @@ -58,10 +58,15 @@ namespace Grid | ||||
|     void writeDefault(const std::string &s, const std::complex<U> &x); | ||||
|     template <typename U> | ||||
|     void writeDefault(const std::string &s, const std::vector<U> &x); | ||||
|     template <typename U, typename P> | ||||
|     void writeDefault(const std::string &s, const std::pair<U,P> &x); | ||||
|  | ||||
|     template<std::size_t N> | ||||
|     void writeDefault(const std::string &s, const char(&x)[N]); | ||||
|  | ||||
|     void writeDefault(const std::string &s, const std::string &x); | ||||
|  | ||||
|  | ||||
|   private: | ||||
|     void delete_comma(); | ||||
|     std::string         fileName_; | ||||
| @@ -82,6 +87,8 @@ namespace Grid | ||||
|     void readDefault(const std::string &s, std::complex<U> &output); | ||||
|     template <typename U> | ||||
|     void readDefault(const std::string &s, std::vector<U> &output); | ||||
|     template <typename U, typename P> | ||||
|     void readDefault(const std::string &s, std::pair<U,P> &output); | ||||
|   private: | ||||
|     json                jobject_; // main object | ||||
|     json                jcur_;  // current json object | ||||
| @@ -106,7 +113,7 @@ namespace Grid | ||||
|   template <typename U> | ||||
|   void JSONWriter::writeDefault(const std::string &s, const U &x) | ||||
|   { | ||||
|     //std::cout << "JSONReader::writeDefault(U) : " << s <<  std::endl; | ||||
|     //std::cout << "JSONWriter::writeDefault(U) : " << s <<  " " << x <<std::endl; | ||||
|     std::ostringstream os; | ||||
|     os << std::boolalpha << x; | ||||
|     if (s.size()) | ||||
| @@ -118,7 +125,7 @@ namespace Grid | ||||
|   template <typename U> | ||||
|   void JSONWriter::writeDefault(const std::string &s, const std::complex<U> &x) | ||||
|   { | ||||
|     //std::cout << "JSONReader::writeDefault(complex) : " << s <<  std::endl; | ||||
|     //std::cout << "JSONWriter::writeDefault(complex) : " << s <<  " " << x <<  std::endl; | ||||
|     std::ostringstream os; | ||||
|     os << "["<< std::boolalpha << x.real() << ", " << x.imag() << "]"; | ||||
|     if (s.size()) | ||||
| @@ -127,10 +134,22 @@ namespace Grid | ||||
|      ss_ << os.str() << " ," ; | ||||
|   } | ||||
|  | ||||
|   template <typename U, typename P> | ||||
|   void JSONWriter::writeDefault(const std::string &s, const std::pair<U,P> &x) | ||||
|   { | ||||
|     //std::cout << "JSONWriter::writeDefault(pair) : " << s <<  " " << x <<  std::endl; | ||||
|     std::ostringstream os; | ||||
|     os << "["<< std::boolalpha << "\""<< x.first << "\" , \"" << x.second << "\" ]"; | ||||
|     if (s.size()) | ||||
|       ss_ << "\""<< s << "\" : " << os.str() << " ," ; | ||||
|     else | ||||
|      ss_ << os.str() << " ," ; | ||||
|   } | ||||
|  | ||||
|   template <typename U> | ||||
|   void JSONWriter::writeDefault(const std::string &s, const std::vector<U> &x) | ||||
|   { | ||||
|     //std::cout << "JSONReader::writeDefault(vec U) : " << s <<  std::endl; | ||||
|     //std::cout << "JSONWriter::writeDefault(vec U) : " << s <<  std::endl; | ||||
|  | ||||
|     if (s.size()) | ||||
|       ss_ << " \""<<s<<"\" : ["; | ||||
| @@ -146,12 +165,12 @@ namespace Grid | ||||
|  | ||||
|   template<std::size_t N> | ||||
|   void JSONWriter::writeDefault(const std::string &s, const char(&x)[N]){ | ||||
|     //std::cout << "JSONReader::writeDefault(char U) : " << s <<  std::endl; | ||||
|     //std::cout << "JSONWriter::writeDefault(char U) : " << s <<  "  " << x << std::endl; | ||||
|  | ||||
|     if (s.size()) | ||||
|     ss_ << "\""<< s << "\" : \"" << x << "\" ," ; | ||||
|       ss_ << "\""<< s << "\" : \"" << x << "\" ," ; | ||||
|     else | ||||
|     ss_ << "\"" << x << "\" ," ; | ||||
|       ss_ << "\"" << x << "\" ," ; | ||||
|   } | ||||
|  | ||||
|   // Reader template implementation //////////////////////////////////////////// | ||||
| @@ -173,11 +192,35 @@ namespace Grid | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Reader template implementation //////////////////////////////////////////// | ||||
|   template <typename U, typename P> | ||||
|   void JSONReader::readDefault(const std::string &s, std::pair<U,P> &output) | ||||
|   { | ||||
|     U first; | ||||
|     P second; | ||||
|     json j; | ||||
|     if (s.size()){ | ||||
|       //std::cout << "JSONReader::readDefault(pair) : " << s << "  |  "<< jcur_[s] << std::endl; | ||||
|       j = jcur_[s]; | ||||
|     } else { | ||||
|       j = jcur_; | ||||
|     } | ||||
|     json::iterator it = j.begin(); | ||||
|     jcur_ = *it; | ||||
|     read("", first); | ||||
|     it++; | ||||
|     jcur_ = *it; | ||||
|     read("", second); | ||||
|     output = std::pair<U,P>(first,second); | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
|   template <typename U> | ||||
|   void JSONReader::readDefault(const std::string &s, std::complex<U> &output) | ||||
|   { | ||||
|     U tmp1, tmp2; | ||||
|     //std::cout << "JSONReader::readDefault( complex U) : " << s << "  :  "<< jcur_ << std::endl; | ||||
|     //std::cout << "JSONReader::readDefault(complex U) : " << s << "  :  "<< jcur_ << std::endl; | ||||
|     json j = jcur_; | ||||
|     json::iterator it = j.begin(); | ||||
|     jcur_ = *it; | ||||
|   | ||||
| @@ -70,8 +70,8 @@ XmlReader::XmlReader(const char *xmlstring,string toplev) : fileName_("") | ||||
|   pugi::xml_parse_result result; | ||||
|   result = doc_.load_string(xmlstring); | ||||
|   if ( !result ) { | ||||
|     cerr << "XML error description: " << result.description() << "\n"; | ||||
|     cerr << "XML error offset     : " << result.offset        << "\n"; | ||||
|     cerr << "XML error description (from char *): " << result.description() << "\nXML\n"<< xmlstring << "\n"; | ||||
|     cerr << "XML error offset      (from char *) " << result.offset         << "\nXML\n"<< xmlstring <<"\n"; | ||||
|     abort(); | ||||
|   } | ||||
|   if ( toplev == std::string("") ) { | ||||
| @@ -87,8 +87,8 @@ XmlReader::XmlReader(const string &fileName,string toplev) : fileName_(fileName) | ||||
|   pugi::xml_parse_result result; | ||||
|   result = doc_.load_file(fileName_.c_str()); | ||||
|   if ( !result ) { | ||||
|     cerr << "XML error description: " << result.description() << "\n"; | ||||
|     cerr << "XML error offset     : " << result.offset        << "\n"; | ||||
|     cerr << "XML error description: " << result.description() <<" "<< fileName_ <<"\n"; | ||||
|     cerr << "XML error offset     : " << result.offset        <<" "<< fileName_ <<"\n"; | ||||
|     abort(); | ||||
|   } | ||||
|   if ( toplev == std::string("") ) { | ||||
|   | ||||
| @@ -82,11 +82,11 @@ namespace Optimization { | ||||
|       double tmp[2]={a,b}; | ||||
|       return vld1q_f64(tmp); | ||||
|     } | ||||
|     //Real double // N:tbc | ||||
|     //Real double | ||||
|     inline float64x2_t operator()(double a){ | ||||
|       return vdupq_n_f64(a); | ||||
|     } | ||||
|     //Integer // N:tbc | ||||
|     //Integer | ||||
|     inline uint32x4_t operator()(Integer a){ | ||||
|       return vdupq_n_u32(a); | ||||
|     } | ||||
| @@ -124,33 +124,32 @@ namespace Optimization { | ||||
|   // Nils: Vset untested; not used currently in Grid at all; | ||||
|   // git commit 4a8c4ccfba1d05159348d21a9698028ea847e77b | ||||
|   struct Vset{ | ||||
|     // Complex float // N:ok | ||||
|     // Complex float | ||||
|     inline float32x4_t operator()(Grid::ComplexF *a){ | ||||
|       float tmp[4]={a[1].imag(),a[1].real(),a[0].imag(),a[0].real()}; | ||||
|       return vld1q_f32(tmp); | ||||
|     } | ||||
|     // Complex double // N:ok | ||||
|     // Complex double | ||||
|     inline float64x2_t operator()(Grid::ComplexD *a){ | ||||
|       double tmp[2]={a[0].imag(),a[0].real()}; | ||||
|       return vld1q_f64(tmp); | ||||
|     } | ||||
|     // Real float // N:ok | ||||
|     // Real float | ||||
|     inline float32x4_t operator()(float *a){ | ||||
|       float tmp[4]={a[3],a[2],a[1],a[0]}; | ||||
|       return vld1q_f32(tmp); | ||||
|     } | ||||
|     // Real double // N:ok | ||||
|     // Real double | ||||
|     inline float64x2_t operator()(double *a){ | ||||
|       double tmp[2]={a[1],a[0]}; | ||||
|       return vld1q_f64(tmp); | ||||
|     } | ||||
|     // Integer // N:ok | ||||
|     // Integer | ||||
|     inline uint32x4_t operator()(Integer *a){ | ||||
|       return vld1q_dup_u32(a); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   // N:leaving as is | ||||
|   template <typename Out_type, typename In_type> | ||||
|   struct Reduce{ | ||||
|     //Need templated class to overload output type | ||||
| @@ -249,9 +248,9 @@ namespace Optimization { | ||||
|       return vfmaq_f32(r4, r0, a); //  ar*br-ai*bi ai*br+ar*bi ... | ||||
|  | ||||
|       // no fma, use mul and add | ||||
|       //float32x4_t r5; | ||||
|       //r5 = vmulq_f32(r0, a); | ||||
|       //return vaddq_f32(r4, r5); | ||||
|       // float32x4_t r5; | ||||
|       // r5 = vmulq_f32(r0, a); | ||||
|       // return vaddq_f32(r4, r5); | ||||
|     } | ||||
|     // Complex double | ||||
|     inline float64x2_t operator()(float64x2_t a, float64x2_t b){ | ||||
| @@ -272,9 +271,9 @@ namespace Optimization { | ||||
|       return vfmaq_f64(r4, r0, a); //  ar*br-ai*bi ai*br+ar*bi | ||||
|  | ||||
|       // no fma, use mul and add | ||||
|       //float64x2_t r5; | ||||
|       //r5 = vmulq_f64(r0, a); | ||||
|       //return vaddq_f64(r4, r5); | ||||
|       // float64x2_t r5; | ||||
|       // r5 = vmulq_f64(r0, a); | ||||
|       // return vaddq_f64(r4, r5); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| @@ -421,11 +420,6 @@ namespace Optimization { | ||||
|       } | ||||
|     } | ||||
|  | ||||
| // working, but no restriction on n | ||||
| //    template<int n> static inline float32x4_t tRotate(float32x4_t in){ return vextq_f32(in,in,n); }; | ||||
| //    template<int n> static inline float64x2_t tRotate(float64x2_t in){ return vextq_f64(in,in,n); }; | ||||
|  | ||||
| // restriction on n | ||||
|     template<int n> static inline float32x4_t tRotate(float32x4_t in){ return vextq_f32(in,in,n%4); }; | ||||
|     template<int n> static inline float64x2_t tRotate(float64x2_t in){ return vextq_f64(in,in,n%2); }; | ||||
|  | ||||
| @@ -441,7 +435,7 @@ namespace Optimization { | ||||
|       sb = vcvt_high_f32_f16(h); | ||||
|       // there is no direct conversion from lower float32x4_t to float64x2_t | ||||
|       // vextq_f16 not supported by clang 3.8 / 4.0 / arm clang | ||||
|       //float16x8_t h1 = vextq_f16(h, h, 4); // correct, but not supported by clang | ||||
|       // float16x8_t h1 = vextq_f16(h, h, 4); // correct, but not supported by clang | ||||
|       // workaround for clang | ||||
|       uint32x4_t h1u = reinterpret_cast<uint32x4_t>(h); | ||||
|       float16x8_t h1 = reinterpret_cast<float16x8_t>(vextq_u32(h1u, h1u, 2)); | ||||
| @@ -547,7 +541,7 @@ namespace Optimization { | ||||
|  | ||||
|  | ||||
|   //Complex double Reduce | ||||
|   template<> // N:by Boyle | ||||
|   template<> | ||||
|   inline Grid::ComplexD Reduce<Grid::ComplexD, float64x2_t>::operator()(float64x2_t in){ | ||||
|     u128d conv; conv.v = in; | ||||
|     return Grid::ComplexD(conv.f[0],conv.f[1]); | ||||
| @@ -562,9 +556,7 @@ namespace Optimization { | ||||
|   //Integer Reduce | ||||
|   template<> | ||||
|   inline Integer Reduce<Integer, uint32x4_t>::operator()(uint32x4_t in){ | ||||
|     // FIXME unimplemented | ||||
|     printf("Reduce : Missing integer implementation -> FIX\n"); | ||||
|     assert(0); | ||||
|     return vaddvq_u32(in); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -604,3 +596,4 @@ namespace Optimization { | ||||
|   typedef Optimization::TimesI      TimesISIMD; | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -376,7 +376,18 @@ class Grid_simd { | ||||
|       Optimization::Exchange::Exchange0(out1.v,out2.v,in1.v,in2.v); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   friend inline void exchange0(Grid_simd &out1,Grid_simd &out2,Grid_simd in1,Grid_simd in2){     | ||||
|     Optimization::Exchange::Exchange0(out1.v,out2.v,in1.v,in2.v); | ||||
|   } | ||||
|   friend inline void exchange1(Grid_simd &out1,Grid_simd &out2,Grid_simd in1,Grid_simd in2){     | ||||
|     Optimization::Exchange::Exchange1(out1.v,out2.v,in1.v,in2.v); | ||||
|   } | ||||
|   friend inline void exchange2(Grid_simd &out1,Grid_simd &out2,Grid_simd in1,Grid_simd in2){     | ||||
|     Optimization::Exchange::Exchange2(out1.v,out2.v,in1.v,in2.v); | ||||
|   } | ||||
|   friend inline void exchange3(Grid_simd &out1,Grid_simd &out2,Grid_simd in1,Grid_simd in2){     | ||||
|     Optimization::Exchange::Exchange3(out1.v,out2.v,in1.v,in2.v); | ||||
|   } | ||||
|   //////////////////////////////////////////////////////////////////// | ||||
|   // General permute; assumes vector length is same across | ||||
|   // all subtypes; may not be a good assumption, but could | ||||
|   | ||||
| @@ -400,11 +400,13 @@ class CartesianStencil { // Stencil runs along coordinate axes only; NO diagonal | ||||
|       if ( sshift[0] == sshift[1] ) { | ||||
| 	if (splice_dim) { | ||||
| 	  splicetime-=usecond(); | ||||
| 	  same_node = same_node && GatherSimd(source,dimension,shift,0x3,compress,face_idx); | ||||
| 	  auto tmp  = GatherSimd(source,dimension,shift,0x3,compress,face_idx); | ||||
| 	  same_node = same_node && tmp; | ||||
| 	  splicetime+=usecond(); | ||||
| 	} else {  | ||||
| 	  nosplicetime-=usecond(); | ||||
| 	  same_node = same_node && Gather(source,dimension,shift,0x3,compress,face_idx); | ||||
| 	  auto tmp  = Gather(source,dimension,shift,0x3,compress,face_idx); | ||||
| 	  same_node = same_node && tmp; | ||||
| 	  nosplicetime+=usecond(); | ||||
| 	} | ||||
|       } else { | ||||
| @@ -412,13 +414,15 @@ class CartesianStencil { // Stencil runs along coordinate axes only; NO diagonal | ||||
| 	  splicetime-=usecond(); | ||||
| 	  // if checkerboard is unfavourable take two passes | ||||
| 	  // both with block stride loop iteration | ||||
| 	  same_node = same_node && GatherSimd(source,dimension,shift,0x1,compress,face_idx); | ||||
| 	  same_node = same_node && GatherSimd(source,dimension,shift,0x2,compress,face_idx); | ||||
| 	  auto tmp1 =  GatherSimd(source,dimension,shift,0x1,compress,face_idx); | ||||
| 	  auto tmp2 =  GatherSimd(source,dimension,shift,0x2,compress,face_idx); | ||||
| 	  same_node = same_node && tmp1 && tmp2; | ||||
| 	  splicetime+=usecond(); | ||||
| 	} else { | ||||
| 	  nosplicetime-=usecond(); | ||||
| 	  same_node = same_node && Gather(source,dimension,shift,0x1,compress,face_idx); | ||||
| 	  same_node = same_node && Gather(source,dimension,shift,0x2,compress,face_idx); | ||||
| 	  auto tmp1 = Gather(source,dimension,shift,0x1,compress,face_idx); | ||||
| 	  auto tmp2 = Gather(source,dimension,shift,0x2,compress,face_idx); | ||||
| 	  same_node = same_node && tmp1 && tmp2; | ||||
| 	  nosplicetime+=usecond(); | ||||
| 	} | ||||
|       } | ||||
|   | ||||
| @@ -175,7 +175,7 @@ class TensorIndexRecursion { | ||||
|       } | ||||
|     } | ||||
|   template<class vtype,int N> inline static  | ||||
|     void pokeIndex(iVector<vtype,N> &ret, const iVector<decltype(TensorIndexRecursion<Level-1>::peekIndex(ret._internal[0],0)),N> &arg, int i,int j) | ||||
|     void pokeIndex(iVector<vtype,N> &ret, const iVector<decltype(TensorIndexRecursion<Level-1>::peekIndex(ret._internal[0],0,0)),N> &arg, int i,int j) | ||||
|     { | ||||
|       for(int ii=0;ii<N;ii++){ | ||||
| 	TensorIndexRecursion<Level-1>::pokeIndex(ret._internal[ii],arg._internal[ii],i,j); | ||||
| @@ -191,7 +191,7 @@ class TensorIndexRecursion { | ||||
|       }} | ||||
|     } | ||||
|   template<class vtype,int N> inline static  | ||||
|     void pokeIndex(iMatrix<vtype,N> &ret, const iMatrix<decltype(TensorIndexRecursion<Level-1>::peekIndex(ret._internal[0][0],0)),N> &arg, int i,int j) | ||||
|     void pokeIndex(iMatrix<vtype,N> &ret, const iMatrix<decltype(TensorIndexRecursion<Level-1>::peekIndex(ret._internal[0][0],0,0)),N> &arg, int i,int j) | ||||
|     { | ||||
|       for(int ii=0;ii<N;ii++){ | ||||
|       for(int jj=0;jj<N;jj++){ | ||||
|   | ||||
| @@ -51,7 +51,9 @@ Author: paboyle <paboyle@ph.ed.ac.uk> | ||||
| #define PARALLEL_CRITICAL | ||||
| #endif | ||||
|  | ||||
| #define parallel_region    PARALLEL_REGION | ||||
| #define parallel_for       PARALLEL_FOR_LOOP for | ||||
| #define parallel_for_internal PARALLEL_FOR_LOOP_INTERN for | ||||
| #define parallel_for_nest2 PARALLEL_NESTED_LOOP2 for | ||||
|  | ||||
| namespace Grid { | ||||
|   | ||||
| @@ -208,7 +208,7 @@ static int Grid_is_initialised = 0; | ||||
|  | ||||
| void Grid_init(int *argc,char ***argv) | ||||
| { | ||||
|   GridLogger::StopWatch.Start(); | ||||
|   GridLogger::GlobalStopWatch.Start(); | ||||
|  | ||||
|   std::string arg; | ||||
|  | ||||
| @@ -243,6 +243,12 @@ void Grid_init(int *argc,char ***argv) | ||||
|     fname<<CartesianCommunicator::RankWorld(); | ||||
|     fp=freopen(fname.str().c_str(),"w",stdout); | ||||
|     assert(fp!=(FILE *)NULL); | ||||
|  | ||||
|     std::ostringstream ename; | ||||
|     ename<<"Grid.stderr."; | ||||
|     ename<<CartesianCommunicator::RankWorld(); | ||||
|     fp=freopen(ename.str().c_str(),"w",stderr); | ||||
|     assert(fp!=(FILE *)NULL); | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////// | ||||
|   | ||||
| @@ -7,7 +7,7 @@ namespace Grid{ | ||||
|   class Lexicographic { | ||||
|   public: | ||||
|  | ||||
|     static inline void CoorFromIndex (std::vector<int>& coor,int index,std::vector<int> &dims){ | ||||
|     static inline void CoorFromIndex (std::vector<int>& coor,int index,const std::vector<int> &dims){ | ||||
|       int nd= dims.size(); | ||||
|       coor.resize(nd); | ||||
|       for(int d=0;d<nd;d++){ | ||||
| @@ -16,7 +16,7 @@ namespace Grid{ | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     static inline void IndexFromCoor (std::vector<int>& coor,int &index,std::vector<int> &dims){ | ||||
|     static inline void IndexFromCoor (const std::vector<int>& coor,int &index,const std::vector<int> &dims){ | ||||
|       int nd=dims.size(); | ||||
|       int stride=1; | ||||
|       index=0; | ||||
| @@ -26,6 +26,25 @@ namespace Grid{ | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     static inline void IndexFromCoorReversed (const std::vector<int>& coor,int &index,const std::vector<int> &dims){ | ||||
|       int nd=dims.size(); | ||||
|       int stride=1; | ||||
|       index=0; | ||||
|       for(int d=nd-1;d>=0;d--){ | ||||
| 	index = index+stride*coor[d]; | ||||
| 	stride=stride*dims[d]; | ||||
|       } | ||||
|     } | ||||
|     static inline void CoorFromIndexReversed (std::vector<int>& coor,int index,const std::vector<int> &dims){ | ||||
|       int nd= dims.size(); | ||||
|       coor.resize(nd); | ||||
|       for(int d=nd-1;d>=0;d--){ | ||||
| 	coor[d] = index % dims[d]; | ||||
| 	index   = index / dims[d]; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|   }; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -29,7 +29,6 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
|     /*  END LEGAL */ | ||||
| #include <Grid/Grid.h> | ||||
|  | ||||
|  | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| @@ -151,6 +150,11 @@ int main(int argc,char **argv) | ||||
|   ioTest<TextWriter, TextReader>("iotest.dat", obj, "text   (object)           "); | ||||
|   ioTest<TextWriter, TextReader>("iotest.dat", vec, "text   (vector of objects)"); | ||||
|   ioTest<TextWriter, TextReader>("iotest.dat", pair, "text   (pair of objects)"); | ||||
|   //// text | ||||
|   ioTest<JSONWriter, JSONReader>("iotest.json", obj,  "JSON   (object)           "); | ||||
|   ioTest<JSONWriter, JSONReader>("iotest.json", vec,  "JSON   (vector of objects)"); | ||||
|   ioTest<JSONWriter, JSONReader>("iotest.json", pair, "JSON   (pair of objects)"); | ||||
|  | ||||
|   //// HDF5 | ||||
| #undef HAVE_HDF5 | ||||
| #ifdef HAVE_HDF5 | ||||
| @@ -201,8 +205,10 @@ int main(int argc,char **argv) | ||||
|     JSONWriter JW("bother.json"); | ||||
|  | ||||
|     // test basic type writing | ||||
|     myenum a = myenum::red; | ||||
|     push(JW,"BasicTypes"); | ||||
|     write(JW,std::string("i16"),i16); | ||||
|     write(JW,"myenum",a); | ||||
|     write(JW,"u16",u16); | ||||
|     write(JW,"i32",i32); | ||||
|     write(JW,"u32",u32); | ||||
| @@ -213,13 +219,14 @@ int main(int argc,char **argv) | ||||
|     write(JW,"b",b); | ||||
|     pop(JW); | ||||
|  | ||||
|  | ||||
|     // test serializable class writing | ||||
|     myclass obj(1234); // non-trivial constructor | ||||
|     std::cout << obj << std::endl; | ||||
|     std::cout << "-- serialisable class writing to 'bother.json'..." << std::endl; | ||||
|     write(JW,"obj",obj); | ||||
|     JW.write("obj2", obj); | ||||
|  | ||||
|     std::cout << obj << std::endl; | ||||
|  | ||||
|     std::vector<myclass> vec; | ||||
|     vec.push_back(myclass(1234)); | ||||
| @@ -229,6 +236,7 @@ int main(int argc,char **argv) | ||||
|  | ||||
|   } | ||||
|  | ||||
|  | ||||
|   { | ||||
|     JSONReader RD("bother.json"); | ||||
|     myclass jcopy1; | ||||
| @@ -239,6 +247,7 @@ int main(int argc,char **argv) | ||||
|     std::cout << jcopy1 << std::endl << jveccopy1 << std::endl; | ||||
|   } | ||||
|   | ||||
|  | ||||
| /* | ||||
|   // This is still work in progress | ||||
|   { | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| SUBDIRS = . core forces hmc solver debug smearing IO | ||||
| SUBDIRS = . core forces hmc solver debug smearing IO lanczos | ||||
|  | ||||
| if BUILD_CHROMA_REGRESSION | ||||
|   SUBDIRS+= qdpxx | ||||
|   | ||||
| @@ -80,31 +80,47 @@ int main (int argc, char ** argv) | ||||
|  | ||||
|  | ||||
|   LatticeFermionD    src_o(FrbGrid); | ||||
|   LatticeFermionD result_o(FrbGrid); | ||||
|   LatticeFermionD result_o_2(FrbGrid); | ||||
|   LatticeFermionD result_cg(FrbGrid); | ||||
|   pickCheckerboard(Odd,src_o,src); | ||||
|   result_o.checkerboard = Odd; | ||||
|   result_o = zero; | ||||
|   result_o_2.checkerboard = Odd; | ||||
|   result_o_2 = zero; | ||||
|   result_cg.checkerboard = Odd; | ||||
|   result_cg = zero; | ||||
|   LatticeFermionD result_mcg(result_cg); | ||||
|   LatticeFermionD result_rlcg(result_cg); | ||||
|  | ||||
|   SchurDiagMooeeOperator<DomainWallFermionD,LatticeFermionD> HermOpEO(Ddwf); | ||||
|   SchurDiagMooeeOperator<DomainWallFermionFH,LatticeFermionF> HermOpEO_f(Ddwf_f); | ||||
|  | ||||
|   //#define DO_MIXED_CG | ||||
| #define DO_RLUP_CG | ||||
|  | ||||
| #ifdef DO_MIXED_CG | ||||
|   std::cout << "Starting mixed CG" << std::endl; | ||||
|   MixedPrecisionConjugateGradient<LatticeFermionD,LatticeFermionF> mCG(1.0e-8, 10000, 50, FrbGrid_f, HermOpEO_f, HermOpEO); | ||||
|   mCG.InnerTolerance = 3.0e-5; | ||||
|   mCG(src_o,result_o); | ||||
|   mCG(src_o,result_mcg); | ||||
| #endif | ||||
|  | ||||
| #ifdef DO_RLUP_CG | ||||
|   std::cout << "Starting reliable update CG" << std::endl; | ||||
|   ConjugateGradientReliableUpdate<LatticeFermionD,LatticeFermionF> rlCG(1.e-8, 10000, 0.1, FrbGrid_f, HermOpEO_f, HermOpEO); | ||||
|   rlCG(src_o,result_rlcg); | ||||
| #endif | ||||
|    | ||||
|   std::cout << "Starting regular CG" << std::endl; | ||||
|   ConjugateGradient<LatticeFermionD> CG(1.0e-8,10000); | ||||
|   CG(HermOpEO,src_o,result_o_2); | ||||
|   CG(HermOpEO,src_o,result_cg); | ||||
|  | ||||
|   LatticeFermionD diff_o(FrbGrid); | ||||
|   RealD diff = axpy_norm(diff_o, -1.0, result_o, result_o_2); | ||||
|  | ||||
|   std::cout << "Diff between mixed and regular CG: " << diff << std::endl; | ||||
| #ifdef DO_MIXED_CG | ||||
|   LatticeFermionD diff_mcg(FrbGrid); | ||||
|   RealD vdiff_mcg = axpy_norm(diff_mcg, -1.0, result_cg, result_mcg); | ||||
|   std::cout << "Diff between mixed and regular CG: " << vdiff_mcg << std::endl; | ||||
| #endif | ||||
|  | ||||
| #ifdef DO_RLUP_CG | ||||
|   LatticeFermionD diff_rlcg(FrbGrid); | ||||
|   RealD vdiff_rlcg = axpy_norm(diff_rlcg, -1.0, result_cg, result_rlcg); | ||||
|   std::cout << "Diff between reliable update and regular CG: " << vdiff_rlcg << std::endl; | ||||
| #endif | ||||
|    | ||||
|   Grid_finalize(); | ||||
| } | ||||
|   | ||||
| @@ -48,7 +48,7 @@ int main(int argc, char ** argv) { | ||||
|   double volume = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; | ||||
|  | ||||
|   GridCartesian Fine(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian rbFine(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian rbFine(&Fine); | ||||
|   GridParallelRNG       fRNG(&Fine); | ||||
|  | ||||
|   //  fRNG.SeedFixedIntegers(std::vector<int>({45,12,81,9}); | ||||
|   | ||||
| @@ -47,7 +47,7 @@ int main (int argc, char ** argv) | ||||
|   mask[0]=0; | ||||
|  | ||||
|   GridCartesian         Fine  (latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian RBFine(latt_size,simd_layout,mpi_layout,mask,1); | ||||
|   GridRedBlackCartesian RBFine(&Fine,mask,1); | ||||
|  | ||||
|   GridParallelRNG      FineRNG(&Fine);  FineRNG.SeedFixedIntegers(std::vector<int>({45,12,81,9})); | ||||
|  | ||||
|   | ||||
| @@ -47,7 +47,7 @@ int main (int argc, char ** argv) | ||||
|   mask[0]=0; | ||||
|  | ||||
|   GridCartesian         Fine  (latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian RBFine(latt_size,simd_layout,mpi_layout,mask,1); | ||||
|   GridRedBlackCartesian RBFine(&Fine,mask,1); | ||||
|  | ||||
|   GridParallelRNG      FineRNG(&Fine);  FineRNG.SeedFixedIntegers(std::vector<int>({45,12,81,9})); | ||||
|  | ||||
|   | ||||
							
								
								
									
										239
									
								
								tests/core/Test_dwf_eofa_even_odd.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								tests/core/Test_dwf_eofa_even_odd.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,239 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/core/Test_dwf_eofa_even_odd.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| template<class d> | ||||
| struct scal { | ||||
|     d internal; | ||||
| }; | ||||
|  | ||||
| Gamma::Algebra Gmu [] = { | ||||
|     Gamma::Algebra::GammaX, | ||||
|     Gamma::Algebra::GammaY, | ||||
|     Gamma::Algebra::GammaZ, | ||||
|     Gamma::Algebra::GammaT | ||||
| }; | ||||
|  | ||||
| int main (int argc, char ** argv) | ||||
| { | ||||
|     Grid_init(&argc, &argv); | ||||
|  | ||||
|     int threads = GridThread::GetThreads(); | ||||
|     std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||
|  | ||||
|     const int Ls = 8; | ||||
|     // GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|     GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|     GridCartesian*         FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|     GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|     GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|     std::vector<int> seeds4({1,2,3,4}); | ||||
|     std::vector<int> seeds5({5,6,7,8}); | ||||
|  | ||||
|     GridParallelRNG RNG4(UGrid); RNG4.SeedFixedIntegers(seeds4); | ||||
|     GridParallelRNG RNG5(FGrid); RNG5.SeedFixedIntegers(seeds5); | ||||
|  | ||||
|     LatticeFermion    src   (FGrid); random(RNG5, src); | ||||
|     LatticeFermion    phi   (FGrid); random(RNG5, phi); | ||||
|     LatticeFermion    chi   (FGrid); random(RNG5, chi); | ||||
|     LatticeFermion    result(FGrid); result = zero; | ||||
|     LatticeFermion    ref   (FGrid); ref = zero; | ||||
|     LatticeFermion    tmp   (FGrid); tmp = zero; | ||||
|     LatticeFermion    err   (FGrid); err = zero; | ||||
|     LatticeGaugeField Umu   (UGrid); SU3::HotConfiguration(RNG4, Umu); | ||||
|     std::vector<LatticeColourMatrix> U(4,UGrid); | ||||
|  | ||||
|     // Only one non-zero (y) | ||||
|     Umu = zero; | ||||
|     for(int nn=0; nn<Nd; nn++){ | ||||
|         random(RNG4, U[nn]); | ||||
|         if(nn>0){ U[nn] = zero; } | ||||
|         PokeIndex<LorentzIndex>(Umu, U[nn], nn); | ||||
|     } | ||||
|  | ||||
|     RealD mq1   = 0.1; | ||||
|     RealD mq2   = 0.5; | ||||
|     RealD mq3   = 1.0; | ||||
|     RealD shift = 0.1234; | ||||
|     RealD M5    = 1.8; | ||||
|     int   pm    = 1; | ||||
|     DomainWallEOFAFermionR Ddwf(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mq1, mq2, mq3, shift, pm, M5); | ||||
|  | ||||
|     LatticeFermion src_e (FrbGrid); | ||||
|     LatticeFermion src_o (FrbGrid); | ||||
|     LatticeFermion r_e   (FrbGrid); | ||||
|     LatticeFermion r_o   (FrbGrid); | ||||
|     LatticeFermion r_eo  (FGrid); | ||||
|     LatticeFermion r_eeoo(FGrid); | ||||
|  | ||||
|     std::cout << GridLogMessage << "==========================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Testing that Meo + Moe + Moo + Mee = Munprec " << std::endl; | ||||
|     std::cout << GridLogMessage << "==========================================================" << std::endl; | ||||
|  | ||||
|     pickCheckerboard(Even, src_e, src); | ||||
|     pickCheckerboard(Odd,  src_o, src); | ||||
|  | ||||
|     Ddwf.Meooe(src_e, r_o); std::cout << GridLogMessage << "Applied Meo" << std::endl; | ||||
|     Ddwf.Meooe(src_o, r_e); std::cout << GridLogMessage << "Applied Moe" << std::endl; | ||||
|     setCheckerboard(r_eo, r_o); | ||||
|     setCheckerboard(r_eo, r_e); | ||||
|  | ||||
|     Ddwf.Mooee(src_e, r_e); std::cout << GridLogMessage << "Applied Mee" << std::endl; | ||||
|     Ddwf.Mooee(src_o, r_o); std::cout << GridLogMessage << "Applied Moo" << std::endl; | ||||
|     setCheckerboard(r_eeoo, r_e); | ||||
|     setCheckerboard(r_eeoo, r_o); | ||||
|  | ||||
|     r_eo = r_eo + r_eeoo; | ||||
|     Ddwf.M(src, ref); | ||||
|  | ||||
|     // std::cout << GridLogMessage << r_eo << std::endl; | ||||
|     // std::cout << GridLogMessage << ref  << std::endl; | ||||
|  | ||||
|     err = ref - r_eo; | ||||
|     std::cout << GridLogMessage << "EO norm diff   " << norm2(err) << " " << norm2(ref) << " " << norm2(r_eo) << std::endl; | ||||
|  | ||||
|     LatticeComplex cerr(FGrid); | ||||
|     cerr = localInnerProduct(err,err); | ||||
|     // std::cout << GridLogMessage << cerr << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test Ddagger is the dagger of D by requiring                " << std::endl; | ||||
|     std::cout << GridLogMessage << "=  < phi | Deo | chi > * = < chi | Deo^dag| phi>  " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     LatticeFermion chi_e (FrbGrid); | ||||
|     LatticeFermion chi_o (FrbGrid); | ||||
|  | ||||
|     LatticeFermion dchi_e(FrbGrid); | ||||
|     LatticeFermion dchi_o(FrbGrid); | ||||
|  | ||||
|     LatticeFermion phi_e (FrbGrid); | ||||
|     LatticeFermion phi_o (FrbGrid); | ||||
|  | ||||
|     LatticeFermion dphi_e(FrbGrid); | ||||
|     LatticeFermion dphi_o(FrbGrid); | ||||
|  | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|     pickCheckerboard(Even, phi_e, phi); | ||||
|     pickCheckerboard(Odd , phi_o, phi); | ||||
|  | ||||
|     Ddwf.Meooe   (chi_e, dchi_o); | ||||
|     Ddwf.Meooe   (chi_o, dchi_e); | ||||
|     Ddwf.MeooeDag(phi_e, dphi_o); | ||||
|     Ddwf.MeooeDag(phi_o, dphi_e); | ||||
|  | ||||
|     ComplexD pDce = innerProduct(phi_e, dchi_e); | ||||
|     ComplexD pDco = innerProduct(phi_o, dchi_o); | ||||
|     ComplexD cDpe = innerProduct(chi_e, dphi_e); | ||||
|     ComplexD cDpo = innerProduct(chi_o, dphi_o); | ||||
|  | ||||
|     std::cout << GridLogMessage << "e " << pDce << " " << cDpe << std::endl; | ||||
|     std::cout << GridLogMessage << "o " << pDco << " " << cDpo << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "pDce - conj(cDpo) " << pDce-conj(cDpo) << std::endl; | ||||
|     std::cout << GridLogMessage << "pDco - conj(cDpe) " << pDco-conj(cDpe) << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test MeeInv Mee = 1                                         " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|  | ||||
|     Ddwf.Mooee   (chi_e, src_e); | ||||
|     Ddwf.MooeeInv(src_e, phi_e); | ||||
|  | ||||
|     Ddwf.Mooee   (chi_o, src_o); | ||||
|     Ddwf.MooeeInv(src_o, phi_o); | ||||
|  | ||||
|     setCheckerboard(phi, phi_e); | ||||
|     setCheckerboard(phi, phi_o); | ||||
|  | ||||
|     err = phi - chi; | ||||
|     std::cout << GridLogMessage << "norm diff   " << norm2(err) << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test MeeInvDag MeeDag = 1                                   " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|  | ||||
|     Ddwf.MooeeDag   (chi_e, src_e); | ||||
|     Ddwf.MooeeInvDag(src_e, phi_e); | ||||
|  | ||||
|     Ddwf.MooeeDag   (chi_o, src_o); | ||||
|     Ddwf.MooeeInvDag(src_o, phi_o); | ||||
|  | ||||
|     setCheckerboard(phi, phi_e); | ||||
|     setCheckerboard(phi, phi_o); | ||||
|  | ||||
|     err = phi - chi; | ||||
|     std::cout << GridLogMessage << "norm diff   " << norm2(err) << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test MpcDagMpc is Hermitian              " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     random(RNG5, phi); | ||||
|     random(RNG5, chi); | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|     pickCheckerboard(Even, phi_e, phi); | ||||
|     pickCheckerboard(Odd , phi_o, phi); | ||||
|     RealD t1,t2; | ||||
|  | ||||
|     SchurDiagMooeeOperator<DomainWallEOFAFermionR,LatticeFermion> HermOpEO(Ddwf); | ||||
|     HermOpEO.MpcDagMpc(chi_e, dchi_e, t1, t2); | ||||
|     HermOpEO.MpcDagMpc(chi_o, dchi_o, t1, t2); | ||||
|  | ||||
|     HermOpEO.MpcDagMpc(phi_e, dphi_e, t1, t2); | ||||
|     HermOpEO.MpcDagMpc(phi_o, dphi_o, t1, t2); | ||||
|  | ||||
|     pDce = innerProduct(phi_e, dchi_e); | ||||
|     pDco = innerProduct(phi_o, dchi_o); | ||||
|     cDpe = innerProduct(chi_e, dphi_e); | ||||
|     cDpo = innerProduct(chi_o, dphi_o); | ||||
|  | ||||
|     std::cout << GridLogMessage << "e " << pDce << " " << cDpe << std::endl; | ||||
|     std::cout << GridLogMessage << "o " << pDco << " " << cDpo << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "pDce - conj(cDpo) " << pDco-conj(cDpo) << std::endl; | ||||
|     std::cout << GridLogMessage << "pDco - conj(cDpe) " << pDce-conj(cDpe) << std::endl; | ||||
|  | ||||
|     Grid_finalize(); | ||||
| } | ||||
| @@ -47,7 +47,7 @@ int main (int argc, char ** argv) | ||||
|     vol = vol * latt_size[d]; | ||||
|   } | ||||
|   GridCartesian         GRID(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian RBGRID(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian RBGRID(&GRID); | ||||
|  | ||||
|   LatticeComplexD     one(&GRID); | ||||
|   LatticeComplexD      zz(&GRID); | ||||
|   | ||||
| @@ -33,22 +33,68 @@ using namespace std; | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| typedef typename GparityDomainWallFermionR::FermionField FermionField; | ||||
| //typedef GparityDomainWallFermionD GparityDiracOp; | ||||
| //typedef DomainWallFermionD StandardDiracOp; | ||||
| //#define DOP_PARAMS | ||||
|  | ||||
| typedef GparityMobiusFermionD GparityDiracOp; | ||||
| typedef MobiusFermionD StandardDiracOp; | ||||
| #define DOP_PARAMS ,1.5, 0.5 | ||||
|  | ||||
|  | ||||
| typedef typename GparityDiracOp::FermionField GparityFermionField; | ||||
| typedef typename GparityDiracOp::GaugeField GparityGaugeField; | ||||
| typedef typename GparityFermionField::vector_type vComplexType; | ||||
|  | ||||
| typedef typename StandardDiracOp::FermionField StandardFermionField; | ||||
| typedef typename StandardDiracOp::GaugeField StandardGaugeField; | ||||
|  | ||||
| enum{ same_vComplex = std::is_same<vComplexType, typename StandardFermionField::vector_type>::value }; | ||||
| static_assert(same_vComplex == 1, "Dirac Operators must have same underlying SIMD complex type"); | ||||
|  | ||||
| int main (int argc, char ** argv) | ||||
| { | ||||
|   const int nu = 3; | ||||
|   int nu = 0; | ||||
|  | ||||
|   Grid_init(&argc,&argv); | ||||
|  | ||||
|   for(int i=1;i<argc;i++){ | ||||
|     if(std::string(argv[i]) == "--Gparity-dir"){ | ||||
|       std::stringstream ss; ss << argv[i+1]; ss >> nu; | ||||
|       std::cout << GridLogMessage << "Set Gparity direction to " << nu << std::endl; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "* Kernel options --dslash-generic, --dslash-unroll, --dslash-asm" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "* Testing Gparity Dirac operator                  "<<std::endl; | ||||
|   std::cout << GridLogMessage<< "* Vectorising space-time by "<<vComplexType::Nsimd()<<std::endl; | ||||
| #ifdef GRID_OMP | ||||
|   if ( WilsonKernelsStatic::Comms == WilsonKernelsStatic::CommsAndCompute ) std::cout << GridLogMessage<< "* Using Overlapped Comms/Compute" <<std::endl; | ||||
|   if ( WilsonKernelsStatic::Comms == WilsonKernelsStatic::CommsThenCompute) std::cout << GridLogMessage<< "* Using sequential comms compute" <<std::endl; | ||||
| #endif | ||||
|   if ( WilsonKernelsStatic::Opt == WilsonKernelsStatic::OptGeneric   ) std::cout << GridLogMessage<< "* Using GENERIC Nc WilsonKernels" <<std::endl; | ||||
|   if ( WilsonKernelsStatic::Opt == WilsonKernelsStatic::OptHandUnroll) std::cout << GridLogMessage<< "* Using UNROLLED Nc=3       WilsonKernels" <<std::endl; | ||||
|   if ( WilsonKernelsStatic::Opt == WilsonKernelsStatic::OptInlineAsm ) std::cout << GridLogMessage<< "* Using Asm Nc=3   WilsonKernels" <<std::endl; | ||||
|   std::cout << GridLogMessage<< "*****************************************************************" <<std::endl; | ||||
|  | ||||
|   const int Ls=4; | ||||
|   const int L =4; | ||||
|   std::vector<int> latt_2f(Nd,L); | ||||
|   std::vector<int> latt_1f(Nd,L); latt_1f[nu] = 2*L; | ||||
|   //const int L =4; | ||||
|   //std::vector<int> latt_2f(Nd,L); | ||||
|  | ||||
|   std::vector<int> latt_2f = GridDefaultLatt(); | ||||
|   std::vector<int> latt_1f(latt_2f); latt_1f[nu] = 2*latt_2f[nu]; | ||||
|   int L = latt_2f[nu]; | ||||
|  | ||||
|  | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplexType::Nsimd()); | ||||
|  | ||||
|   std::cout << GridLogMessage << "SIMD layout: "; | ||||
|   for(int i=0;i<simd_layout.size();i++) std::cout << simd_layout[i] << " "; | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); //node layout | ||||
|  | ||||
|   GridCartesian         * UGrid_1f   = SpaceTimeGrid::makeFourDimGrid(latt_1f, simd_layout, mpi_layout); | ||||
| @@ -67,13 +113,13 @@ int main (int argc, char ** argv) | ||||
|   GridParallelRNG          RNG5_2f(FGrid_2f);  RNG5_2f.SeedFixedIntegers(seeds5); | ||||
|   GridParallelRNG          RNG4_2f(UGrid_2f);  RNG4_2f.SeedFixedIntegers(seeds4); | ||||
|  | ||||
|   LatticeGaugeField Umu_2f(UGrid_2f); | ||||
|   GparityGaugeField Umu_2f(UGrid_2f); | ||||
|   SU3::HotConfiguration(RNG4_2f,Umu_2f); | ||||
|  | ||||
|   LatticeFermion    src   (FGrid_2f);  | ||||
|   LatticeFermion    tmpsrc(FGrid_2f);  | ||||
|   FermionField      src_2f(FGrid_2f);  | ||||
|   LatticeFermion    src_1f(FGrid_1f);  | ||||
|   StandardFermionField    src   (FGrid_2f);  | ||||
|   StandardFermionField    tmpsrc(FGrid_2f);  | ||||
|   GparityFermionField      src_2f(FGrid_2f);  | ||||
|   StandardFermionField    src_1f(FGrid_1f);  | ||||
|  | ||||
|   // Replicate fermion source | ||||
|   random(RNG5_2f,src); | ||||
| @@ -81,8 +127,8 @@ int main (int argc, char ** argv) | ||||
|   tmpsrc=src*2.0; | ||||
|   PokeIndex<0>(src_2f,tmpsrc,1); | ||||
|  | ||||
|   LatticeFermion result_1f(FGrid_1f); result_1f=zero; | ||||
|   LatticeGaugeField Umu_1f(UGrid_1f);  | ||||
|   StandardFermionField result_1f(FGrid_1f); result_1f=zero; | ||||
|   StandardGaugeField Umu_1f(UGrid_1f);  | ||||
|   Replicate(Umu_2f,Umu_1f); | ||||
|  | ||||
|   //Coordinate grid for reference | ||||
| @@ -92,7 +138,7 @@ int main (int argc, char ** argv) | ||||
|   //Copy-conjugate the gauge field | ||||
|   //First C-shift the lattice by Lx/2 | ||||
|   { | ||||
|     LatticeGaugeField Umu_shift = conjugate( Cshift(Umu_1f,nu,L) ); | ||||
|     StandardGaugeField Umu_shift = conjugate( Cshift(Umu_1f,nu,L) ); | ||||
|     Umu_1f = where( xcoor_1f >= Integer(L), Umu_shift, Umu_1f ); | ||||
|  | ||||
|     // hack test to check the same | ||||
| @@ -101,7 +147,7 @@ int main (int argc, char ** argv) | ||||
|     cout << GridLogMessage << "Umu diff " << norm2(Umu_shift)<<std::endl; | ||||
|  | ||||
|     //Make the gauge field antiperiodic in nu-direction | ||||
|     LatticeColourMatrix Unu(UGrid_1f); | ||||
|     decltype(PeekIndex<LorentzIndex>(Umu_1f,nu)) Unu(UGrid_1f); | ||||
|     Unu = PeekIndex<LorentzIndex>(Umu_1f,nu); | ||||
|     Unu = where(xcoor_1f == Integer(2*L-1), -Unu, Unu); | ||||
|     PokeIndex<LorentzIndex>(Umu_1f,Unu,nu); | ||||
| @@ -115,33 +161,33 @@ int main (int argc, char ** argv) | ||||
|  | ||||
|   RealD mass=0.0; | ||||
|   RealD M5=1.8; | ||||
|   DomainWallFermionR Ddwf(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f,mass,M5); | ||||
|   StandardDiracOp Ddwf(Umu_1f,*FGrid_1f,*FrbGrid_1f,*UGrid_1f,*UrbGrid_1f,mass,M5 DOP_PARAMS); | ||||
|  | ||||
|   LatticeFermion    src_o_1f(FrbGrid_1f); | ||||
|   LatticeFermion result_o_1f(FrbGrid_1f); | ||||
|   StandardFermionField    src_o_1f(FrbGrid_1f); | ||||
|   StandardFermionField result_o_1f(FrbGrid_1f); | ||||
|   pickCheckerboard(Odd,src_o_1f,src_1f); | ||||
|   result_o_1f=zero; | ||||
|  | ||||
|   SchurDiagMooeeOperator<DomainWallFermionR,LatticeFermion> HermOpEO(Ddwf); | ||||
|   ConjugateGradient<LatticeFermion> CG(1.0e-8,10000); | ||||
|   SchurDiagMooeeOperator<StandardDiracOp,StandardFermionField> HermOpEO(Ddwf); | ||||
|   ConjugateGradient<StandardFermionField> CG(1.0e-8,10000); | ||||
|   CG(HermOpEO,src_o_1f,result_o_1f); | ||||
|    | ||||
|   //  const int nu = 3; | ||||
|   std::vector<int> twists(Nd,0); | ||||
|   twists[nu] = 1; | ||||
|   GparityDomainWallFermionR::ImplParams params; | ||||
|   GparityDiracOp::ImplParams params; | ||||
|   params.twists = twists; | ||||
|   GparityDomainWallFermionR GPDdwf(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f,mass,M5,params); | ||||
|   GparityDiracOp GPDdwf(Umu_2f,*FGrid_2f,*FrbGrid_2f,*UGrid_2f,*UrbGrid_2f,mass,M5 DOP_PARAMS,params); | ||||
|  | ||||
|   for(int disp=-1;disp<=1;disp+=2) | ||||
|   for(int mu=0;mu<5;mu++) | ||||
|   {  | ||||
|     FermionField Dsrc_2f(FGrid_2f); | ||||
|     GparityFermionField Dsrc_2f(FGrid_2f); | ||||
|  | ||||
|     LatticeFermion Dsrc_1f(FGrid_1f); | ||||
|     LatticeFermion Dsrc_2freplica(FGrid_1f); | ||||
|     LatticeFermion Dsrc_2freplica0(FGrid_1f); | ||||
|     LatticeFermion Dsrc_2freplica1(FGrid_1f); | ||||
|     StandardFermionField Dsrc_1f(FGrid_1f); | ||||
|     StandardFermionField Dsrc_2freplica(FGrid_1f); | ||||
|     StandardFermionField Dsrc_2freplica0(FGrid_1f); | ||||
|     StandardFermionField Dsrc_2freplica1(FGrid_1f); | ||||
|  | ||||
|     if ( mu ==0 ) { | ||||
|       std::cout << GridLogMessage<< " Cross checking entire hopping term"<<std::endl; | ||||
| @@ -156,8 +202,8 @@ int main (int argc, char ** argv) | ||||
|     std::cout << GridLogMessage << "S norms "<< norm2(src_2f) << " " << norm2(src_1f)  <<std::endl; | ||||
|     std::cout << GridLogMessage << "D norms "<< norm2(Dsrc_2f)<< " " << norm2(Dsrc_1f) <<std::endl; | ||||
|  | ||||
|     LatticeFermion Dsrc_2f0(FGrid_2f); Dsrc_2f0 = PeekIndex<0>(Dsrc_2f,0); | ||||
|     LatticeFermion Dsrc_2f1(FGrid_2f); Dsrc_2f1 = PeekIndex<0>(Dsrc_2f,1); | ||||
|     StandardFermionField Dsrc_2f0(FGrid_2f); Dsrc_2f0 = PeekIndex<0>(Dsrc_2f,0); | ||||
|     StandardFermionField Dsrc_2f1(FGrid_2f); Dsrc_2f1 = PeekIndex<0>(Dsrc_2f,1); | ||||
|  | ||||
|     //    Dsrc_2f1 = Dsrc_2f1 - Dsrc_2f0; | ||||
|     //    std::cout << GridLogMessage << " Cross check two halves " <<norm2(Dsrc_2f1)<<std::endl; | ||||
| @@ -174,20 +220,20 @@ int main (int argc, char ** argv) | ||||
|   } | ||||
|  | ||||
|   { | ||||
|     FermionField chi   (FGrid_2f); gaussian(RNG5_2f,chi); | ||||
|     FermionField phi   (FGrid_2f); gaussian(RNG5_2f,phi); | ||||
|     GparityFermionField chi   (FGrid_2f); gaussian(RNG5_2f,chi); | ||||
|     GparityFermionField phi   (FGrid_2f); gaussian(RNG5_2f,phi); | ||||
|    | ||||
|     FermionField chi_e   (FrbGrid_2f); | ||||
|     FermionField chi_o   (FrbGrid_2f); | ||||
|     GparityFermionField chi_e   (FrbGrid_2f); | ||||
|     GparityFermionField chi_o   (FrbGrid_2f); | ||||
|      | ||||
|     FermionField dchi_e  (FrbGrid_2f); | ||||
|     FermionField dchi_o  (FrbGrid_2f); | ||||
|     GparityFermionField dchi_e  (FrbGrid_2f); | ||||
|     GparityFermionField dchi_o  (FrbGrid_2f); | ||||
|      | ||||
|     FermionField phi_e   (FrbGrid_2f); | ||||
|     FermionField phi_o   (FrbGrid_2f); | ||||
|     GparityFermionField phi_e   (FrbGrid_2f); | ||||
|     GparityFermionField phi_o   (FrbGrid_2f); | ||||
|      | ||||
|     FermionField dphi_e  (FrbGrid_2f); | ||||
|     FermionField dphi_o  (FrbGrid_2f); | ||||
|     GparityFermionField dphi_e  (FrbGrid_2f); | ||||
|     GparityFermionField dphi_o  (FrbGrid_2f); | ||||
|  | ||||
|     pickCheckerboard(Even,chi_e,chi); | ||||
|     pickCheckerboard(Odd ,chi_o,chi); | ||||
| @@ -212,14 +258,14 @@ int main (int argc, char ** argv) | ||||
|  | ||||
|   } | ||||
|  | ||||
|   FermionField result_2f(FGrid_2f); result_2f=zero; | ||||
|   FermionField    src_o_2f(FrbGrid_2f); | ||||
|   FermionField result_o_2f(FrbGrid_2f); | ||||
|   GparityFermionField result_2f(FGrid_2f); result_2f=zero; | ||||
|   GparityFermionField    src_o_2f(FrbGrid_2f); | ||||
|   GparityFermionField result_o_2f(FrbGrid_2f); | ||||
|   pickCheckerboard(Odd,src_o_2f,src_2f); | ||||
|   result_o_2f=zero; | ||||
|  | ||||
|   ConjugateGradient<FermionField> CG2f(1.0e-8,10000); | ||||
|   SchurDiagMooeeOperator<GparityDomainWallFermionR,FermionField> HermOpEO2f(GPDdwf); | ||||
|   ConjugateGradient<GparityFermionField> CG2f(1.0e-8,10000); | ||||
|   SchurDiagMooeeOperator<GparityDiracOp,GparityFermionField> HermOpEO2f(GPDdwf); | ||||
|   CG2f(HermOpEO2f,src_o_2f,result_o_2f); | ||||
|  | ||||
|   std::cout << "2f cb "<<result_o_2f.checkerboard<<std::endl; | ||||
| @@ -227,10 +273,10 @@ int main (int argc, char ** argv) | ||||
|  | ||||
|   std::cout << " result norms " <<norm2(result_o_2f)<<" " <<norm2(result_o_1f)<<std::endl; | ||||
|  | ||||
|   LatticeFermion    res0o  (FrbGrid_2f);  | ||||
|   LatticeFermion    res1o  (FrbGrid_2f);  | ||||
|   LatticeFermion    res0  (FGrid_2f);  | ||||
|   LatticeFermion    res1  (FGrid_2f);  | ||||
|   StandardFermionField    res0o  (FrbGrid_2f);  | ||||
|   StandardFermionField    res1o  (FrbGrid_2f);  | ||||
|   StandardFermionField    res0  (FGrid_2f);  | ||||
|   StandardFermionField    res1  (FGrid_2f);  | ||||
|  | ||||
|   res0=zero; | ||||
|   res1=zero; | ||||
| @@ -244,9 +290,9 @@ int main (int argc, char ** argv) | ||||
|   setCheckerboard(res0,res0o); | ||||
|   setCheckerboard(res1,res1o); | ||||
|  | ||||
|   LatticeFermion replica (FGrid_1f); | ||||
|   LatticeFermion replica0(FGrid_1f); | ||||
|   LatticeFermion replica1(FGrid_1f); | ||||
|   StandardFermionField replica (FGrid_1f); | ||||
|   StandardFermionField replica0(FGrid_1f); | ||||
|   StandardFermionField replica1(FGrid_1f); | ||||
|   Replicate(res0,replica0); | ||||
|   Replicate(res1,replica1); | ||||
|  | ||||
|   | ||||
| @@ -40,7 +40,7 @@ int main (int argc, char ** argv) | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); | ||||
|   GridCartesian               Grid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(&Grid); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   | ||||
| @@ -84,7 +84,7 @@ int main(int argc, char **argv) { | ||||
|       double volume = latt_size[0] * latt_size[1] * latt_size[2] * latt_size[3]; | ||||
|  | ||||
|       GridCartesian Fine(latt_size, simd_layout, mpi_layout); | ||||
|       GridRedBlackCartesian rbFine(latt_size, simd_layout, mpi_layout); | ||||
|       GridRedBlackCartesian rbFine(&Fine); | ||||
|       GridParallelRNG FineRNG(&Fine); | ||||
|       GridSerialRNG SerialRNG; | ||||
|       GridSerialRNG SerialRNG1; | ||||
|   | ||||
							
								
								
									
										241
									
								
								tests/core/Test_mobius_eofa_even_odd.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								tests/core/Test_mobius_eofa_even_odd.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/core/Test_dwf_eofa_even_odd.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| template<class d> | ||||
| struct scal { | ||||
|     d internal; | ||||
| }; | ||||
|  | ||||
| Gamma::Algebra Gmu [] = { | ||||
|     Gamma::Algebra::GammaX, | ||||
|     Gamma::Algebra::GammaY, | ||||
|     Gamma::Algebra::GammaZ, | ||||
|     Gamma::Algebra::GammaT | ||||
| }; | ||||
|  | ||||
| int main (int argc, char ** argv) | ||||
| { | ||||
|     Grid_init(&argc, &argv); | ||||
|  | ||||
|     int threads = GridThread::GetThreads(); | ||||
|     std::cout << GridLogMessage << "Grid is setup to use " << threads << " threads" << std::endl; | ||||
|  | ||||
|     const int Ls = 8; | ||||
|     // GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|     GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|     GridCartesian*         FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|     GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|     GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|     std::vector<int> seeds4({1,2,3,4}); | ||||
|     std::vector<int> seeds5({5,6,7,8}); | ||||
|  | ||||
|     GridParallelRNG RNG4(UGrid); RNG4.SeedFixedIntegers(seeds4); | ||||
|     GridParallelRNG RNG5(FGrid); RNG5.SeedFixedIntegers(seeds5); | ||||
|  | ||||
|     LatticeFermion    src   (FGrid); random(RNG5, src); | ||||
|     LatticeFermion    phi   (FGrid); random(RNG5, phi); | ||||
|     LatticeFermion    chi   (FGrid); random(RNG5, chi); | ||||
|     LatticeFermion    result(FGrid); result = zero; | ||||
|     LatticeFermion    ref   (FGrid); ref = zero; | ||||
|     LatticeFermion    tmp   (FGrid); tmp = zero; | ||||
|     LatticeFermion    err   (FGrid); err = zero; | ||||
|     LatticeGaugeField Umu   (UGrid); SU3::HotConfiguration(RNG4, Umu); | ||||
|     std::vector<LatticeColourMatrix> U(4,UGrid); | ||||
|  | ||||
|     // Only one non-zero (y) | ||||
|     Umu = zero; | ||||
|     for(int nn=0; nn<Nd; nn++){ | ||||
|         random(RNG4, U[nn]); | ||||
|         if(nn>0){ U[nn] = zero; } | ||||
|         PokeIndex<LorentzIndex>(Umu, U[nn], nn); | ||||
|     } | ||||
|  | ||||
|     RealD b     = 2.5; | ||||
|     RealD c     = 1.5; | ||||
|     RealD mq1   = 0.1; | ||||
|     RealD mq2   = 0.5; | ||||
|     RealD mq3   = 1.0; | ||||
|     RealD shift = 0.1234; | ||||
|     RealD M5    = 1.8; | ||||
|     int   pm    = 1; | ||||
|     MobiusEOFAFermionR Ddwf(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mq1, mq2, mq3, shift, pm, M5, b, c); | ||||
|  | ||||
|     LatticeFermion src_e (FrbGrid); | ||||
|     LatticeFermion src_o (FrbGrid); | ||||
|     LatticeFermion r_e   (FrbGrid); | ||||
|     LatticeFermion r_o   (FrbGrid); | ||||
|     LatticeFermion r_eo  (FGrid); | ||||
|     LatticeFermion r_eeoo(FGrid); | ||||
|  | ||||
|     std::cout << GridLogMessage << "==========================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Testing that Meo + Moe + Moo + Mee = Munprec " << std::endl; | ||||
|     std::cout << GridLogMessage << "==========================================================" << std::endl; | ||||
|  | ||||
|     pickCheckerboard(Even, src_e, src); | ||||
|     pickCheckerboard(Odd,  src_o, src); | ||||
|  | ||||
|     Ddwf.Meooe(src_e, r_o); std::cout << GridLogMessage << "Applied Meo" << std::endl; | ||||
|     Ddwf.Meooe(src_o, r_e); std::cout << GridLogMessage << "Applied Moe" << std::endl; | ||||
|     setCheckerboard(r_eo, r_o); | ||||
|     setCheckerboard(r_eo, r_e); | ||||
|  | ||||
|     Ddwf.Mooee(src_e, r_e); std::cout << GridLogMessage << "Applied Mee" << std::endl; | ||||
|     Ddwf.Mooee(src_o, r_o); std::cout << GridLogMessage << "Applied Moo" << std::endl; | ||||
|     setCheckerboard(r_eeoo, r_e); | ||||
|     setCheckerboard(r_eeoo, r_o); | ||||
|  | ||||
|     r_eo = r_eo + r_eeoo; | ||||
|     Ddwf.M(src, ref); | ||||
|  | ||||
|     // std::cout << GridLogMessage << r_eo << std::endl; | ||||
|     // std::cout << GridLogMessage << ref  << std::endl; | ||||
|  | ||||
|     err = ref - r_eo; | ||||
|     std::cout << GridLogMessage << "EO norm diff   " << norm2(err) << " " << norm2(ref) << " " << norm2(r_eo) << std::endl; | ||||
|  | ||||
|     LatticeComplex cerr(FGrid); | ||||
|     cerr = localInnerProduct(err,err); | ||||
|     // std::cout << GridLogMessage << cerr << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test Ddagger is the dagger of D by requiring                " << std::endl; | ||||
|     std::cout << GridLogMessage << "=  < phi | Deo | chi > * = < chi | Deo^dag| phi>  " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     LatticeFermion chi_e (FrbGrid); | ||||
|     LatticeFermion chi_o (FrbGrid); | ||||
|  | ||||
|     LatticeFermion dchi_e(FrbGrid); | ||||
|     LatticeFermion dchi_o(FrbGrid); | ||||
|  | ||||
|     LatticeFermion phi_e (FrbGrid); | ||||
|     LatticeFermion phi_o (FrbGrid); | ||||
|  | ||||
|     LatticeFermion dphi_e(FrbGrid); | ||||
|     LatticeFermion dphi_o(FrbGrid); | ||||
|  | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|     pickCheckerboard(Even, phi_e, phi); | ||||
|     pickCheckerboard(Odd , phi_o, phi); | ||||
|  | ||||
|     Ddwf.Meooe   (chi_e, dchi_o); | ||||
|     Ddwf.Meooe   (chi_o, dchi_e); | ||||
|     Ddwf.MeooeDag(phi_e, dphi_o); | ||||
|     Ddwf.MeooeDag(phi_o, dphi_e); | ||||
|  | ||||
|     ComplexD pDce = innerProduct(phi_e, dchi_e); | ||||
|     ComplexD pDco = innerProduct(phi_o, dchi_o); | ||||
|     ComplexD cDpe = innerProduct(chi_e, dphi_e); | ||||
|     ComplexD cDpo = innerProduct(chi_o, dphi_o); | ||||
|  | ||||
|     std::cout << GridLogMessage << "e " << pDce << " " << cDpe << std::endl; | ||||
|     std::cout << GridLogMessage << "o " << pDco << " " << cDpo << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "pDce - conj(cDpo) " << pDce-conj(cDpo) << std::endl; | ||||
|     std::cout << GridLogMessage << "pDco - conj(cDpe) " << pDco-conj(cDpe) << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test MeeInv Mee = 1                                         " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|  | ||||
|     Ddwf.Mooee   (chi_e, src_e); | ||||
|     Ddwf.MooeeInv(src_e, phi_e); | ||||
|  | ||||
|     Ddwf.Mooee   (chi_o, src_o); | ||||
|     Ddwf.MooeeInv(src_o, phi_o); | ||||
|  | ||||
|     setCheckerboard(phi, phi_e); | ||||
|     setCheckerboard(phi, phi_o); | ||||
|  | ||||
|     err = phi - chi; | ||||
|     std::cout << GridLogMessage << "norm diff   " << norm2(err) << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test MeeInvDag MeeDag = 1                                   " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|  | ||||
|     Ddwf.MooeeDag   (chi_e, src_e); | ||||
|     Ddwf.MooeeInvDag(src_e, phi_e); | ||||
|  | ||||
|     Ddwf.MooeeDag   (chi_o, src_o); | ||||
|     Ddwf.MooeeInvDag(src_o, phi_o); | ||||
|  | ||||
|     setCheckerboard(phi, phi_e); | ||||
|     setCheckerboard(phi, phi_o); | ||||
|  | ||||
|     err = phi - chi; | ||||
|     std::cout << GridLogMessage << "norm diff   " << norm2(err) << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|     std::cout << GridLogMessage << "= Test MpcDagMpc is Hermitian              " << std::endl; | ||||
|     std::cout << GridLogMessage << "==============================================================" << std::endl; | ||||
|  | ||||
|     random(RNG5, phi); | ||||
|     random(RNG5, chi); | ||||
|     pickCheckerboard(Even, chi_e, chi); | ||||
|     pickCheckerboard(Odd , chi_o, chi); | ||||
|     pickCheckerboard(Even, phi_e, phi); | ||||
|     pickCheckerboard(Odd , phi_o, phi); | ||||
|     RealD t1,t2; | ||||
|  | ||||
|     SchurDiagMooeeOperator<MobiusEOFAFermionR,LatticeFermion> HermOpEO(Ddwf); | ||||
|     HermOpEO.MpcDagMpc(chi_e, dchi_e, t1, t2); | ||||
|     HermOpEO.MpcDagMpc(chi_o, dchi_o, t1, t2); | ||||
|  | ||||
|     HermOpEO.MpcDagMpc(phi_e, dphi_e, t1, t2); | ||||
|     HermOpEO.MpcDagMpc(phi_o, dphi_o, t1, t2); | ||||
|  | ||||
|     pDce = innerProduct(phi_e, dchi_e); | ||||
|     pDco = innerProduct(phi_o, dchi_o); | ||||
|     cDpe = innerProduct(chi_e, dphi_e); | ||||
|     cDpo = innerProduct(chi_o, dphi_o); | ||||
|  | ||||
|     std::cout << GridLogMessage << "e " << pDce << " " << cDpe << std::endl; | ||||
|     std::cout << GridLogMessage << "o " << pDco << " " << cDpo << std::endl; | ||||
|  | ||||
|     std::cout << GridLogMessage << "pDce - conj(cDpo) " << pDco-conj(cDpo) << std::endl; | ||||
|     std::cout << GridLogMessage << "pDco - conj(cDpe) " << pDce-conj(cDpe) << std::endl; | ||||
|  | ||||
|     Grid_finalize(); | ||||
| } | ||||
| @@ -40,7 +40,7 @@ int main (int argc, char ** argv) | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); | ||||
|   GridCartesian               Grid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(&Grid); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   | ||||
| @@ -51,7 +51,7 @@ int main (int argc, char ** argv) | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); | ||||
|   GridCartesian               Grid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(&Grid); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   | ||||
| @@ -52,7 +52,7 @@ int main (int argc, char ** argv) | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> mpi_layout  = GridDefaultMpi(); | ||||
|   GridCartesian               Grid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(latt_size,simd_layout,mpi_layout); | ||||
|   GridRedBlackCartesian     RBGrid(&Grid); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout<<GridLogMessage << "Grid is setup to use "<<threads<<" threads"<<std::endl; | ||||
|   | ||||
| @@ -37,8 +37,15 @@ RealD InverseApproximation(RealD x){ | ||||
| RealD SqrtApproximation(RealD x){ | ||||
|   return std::sqrt(x); | ||||
| } | ||||
| RealD Approximation32(RealD x){ | ||||
|   return std::pow(x,-1.0/32.0); | ||||
| } | ||||
| RealD Approximation2(RealD x){ | ||||
|   return std::pow(x,-1.0/2.0); | ||||
| } | ||||
|  | ||||
| RealD StepFunction(RealD x){ | ||||
|   if ( x<0.1 )  return 1.0; | ||||
|   if ( x<10.0 )  return 1.0; | ||||
|   else return 0.0; | ||||
| } | ||||
|  | ||||
| @@ -56,7 +63,6 @@ int main (int argc, char ** argv) | ||||
|  | ||||
|   Chebyshev<LatticeFermion> ChebyInv(lo,hi,2000,InverseApproximation); | ||||
|  | ||||
|  | ||||
|   { | ||||
|     std::ofstream of("chebyinv"); | ||||
|     ChebyInv.csv(of); | ||||
| @@ -78,7 +84,6 @@ int main (int argc, char ** argv) | ||||
|  | ||||
|  | ||||
|   ChebyStep.JacksonSmooth(); | ||||
|  | ||||
|   { | ||||
|     std::ofstream of("chebystepjack"); | ||||
|     ChebyStep.csv(of); | ||||
| @@ -100,5 +105,30 @@ int main (int argc, char ** argv) | ||||
|     ChebyNE.csv(of); | ||||
|   } | ||||
|  | ||||
|   lo=0.0; | ||||
|   hi=4.0; | ||||
|   Chebyshev<LatticeFermion> Cheby32(lo,hi,2000,Approximation32); | ||||
|   { | ||||
|     std::ofstream of("cheby32"); | ||||
|     Cheby32.csv(of); | ||||
|   } | ||||
|   Cheby32.JacksonSmooth(); | ||||
|   { | ||||
|     std::ofstream of("cheby32jack"); | ||||
|     Cheby32.csv(of); | ||||
|   } | ||||
|  | ||||
|   Chebyshev<LatticeFermion> ChebySqrt(lo,hi,2000,Approximation2); | ||||
|   { | ||||
|     std::ofstream of("chebysqrt"); | ||||
|     ChebySqrt.csv(of); | ||||
|   } | ||||
|   ChebySqrt.JacksonSmooth(); | ||||
|   { | ||||
|     std::ofstream of("chebysqrtjack"); | ||||
|     ChebySqrt.csv(of); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   Grid_finalize(); | ||||
| } | ||||
|   | ||||
							
								
								
									
										102
									
								
								tests/debug/Test_heatbath_dwf_eofa.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								tests/debug/Test_heatbath_dwf_eofa.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
|     Source file: ./tests/debug/Test_heatbath_dwf_eofa.cc | ||||
|  | ||||
|     Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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 */ | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // This program sets up the initial pseudofermion field |Phi> = Meofa^{-1/2}*|eta>, and | ||||
| // then uses this Phi to compute the action <Phi|Meofa|Phi>. | ||||
| // If all is working, one should find that <eta|eta> = <Phi|Meofa|Phi>. | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include <Grid/Grid.h> | ||||
|  | ||||
| using namespace std; | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| // Parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int              Ls       = 8; | ||||
| const int              Npoles   = 12; | ||||
| const RealD            mf       = 0.01; | ||||
| const RealD            mpv      = 1.0; | ||||
| const RealD            M5       = 1.8; | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout << GridLogMessage << "Grid is set up to use " << threads << " threads" << std::endl; | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " << grid_dim << "  Ls: " << Ls << std::endl; | ||||
|   GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|                                       GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian*         FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   DomainWallEOFAFermionR Lop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf,  mf, mpv,  0.0, -1, M5); | ||||
|   DomainWallEOFAFermionR Rop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mpv, mf, mpv, -1.0,  1, M5); | ||||
|  | ||||
|   // Construct the action and test the heatbath (zero initial guess) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<LatticeFermion> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, Params, false); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   // Construct the action and test the heatbath (forecasted initial guesses) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<LatticeFermion> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, Params, true); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										108
									
								
								tests/debug/Test_heatbath_dwf_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								tests/debug/Test_heatbath_dwf_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
|     /************************************************************************************* | ||||
|  | ||||
|     Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
|     Source file: ./tests/debug/Test_heatbath_dwf_eofa.cc | ||||
|  | ||||
|     Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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 */ | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // This program sets up the initial pseudofermion field |Phi> = Meofa^{-1/2}*|eta>, and | ||||
| // then uses this Phi to compute the action <Phi|Meofa|Phi>. | ||||
| // If all is working, one should find that <eta|eta> = <Phi|Meofa|Phi>. | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include <Grid/Grid.h> | ||||
|  | ||||
| using namespace std; | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| typedef GparityWilsonImplR FermionImplPolicy; | ||||
| typedef GparityDomainWallEOFAFermionR FermionAction; | ||||
| typedef typename FermionAction::FermionField FermionField; | ||||
|  | ||||
| // Parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int              Ls       = 8; | ||||
| const int              Npoles   = 12; | ||||
| const RealD            mf       = 0.01; | ||||
| const RealD            mpv      = 1.0; | ||||
| const RealD            M5       = 1.8; | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout << GridLogMessage << "Grid is set up to use " << threads << " threads" << std::endl; | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " << grid_dim << "  Ls: " << Ls << std::endl; | ||||
|   GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|                                       GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian*         FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   // GparityDomainWallFermionR::ImplParams params; | ||||
|   FermionAction::ImplParams params; | ||||
|   FermionAction Lop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf,  mf, mpv,  0.0, -1, M5, params); | ||||
|   FermionAction Rop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mpv, mf, mpv, -1.0,  1, M5, params); | ||||
|  | ||||
|   // Construct the action and test the heatbath (zero initial guess) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<FermionField> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> Meofa(Lop, Rop, CG, Params, false); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   // Construct the action and test the heatbath (forecasted initial guesses) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<FermionField> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> Meofa(Lop, Rop, CG, Params, true); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										104
									
								
								tests/debug/Test_heatbath_mobius_eofa.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								tests/debug/Test_heatbath_mobius_eofa.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/debug/Test_heatbath_dwf_eofa.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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 */ | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // This program sets up the initial pseudofermion field |Phi> = Meofa^{-1/2}*|eta>, and | ||||
| // then uses this Phi to compute the action <Phi|Meofa|Phi>. | ||||
| // If all is working, one should find that <eta|eta> = <Phi|Meofa|Phi>. | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include <Grid/Grid.h> | ||||
|  | ||||
| using namespace std; | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| // Parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int              Ls       = 8; | ||||
| const int              Npoles   = 12; | ||||
| const RealD            b        = 2.5; | ||||
| const RealD            c        = 1.5; | ||||
| const RealD            mf       = 0.01; | ||||
| const RealD            mpv      = 1.0; | ||||
| const RealD            M5       = 1.8; | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout << GridLogMessage << "Grid is set up to use " << threads << " threads" << std::endl; | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " << grid_dim << "  Ls: " << Ls << std::endl; | ||||
|   GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|                                     GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian*         FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   MobiusEOFAFermionR Lop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf,  mf, mpv,  0.0, -1, M5, b, c); | ||||
|   MobiusEOFAFermionR Rop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mpv, mf, mpv, -1.0,  1, M5, b, c); | ||||
|  | ||||
|   // Construct the action and test the heatbath (zero initial guess) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<LatticeFermion> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, Params, false); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   // Construct the action and test the heatbath (forecasted initial guesses) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<LatticeFermion> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, Params, true); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										109
									
								
								tests/debug/Test_heatbath_mobius_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								tests/debug/Test_heatbath_mobius_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/debug/Test_heatbath_dwf_eofa.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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 */ | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // This program sets up the initial pseudofermion field |Phi> = Meofa^{-1/2}*|eta>, and | ||||
| // then uses this Phi to compute the action <Phi|Meofa|Phi>. | ||||
| // If all is working, one should find that <eta|eta> = <Phi|Meofa|Phi>. | ||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| #include <Grid/Grid.h> | ||||
|  | ||||
| using namespace std; | ||||
| using namespace Grid; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| typedef GparityWilsonImplR FermionImplPolicy; | ||||
| typedef GparityMobiusEOFAFermionR FermionAction; | ||||
| typedef typename FermionAction::FermionField FermionField; | ||||
|  | ||||
| // Parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int              Ls       = 8; | ||||
| const int              Npoles   = 12; | ||||
| const RealD            b        = 2.5; | ||||
| const RealD            c        = 1.5; | ||||
| const RealD            mf       = 0.01; | ||||
| const RealD            mpv      = 1.0; | ||||
| const RealD            M5       = 1.8; | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   int threads = GridThread::GetThreads(); | ||||
|   std::cout << GridLogMessage << "Grid is set up to use " << threads << " threads" << std::endl; | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " << grid_dim << "  Ls: " << Ls << std::endl; | ||||
|   GridCartesian*         UGrid   = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|                                     GridDefaultSimd(Nd,vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian*         FGrid   = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   FermionAction::ImplParams params; | ||||
|   FermionAction Lop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf,  mf, mpv,  0.0, -1, M5, b, c, params); | ||||
|   FermionAction Rop(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mpv, mf, mpv, -1.0,  1, M5, b, c, params); | ||||
|  | ||||
|   // Construct the action and test the heatbath (zero initial guess) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<FermionField> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> Meofa(Lop, Rop, CG, Params, false); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   // Construct the action and test the heatbath (forecasted initial guesses) | ||||
|   { | ||||
|     OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, Npoles); | ||||
|     ConjugateGradient<FermionField> CG(1.0e-12, 5000); | ||||
|     ExactOneFlavourRatioPseudoFermionAction<FermionImplPolicy> Meofa(Lop, Rop, CG, Params, true); | ||||
|  | ||||
|     Meofa.refresh(Umu, RNG5); | ||||
|     printf("<Phi|Meofa|Phi> = %1.15e\n", Meofa.S(Umu)); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										206
									
								
								tests/debug/Test_reweight_dwf_eofa.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								tests/debug/Test_reweight_dwf_eofa.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/debug/Test_reweight_dwf_eofa.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| // parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int Ls = 8; | ||||
| const int Nhits = 25; | ||||
| const int max_iter = 5000; | ||||
| const RealD mf = 0.1; | ||||
| const RealD mb = 0.11; | ||||
| const RealD M5 = 1.8; | ||||
| const RealD stop_tol = 1.0e-12; | ||||
|  | ||||
| RealD mean(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ mean += data[i]; } | ||||
|     return mean/RealD(N); | ||||
| } | ||||
|  | ||||
| RealD jack_mean(const std::vector<RealD>& data, int sample) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ if(i != sample){ mean += data[i]; } } | ||||
|     return mean/RealD(N-1); | ||||
| } | ||||
|  | ||||
| RealD jack_std(const std::vector<RealD>& jacks, RealD mean) | ||||
| { | ||||
|     int N = jacks.size(); | ||||
|     RealD std(0.0); | ||||
|     for(int i=0; i<N; ++i){ std += std::pow(jacks[i]-mean, 2.0); } | ||||
|     return std::sqrt(RealD(N-1)/RealD(N)*std); | ||||
| } | ||||
|  | ||||
| std::vector<RealD> jack_stats(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     std::vector<RealD> jack_samples(N); | ||||
|     std::vector<RealD> jack_stats(2); | ||||
|  | ||||
|     jack_stats[0] = mean(data); | ||||
|     for(int i=0; i<N; i++){ jack_samples[i] = jack_mean(data,i); } | ||||
|     jack_stats[1] = jack_std(jack_samples, jack_stats[0]); | ||||
|     return jack_stats; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " | ||||
|     << grid_dim << "   Ls: " << Ls << std::endl; | ||||
|   GridCartesian* UGrid = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|       GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian* FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   // Initialize RHMC fermion operators | ||||
|   DomainWallFermionR Ddwf_f(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, M5); | ||||
|   DomainWallFermionR Ddwf_b(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, M5); | ||||
|   SchurDiagMooeeOperator<DomainWallFermionR, LatticeFermion> MdagM(Ddwf_f); | ||||
|   SchurDiagMooeeOperator<DomainWallFermionR, LatticeFermion> VdagV(Ddwf_b); | ||||
|  | ||||
|   // Degree 12 rational approximations to x^(1/4) and x^(-1/4) | ||||
|   double     lo = 0.0001; | ||||
|   double     hi = 95.0; | ||||
|   int precision = 64; | ||||
|   int    degree = 12; | ||||
|   AlgRemez remez(lo, hi, precision); | ||||
|   std::cout << GridLogMessage << "Generating degree " << degree << " for x^(1/4)" << std::endl; | ||||
|   remez.generateApprox(degree, 1, 4); | ||||
|   MultiShiftFunction PowerQuarter(remez, stop_tol, false); | ||||
|   MultiShiftFunction PowerNegQuarter(remez, stop_tol, true); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via RHMC | ||||
|   RealD scale = std::sqrt(0.5); | ||||
|   std::vector<RealD> rw_rhmc(Nhits); | ||||
|   ConjugateGradientMultiShift<LatticeFermion> msCG_V(max_iter, PowerQuarter); | ||||
|   ConjugateGradientMultiShift<LatticeFermion> msCG_M(max_iter, PowerNegQuarter); | ||||
|   std::cout.precision(12); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     LatticeFermion Phi    (Ddwf_f.FermionGrid()); | ||||
|     LatticeFermion PhiOdd (Ddwf_f.FermionRedBlackGrid()); | ||||
|     std::vector<LatticeFermion> tmp(2, Ddwf_f.FermionRedBlackGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     pickCheckerboard(Odd, PhiOdd, Phi); | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     msCG_V(VdagV, PhiOdd, tmp[0]); | ||||
|     msCG_M(MdagM, tmp[0], tmp[1]); | ||||
|     rw_rhmc[hit] = norm2(tmp[1]) - norm2(PhiOdd); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- RHMC: Hit " << hit << ": rw = " << rw_rhmc[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Initialize EOFA fermion operators | ||||
|   RealD shift_L = 0.0; | ||||
|   RealD shift_R = -1.0; | ||||
|   int pm = 1; | ||||
|   DomainWallEOFAFermionR Deofa_L(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, mf, mb, shift_L, pm, M5); | ||||
|   DomainWallEOFAFermionR Deofa_R(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, mf, mb, shift_R, pm, M5); | ||||
|   MdagMLinearOperator<DomainWallEOFAFermionR, LatticeFermion> LdagL(Deofa_L); | ||||
|   MdagMLinearOperator<DomainWallEOFAFermionR, LatticeFermion> RdagR(Deofa_R); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via EOFA | ||||
|   RealD k = Deofa_L.k; | ||||
|   std::vector<RealD> rw_eofa(Nhits); | ||||
|   ConjugateGradient<LatticeFermion> CG(stop_tol, max_iter); | ||||
|   SchurRedBlackDiagMooeeSolve<LatticeFermion> SchurSolver(CG); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     LatticeFermion Phi       (Deofa_L.FermionGrid()); | ||||
|     LatticeFermion spProj_Phi(Deofa_L.FermionGrid()); | ||||
|     std::vector<LatticeFermion> tmp(2, Deofa_L.FermionGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     // LH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pminus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_L.Omega(spProj_Phi, tmp[0], -1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_L, tmp[1], tmp[0]); | ||||
|     Deofa_L.Omega(tmp[0], tmp[1], -1, 1); | ||||
|     rw_eofa[hit] = -k*innerProduct(spProj_Phi,tmp[1]).real(); | ||||
|  | ||||
|     // RH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pplus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_R.Omega(spProj_Phi, tmp[0], 1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_R, tmp[1], tmp[0]); | ||||
|     Deofa_R.Omega(tmp[0], tmp[1], 1, 1); | ||||
|     rw_eofa[hit] += k*innerProduct(spProj_Phi,tmp[1]).real(); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- EOFA: Hit " << hit << ": rw = " << rw_eofa[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   std::vector<RealD> rhmc_result = jack_stats(rw_rhmc); | ||||
|   std::vector<RealD> eofa_result = jack_stats(rw_eofa); | ||||
|   std::cout << std::endl << "RHMC: rw = " << rhmc_result[0] << " +/- " << rhmc_result[1] << std::endl; | ||||
|   std::cout << std::endl << "EOFA: rw = " << eofa_result[0] << " +/- " << eofa_result[1] << std::endl; | ||||
|  | ||||
|   Grid_finalize(); | ||||
| } | ||||
							
								
								
									
										209
									
								
								tests/debug/Test_reweight_dwf_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								tests/debug/Test_reweight_dwf_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,209 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/debug/Test_reweight_dwf_eofa_gparity.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| typedef typename GparityDomainWallFermionR::FermionField FermionField; | ||||
|  | ||||
| // parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int Ls = 8; | ||||
| const int Nhits = 10; | ||||
| const int max_iter = 5000; | ||||
| const RealD mf = 0.1; | ||||
| const RealD mb = 0.11; | ||||
| const RealD M5 = 1.8; | ||||
| const RealD stop_tol = 1.0e-12; | ||||
|  | ||||
| RealD mean(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ mean += data[i]; } | ||||
|     return mean/RealD(N); | ||||
| } | ||||
|  | ||||
| RealD jack_mean(const std::vector<RealD>& data, int sample) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ if(i != sample){ mean += data[i]; } } | ||||
|     return mean/RealD(N-1); | ||||
| } | ||||
|  | ||||
| RealD jack_std(const std::vector<RealD>& jacks, RealD mean) | ||||
| { | ||||
|     int N = jacks.size(); | ||||
|     RealD std(0.0); | ||||
|     for(int i=0; i<N; ++i){ std += std::pow(jacks[i]-mean, 2.0); } | ||||
|     return std::sqrt(RealD(N-1)/RealD(N)*std); | ||||
| } | ||||
|  | ||||
| std::vector<RealD> jack_stats(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     std::vector<RealD> jack_samples(N); | ||||
|     std::vector<RealD> jack_stats(2); | ||||
|  | ||||
|     jack_stats[0] = mean(data); | ||||
|     for(int i=0; i<N; i++){ jack_samples[i] = jack_mean(data,i); } | ||||
|     jack_stats[1] = jack_std(jack_samples, jack_stats[0]); | ||||
|     return jack_stats; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " | ||||
|     << grid_dim << "   Ls: " << Ls << std::endl; | ||||
|   GridCartesian* UGrid = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|       GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian* FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   // Initialize RHMC fermion operators | ||||
|   GparityDomainWallFermionR::ImplParams params; | ||||
|   GparityDomainWallFermionR Ddwf_f(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, M5, params); | ||||
|   GparityDomainWallFermionR Ddwf_b(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, M5, params); | ||||
|   SchurDiagMooeeOperator<GparityDomainWallFermionR, FermionField> MdagM(Ddwf_f); | ||||
|   SchurDiagMooeeOperator<GparityDomainWallFermionR, FermionField> VdagV(Ddwf_b); | ||||
|  | ||||
|   // Degree 12 rational approximations to x^(1/4) and x^(-1/4) | ||||
|   double     lo = 0.0001; | ||||
|   double     hi = 95.0; | ||||
|   int precision = 64; | ||||
|   int    degree = 12; | ||||
|   AlgRemez remez(lo, hi, precision); | ||||
|   std::cout << GridLogMessage << "Generating degree " << degree << " for x^(1/4)" << std::endl; | ||||
|   remez.generateApprox(degree, 1, 4); | ||||
|   MultiShiftFunction PowerQuarter(remez, stop_tol, false); | ||||
|   MultiShiftFunction PowerNegQuarter(remez, stop_tol, true); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via RHMC | ||||
|   RealD scale = std::sqrt(0.5); | ||||
|   std::vector<RealD> rw_rhmc(Nhits); | ||||
|   ConjugateGradientMultiShift<FermionField> msCG_V(max_iter, PowerQuarter); | ||||
|   ConjugateGradientMultiShift<FermionField> msCG_M(max_iter, PowerNegQuarter); | ||||
|   std::cout.precision(12); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     FermionField Phi    (Ddwf_f.FermionGrid()); | ||||
|     FermionField PhiOdd (Ddwf_f.FermionRedBlackGrid()); | ||||
|     std::vector<FermionField> tmp(2, Ddwf_f.FermionRedBlackGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     pickCheckerboard(Odd, PhiOdd, Phi); | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     msCG_V(VdagV, PhiOdd, tmp[0]); | ||||
|     msCG_M(MdagM, tmp[0], tmp[1]); | ||||
|     rw_rhmc[hit] = norm2(tmp[1]) - norm2(PhiOdd); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- RHMC: Hit " << hit << ": rw = " << rw_rhmc[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Initialize EOFA fermion operators | ||||
|   RealD shift_L = 0.0; | ||||
|   RealD shift_R = -1.0; | ||||
|   int pm = 1; | ||||
|   GparityDomainWallEOFAFermionR Deofa_L(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, mf, mb, shift_L, pm, M5, params); | ||||
|   GparityDomainWallEOFAFermionR Deofa_R(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, mf, mb, shift_R, pm, M5, params); | ||||
|   MdagMLinearOperator<GparityDomainWallEOFAFermionR, FermionField> LdagL(Deofa_L); | ||||
|   MdagMLinearOperator<GparityDomainWallEOFAFermionR, FermionField> RdagR(Deofa_R); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via EOFA | ||||
|   RealD k = Deofa_L.k; | ||||
|   std::vector<RealD> rw_eofa(Nhits); | ||||
|   ConjugateGradient<FermionField> CG(stop_tol, max_iter); | ||||
|   SchurRedBlackDiagMooeeSolve<FermionField> SchurSolver(CG); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     FermionField Phi       (Deofa_L.FermionGrid()); | ||||
|     FermionField spProj_Phi(Deofa_L.FermionGrid()); | ||||
|     std::vector<FermionField> tmp(2, Deofa_L.FermionGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     // LH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pminus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_L.Omega(spProj_Phi, tmp[0], -1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_L, tmp[1], tmp[0]); | ||||
|     Deofa_L.Omega(tmp[0], tmp[1], -1, 1); | ||||
|     rw_eofa[hit] = -k*innerProduct(spProj_Phi,tmp[1]).real(); | ||||
|  | ||||
|     // RH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pplus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_R.Omega(spProj_Phi, tmp[0], 1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_R, tmp[1], tmp[0]); | ||||
|     Deofa_R.Omega(tmp[0], tmp[1], 1, 1); | ||||
|     rw_eofa[hit] += k*innerProduct(spProj_Phi,tmp[1]).real(); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- EOFA: Hit " << hit << ": rw = " << rw_eofa[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   std::vector<RealD> rhmc_result = jack_stats(rw_rhmc); | ||||
|   std::vector<RealD> eofa_result = jack_stats(rw_eofa); | ||||
|   std::cout << std::endl << "RHMC: rw = " << rhmc_result[0] << " +/- " << rhmc_result[1] << std::endl; | ||||
|   std::cout << std::endl << "EOFA: rw = " << eofa_result[0] << " +/- " << eofa_result[1] << std::endl; | ||||
|  | ||||
|   Grid_finalize(); | ||||
| } | ||||
							
								
								
									
										215
									
								
								tests/debug/Test_reweight_mobius_eofa.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								tests/debug/Test_reweight_mobius_eofa.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/debug/Test_reweight_dwf_eofa.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| // parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int Ls = 8; | ||||
| const int Nhits = 10; | ||||
| const int max_iter = 5000; | ||||
| const RealD b  = 2.5; | ||||
| const RealD c  = 1.5; | ||||
| const RealD mf = 0.1; | ||||
| const RealD mb = 0.11; | ||||
| const RealD M5 = 1.8; | ||||
| const RealD stop_tol = 1.0e-12; | ||||
|  | ||||
| RealD mean(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ mean += data[i]; } | ||||
|     return mean/RealD(N); | ||||
| } | ||||
|  | ||||
| RealD jack_mean(const std::vector<RealD>& data, int sample) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ if(i != sample){ mean += data[i]; } } | ||||
|     return mean/RealD(N-1); | ||||
| } | ||||
|  | ||||
| RealD jack_std(const std::vector<RealD>& jacks, RealD mean) | ||||
| { | ||||
|     int N = jacks.size(); | ||||
|     RealD std(0.0); | ||||
|     for(int i=0; i<N; ++i){ std += std::pow(jacks[i]-mean, 2.0); } | ||||
|     return std::sqrt(RealD(N-1)/RealD(N)*std); | ||||
| } | ||||
|  | ||||
| std::vector<RealD> jack_stats(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     std::vector<RealD> jack_samples(N); | ||||
|     std::vector<RealD> jack_stats(2); | ||||
|  | ||||
|     jack_stats[0] = mean(data); | ||||
|     for(int i=0; i<N; i++){ jack_samples[i] = jack_mean(data,i); } | ||||
|     jack_stats[1] = jack_std(jack_samples, jack_stats[0]); | ||||
|     return jack_stats; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " | ||||
|     << grid_dim << "   Ls: " << Ls << std::endl; | ||||
|   GridCartesian* UGrid = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|       GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian* FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   // Initialize RHMC fermion operators | ||||
|   MobiusFermionR Ddwf_f(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, M5, b, c); | ||||
|   MobiusFermionR Ddwf_b(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, M5, b, c); | ||||
|   SchurDiagMooeeOperator<MobiusFermionR, LatticeFermion> MdagM(Ddwf_f); | ||||
|   SchurDiagMooeeOperator<MobiusFermionR, LatticeFermion> VdagV(Ddwf_b); | ||||
|  | ||||
|   // Degree 12 rational approximations to x^(1/4) and x^(-1/4) | ||||
|   double     lo = 0.0001; | ||||
|   double     hi = 95.0; | ||||
|   int precision = 64; | ||||
|   int    degree = 12; | ||||
|   AlgRemez remez(lo, hi, precision); | ||||
|   std::cout << GridLogMessage << "Generating degree " << degree << " for x^(1/4)" << std::endl; | ||||
|   remez.generateApprox(degree, 1, 4); | ||||
|   MultiShiftFunction PowerQuarter(remez, stop_tol, false); | ||||
|   MultiShiftFunction PowerNegQuarter(remez, stop_tol, true); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via RHMC | ||||
|   RealD scale = std::sqrt(0.5); | ||||
|   std::vector<RealD> rw_rhmc(Nhits); | ||||
|   ConjugateGradientMultiShift<LatticeFermion> msCG_V(max_iter, PowerQuarter); | ||||
|   ConjugateGradientMultiShift<LatticeFermion> msCG_M(max_iter, PowerNegQuarter); | ||||
|   std::cout.precision(12); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     LatticeFermion Phi    (Ddwf_f.FermionGrid()); | ||||
|     LatticeFermion PhiOdd (Ddwf_f.FermionRedBlackGrid()); | ||||
|     std::vector<LatticeFermion> tmp(2, Ddwf_f.FermionRedBlackGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     pickCheckerboard(Odd, PhiOdd, Phi); | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     msCG_V(VdagV, PhiOdd, tmp[0]); | ||||
|     msCG_M(MdagM, tmp[0], tmp[1]); | ||||
|     rw_rhmc[hit] = norm2(tmp[1]) - norm2(PhiOdd); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- RHMC: Hit " << hit << ": rw = " << rw_rhmc[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Initialize EOFA fermion operators | ||||
|   RealD shift_L = 0.0; | ||||
|   RealD shift_R = -1.0; | ||||
|   int pm = 1; | ||||
|   MobiusEOFAFermionR Deofa_L(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, mf, mb, shift_L, pm, M5, b, c); | ||||
|   MobiusEOFAFermionR Deofa_R(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, mf, mb, shift_R, pm, M5, b, c); | ||||
|   MdagMLinearOperator<MobiusEOFAFermionR, LatticeFermion> LdagL(Deofa_L); | ||||
|   MdagMLinearOperator<MobiusEOFAFermionR, LatticeFermion> RdagR(Deofa_R); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via EOFA | ||||
|   RealD k = Deofa_L.k; | ||||
|   std::vector<RealD> rw_eofa(Nhits); | ||||
|   ConjugateGradient<LatticeFermion> CG(stop_tol, max_iter); | ||||
|   SchurRedBlackDiagMooeeSolve<LatticeFermion> SchurSolver(CG); | ||||
|  | ||||
|   // Compute -log(Z), where: ( RHMC det ratio ) = Z * ( EOFA det ratio ) | ||||
|   RealD Z = std::pow(b+c+1.0,Ls) + mf*std::pow(b+c-1.0,Ls); | ||||
|   Z /= std::pow(b+c+1.0,Ls) + mb*std::pow(b+c-1.0,Ls); | ||||
|   Z = -12.0*grid_dim[0]*grid_dim[1]*grid_dim[2]*grid_dim[3]*std::log(Z); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     LatticeFermion Phi       (Deofa_L.FermionGrid()); | ||||
|     LatticeFermion spProj_Phi(Deofa_L.FermionGrid()); | ||||
|     std::vector<LatticeFermion> tmp(2, Deofa_L.FermionGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     // LH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pminus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_L.Omega(spProj_Phi, tmp[0], -1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_L, tmp[1], tmp[0]); | ||||
|     Deofa_L.Dtilde(tmp[0], tmp[1]); | ||||
|     Deofa_L.Omega(tmp[1], tmp[0], -1, 1); | ||||
|     rw_eofa[hit] = Z - k*innerProduct(spProj_Phi,tmp[0]).real(); | ||||
|  | ||||
|     // RH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pplus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_R.Omega(spProj_Phi, tmp[0], 1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_R, tmp[1], tmp[0]); | ||||
|     Deofa_R.Dtilde(tmp[0], tmp[1]); | ||||
|     Deofa_R.Omega(tmp[1], tmp[0], 1, 1); | ||||
|     rw_eofa[hit] += k*innerProduct(spProj_Phi,tmp[0]).real(); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- EOFA: Hit " << hit << ": rw = " << rw_eofa[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   std::vector<RealD> rhmc_result = jack_stats(rw_rhmc); | ||||
|   std::vector<RealD> eofa_result = jack_stats(rw_eofa); | ||||
|   std::cout << std::endl << "RHMC: rw = " << rhmc_result[0] << " +/- " << rhmc_result[1] << std::endl; | ||||
|   std::cout << std::endl << "EOFA: rw = " << eofa_result[0] << " +/- " << eofa_result[1] << std::endl; | ||||
|  | ||||
|   Grid_finalize(); | ||||
| } | ||||
							
								
								
									
										218
									
								
								tests/debug/Test_reweight_mobius_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								tests/debug/Test_reweight_mobius_eofa_gparity.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,218 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/debug/Test_reweight_dwf_eofa.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| Author: Peter Boyle <paboyle@ph.ed.ac.uk> | ||||
| Author: paboyle <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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| typedef typename GparityDomainWallFermionR::FermionField FermionField; | ||||
|  | ||||
| // parameters for test | ||||
| const std::vector<int> grid_dim = { 8, 8, 8, 8 }; | ||||
| const int Ls = 8; | ||||
| const int Nhits = 10; | ||||
| const int max_iter = 5000; | ||||
| const RealD b  = 2.5; | ||||
| const RealD c  = 1.5; | ||||
| const RealD mf = 0.1; | ||||
| const RealD mb = 0.11; | ||||
| const RealD M5 = 1.8; | ||||
| const RealD stop_tol = 1.0e-12; | ||||
|  | ||||
| RealD mean(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ mean += data[i]; } | ||||
|     return mean/RealD(N); | ||||
| } | ||||
|  | ||||
| RealD jack_mean(const std::vector<RealD>& data, int sample) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     RealD mean(0.0); | ||||
|     for(int i=0; i<N; ++i){ if(i != sample){ mean += data[i]; } } | ||||
|     return mean/RealD(N-1); | ||||
| } | ||||
|  | ||||
| RealD jack_std(const std::vector<RealD>& jacks, RealD mean) | ||||
| { | ||||
|     int N = jacks.size(); | ||||
|     RealD std(0.0); | ||||
|     for(int i=0; i<N; ++i){ std += std::pow(jacks[i]-mean, 2.0); } | ||||
|     return std::sqrt(RealD(N-1)/RealD(N)*std); | ||||
| } | ||||
|  | ||||
| std::vector<RealD> jack_stats(const std::vector<RealD>& data) | ||||
| { | ||||
|     int N = data.size(); | ||||
|     std::vector<RealD> jack_samples(N); | ||||
|     std::vector<RealD> jack_stats(2); | ||||
|  | ||||
|     jack_stats[0] = mean(data); | ||||
|     for(int i=0; i<N; i++){ jack_samples[i] = jack_mean(data,i); } | ||||
|     jack_stats[1] = jack_std(jack_samples, jack_stats[0]); | ||||
|     return jack_stats; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   // Initialize spacetime grid | ||||
|   std::cout << GridLogMessage << "Lattice dimensions: " | ||||
|     << grid_dim << "   Ls: " << Ls << std::endl; | ||||
|   GridCartesian* UGrid = SpaceTimeGrid::makeFourDimGrid(grid_dim, | ||||
|       GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi()); | ||||
|   GridRedBlackCartesian* UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); | ||||
|   GridCartesian* FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls, UGrid); | ||||
|   GridRedBlackCartesian* FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls, UGrid); | ||||
|  | ||||
|   // Set up RNGs | ||||
|   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); | ||||
|  | ||||
|   // Random gauge field | ||||
|   LatticeGaugeField Umu(UGrid); | ||||
|   SU3::HotConfiguration(RNG4, Umu); | ||||
|  | ||||
|   // Initialize RHMC fermion operators | ||||
|   GparityDomainWallFermionR::ImplParams params; | ||||
|   GparityMobiusFermionR Ddwf_f(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, M5, b, c, params); | ||||
|   GparityMobiusFermionR Ddwf_b(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, M5, b, c, params); | ||||
|   SchurDiagMooeeOperator<GparityMobiusFermionR, FermionField> MdagM(Ddwf_f); | ||||
|   SchurDiagMooeeOperator<GparityMobiusFermionR, FermionField> VdagV(Ddwf_b); | ||||
|  | ||||
|   // Degree 12 rational approximations to x^(1/4) and x^(-1/4) | ||||
|   double     lo = 0.0001; | ||||
|   double     hi = 95.0; | ||||
|   int precision = 64; | ||||
|   int    degree = 12; | ||||
|   AlgRemez remez(lo, hi, precision); | ||||
|   std::cout << GridLogMessage << "Generating degree " << degree << " for x^(1/4)" << std::endl; | ||||
|   remez.generateApprox(degree, 1, 4); | ||||
|   MultiShiftFunction PowerQuarter(remez, stop_tol, false); | ||||
|   MultiShiftFunction PowerNegQuarter(remez, stop_tol, true); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via RHMC | ||||
|   RealD scale = std::sqrt(0.5); | ||||
|   std::vector<RealD> rw_rhmc(Nhits); | ||||
|   ConjugateGradientMultiShift<FermionField> msCG_V(max_iter, PowerQuarter); | ||||
|   ConjugateGradientMultiShift<FermionField> msCG_M(max_iter, PowerNegQuarter); | ||||
|   std::cout.precision(12); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     FermionField Phi    (Ddwf_f.FermionGrid()); | ||||
|     FermionField PhiOdd (Ddwf_f.FermionRedBlackGrid()); | ||||
|     std::vector<FermionField> tmp(2, Ddwf_f.FermionRedBlackGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     pickCheckerboard(Odd, PhiOdd, Phi); | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     msCG_V(VdagV, PhiOdd, tmp[0]); | ||||
|     msCG_M(MdagM, tmp[0], tmp[1]); | ||||
|     rw_rhmc[hit] = norm2(tmp[1]) - norm2(PhiOdd); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- RHMC: Hit " << hit << ": rw = " << rw_rhmc[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Initialize EOFA fermion operators | ||||
|   RealD shift_L = 0.0; | ||||
|   RealD shift_R = -1.0; | ||||
|   int pm = 1; | ||||
|   GparityMobiusEOFAFermionR Deofa_L(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, mf, mb, shift_L, pm, M5, b, c, params); | ||||
|   GparityMobiusEOFAFermionR Deofa_R(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, mf, mb, shift_R, pm, M5, b, c, params); | ||||
|   MdagMLinearOperator<GparityMobiusEOFAFermionR, FermionField> LdagL(Deofa_L); | ||||
|   MdagMLinearOperator<GparityMobiusEOFAFermionR, FermionField> RdagR(Deofa_R); | ||||
|  | ||||
|   // Stochastically estimate reweighting factor via EOFA | ||||
|   RealD k = Deofa_L.k; | ||||
|   std::vector<RealD> rw_eofa(Nhits); | ||||
|   ConjugateGradient<FermionField> CG(stop_tol, max_iter); | ||||
|   SchurRedBlackDiagMooeeSolve<FermionField> SchurSolver(CG); | ||||
|  | ||||
|   // Compute -log(Z), where: ( RHMC det ratio ) = Z * ( EOFA det ratio ) | ||||
|   RealD Z = std::pow(b+c+1.0,Ls) + mf*std::pow(b+c-1.0,Ls); | ||||
|   Z /= std::pow(b+c+1.0,Ls) + mb*std::pow(b+c-1.0,Ls); | ||||
|   Z = -12.0*grid_dim[0]*grid_dim[1]*grid_dim[2]*grid_dim[3]*std::log(Z); | ||||
|  | ||||
|   for(int hit=0; hit<Nhits; hit++){ | ||||
|  | ||||
|     // Gaussian source | ||||
|     FermionField Phi       (Deofa_L.FermionGrid()); | ||||
|     FermionField spProj_Phi(Deofa_L.FermionGrid()); | ||||
|     std::vector<FermionField> tmp(2, Deofa_L.FermionGrid()); | ||||
|     gaussian(RNG5, Phi); | ||||
|     Phi = Phi*scale; | ||||
|  | ||||
|     // evaluate -log(rw) | ||||
|     // LH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pminus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_L.Omega(spProj_Phi, tmp[0], -1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_L, tmp[1], tmp[0]); | ||||
|     Deofa_L.Dtilde(tmp[0], tmp[1]); | ||||
|     Deofa_L.Omega(tmp[1], tmp[0], -1, 1); | ||||
|     rw_eofa[hit] = 2.0*Z - k*innerProduct(spProj_Phi,tmp[0]).real(); | ||||
|  | ||||
|     // RH term | ||||
|     for(int s=0; s<Ls; ++s){ axpby_ssp_pplus(spProj_Phi, 0.0, Phi, 1.0, Phi, s, s); } | ||||
|     Deofa_R.Omega(spProj_Phi, tmp[0], 1, 0); | ||||
|     G5R5(tmp[1], tmp[0]); | ||||
|     tmp[0] = zero; | ||||
|     SchurSolver(Deofa_R, tmp[1], tmp[0]); | ||||
|     Deofa_R.Dtilde(tmp[0], tmp[1]); | ||||
|     Deofa_R.Omega(tmp[1], tmp[0], 1, 1); | ||||
|     rw_eofa[hit] += k*innerProduct(spProj_Phi,tmp[0]).real(); | ||||
|     std::cout << std::endl << "==================================================" << std::endl; | ||||
|     std::cout << " --- EOFA: Hit " << hit << ": rw = " << rw_eofa[hit]; | ||||
|     std::cout << std::endl << "==================================================" << std::endl << std::endl; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   std::vector<RealD> rhmc_result = jack_stats(rw_rhmc); | ||||
|   std::vector<RealD> eofa_result = jack_stats(rw_eofa); | ||||
|   std::cout << std::endl << "RHMC: rw = " << rhmc_result[0] << " +/- " << rhmc_result[1] << std::endl; | ||||
|   std::cout << std::endl << "EOFA: rw = " << eofa_result[0] << " +/- " << eofa_result[1] << std::endl; | ||||
|  | ||||
|   Grid_finalize(); | ||||
| } | ||||
							
								
								
									
										164
									
								
								tests/forces/Test_dwf_force_eofa.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								tests/forces/Test_dwf_force_eofa.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| /************************************************************************************* | ||||
|  | ||||
| Grid physics library, www.github.com/paboyle/Grid | ||||
|  | ||||
| Source file: ./tests/forces/Test_dwf_force_eofa.cc | ||||
|  | ||||
| Copyright (C) 2017 | ||||
|  | ||||
| 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; | ||||
| using namespace Grid::QCD; | ||||
|  | ||||
| int main (int argc, char** argv) | ||||
| { | ||||
|   Grid_init(&argc, &argv); | ||||
|  | ||||
|   std::vector<int> latt_size   = GridDefaultLatt(); | ||||
|   std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); | ||||
|   std::vector<int> 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); | ||||
|   SU3::HotConfiguration(RNG4,U); | ||||
|  | ||||
|   //////////////////////////////////// | ||||
|   // Unmodified matrix element | ||||
|   //////////////////////////////////// | ||||
|   RealD mf = 0.01; | ||||
|   RealD mb = 1.0; | ||||
|   RealD M5 = 1.8; | ||||
|   DomainWallEOFAFermionR Lop(U, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mf, mf, mb, 0.0, -1, M5); | ||||
|   DomainWallEOFAFermionR Rop(U, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mb, mf, mb, -1.0, 1, M5); | ||||
|   OneFlavourRationalParams Params(0.95, 100.0, 5000, 1.0e-12, 12); | ||||
|   ConjugateGradient<LatticeFermion> CG(1.0e-12, 5000); | ||||
|   ExactOneFlavourRatioPseudoFermionAction<WilsonImplR> Meofa(Lop, Rop, CG, Params, true); | ||||
|  | ||||
|   Meofa.refresh(U, RNG5); | ||||
|   RealD S = Meofa.S(U); // pdag M p | ||||
|  | ||||
|   // get the deriv of phidag M phi with respect to "U" | ||||
|   LatticeGaugeField UdSdU(UGrid); | ||||
|   Meofa.deriv(U, UdSdU); | ||||
|  | ||||
|   //////////////////////////////////// | ||||
|   // Modify the gauge field a little | ||||
|   //////////////////////////////////// | ||||
|   RealD dt = 0.0001; | ||||
|  | ||||
|   LatticeColourMatrix mommu(UGrid); | ||||
|   LatticeColourMatrix forcemu(UGrid); | ||||
|   LatticeGaugeField mom(UGrid); | ||||
|   LatticeGaugeField Uprime(UGrid); | ||||
|  | ||||
|   for(int mu=0; mu<Nd; mu++){ | ||||
|  | ||||
|     SU3::GaussianFundamentalLieAlgebraMatrix(RNG4, mommu); // Traceless antihermitian momentum; gaussian in lie alg | ||||
|  | ||||
|     PokeIndex<LorentzIndex>(mom, mommu, mu); | ||||
|  | ||||
|     // fourth order exponential approx | ||||
|     parallel_for(auto i=mom.begin(); i<mom.end(); i++){ | ||||
|       Uprime[i](mu) = U[i](mu) + mom[i](mu)*U[i](mu)*dt + mom[i](mu) *mom[i](mu) *U[i](mu)*(dt*dt/2.0) | ||||
|                         + mom[i](mu) *mom[i](mu) *mom[i](mu) *U[i](mu)*(dt*dt*dt/6.0) | ||||
|                         + mom[i](mu) *mom[i](mu) *mom[i](mu) *mom[i](mu) *U[i](mu)*(dt*dt*dt*dt/24.0) | ||||
|                         + mom[i](mu) *mom[i](mu) *mom[i](mu) *mom[i](mu) *mom[i](mu) *U[i](mu)*(dt*dt*dt*dt*dt/120.0) | ||||
|                         + mom[i](mu) *mom[i](mu) *mom[i](mu) *mom[i](mu) *mom[i](mu) *mom[i](mu) *U[i](mu)*(dt*dt*dt*dt*dt*dt/720.0); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /*Ddwf.ImportGauge(Uprime); | ||||
|   Ddwf.M          (phi,MphiPrime); | ||||
|  | ||||
|   ComplexD Sprime    = innerProduct(MphiPrime   ,MphiPrime);*/ | ||||
|   RealD Sprime = Meofa.S(Uprime); | ||||
|  | ||||
|   ////////////////////////////////////////////// | ||||
|   // Use derivative to estimate dS | ||||
|   ////////////////////////////////////////////// | ||||
|  | ||||
|   LatticeComplex dS(UGrid); | ||||
|   dS = zero; | ||||
|   for(int mu=0; mu<Nd; mu++){ | ||||
|     mommu = PeekIndex<LorentzIndex>(UdSdU, mu); | ||||
|     mommu = Ta(mommu)*2.0; | ||||
|     PokeIndex<LorentzIndex>(UdSdU, mommu, mu); | ||||
|   } | ||||
|  | ||||
|   for(int mu=0; mu<Nd; mu++){ | ||||
|     forcemu = PeekIndex<LorentzIndex>(UdSdU, mu); | ||||
|     mommu   = PeekIndex<LorentzIndex>(mom, mu); | ||||
|  | ||||
|     // Update PF action density | ||||
|     dS = dS + trace(mommu*forcemu)*dt; | ||||
|   } | ||||
|  | ||||
|   ComplexD dSpred = sum(dS); | ||||
|  | ||||
|   /*std::cout << GridLogMessage << " S      " << S << std::endl; | ||||
|   std::cout << GridLogMessage << " Sprime " << Sprime << std::endl; | ||||
|   std::cout << GridLogMessage << "dS      " << Sprime-S << std::endl; | ||||
|   std::cout << GridLogMessage << "predict dS    " << dSpred << std::endl;*/ | ||||
|   printf("\nS = %1.15e\n", S); | ||||
|   printf("Sprime = %1.15e\n", Sprime); | ||||
|   printf("dS = %1.15e\n", Sprime - S); | ||||
|   printf("real(dS_predict) = %1.15e\n", dSpred.real()); | ||||
|   printf("imag(dS_predict) = %1.15e\n\n", dSpred.imag()); | ||||
|  | ||||
|   assert( fabs(real(Sprime-S-dSpred)) < 1.0 ) ; | ||||
|  | ||||
|   std::cout << GridLogMessage << "Done" << std::endl; | ||||
|   Grid_finalize(); | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user