mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-11-03 21:44:33 +00:00 
			
		
		
		
	HMC bit repro across checkpoints. Fixed parallel RNG issue with threading.
Conclusion: c++11 distributions not thread safe and must us distinct dist as well as distinct engine per site. Makes sense when you think of box muller. Also added a reset of dist on fill to ensure repro across checkpoints.
This commit is contained in:
		@@ -22,13 +22,16 @@ namespace Grid {
 | 
			
		||||
      assert(fine->_processors[d]==1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // local and global volumes subdivide cleanly after SIMDization
 | 
			
		||||
    int multiplicity=1;
 | 
			
		||||
    for(int d=0;d<lowerdims;d++){
 | 
			
		||||
      multiplicity=multiplicity*fine->_rdimensions[d];
 | 
			
		||||
    }
 | 
			
		||||
    // local and global volumes subdivide cleanly after SIMDization
 | 
			
		||||
    for(int d=0;d<rngdims;d++){
 | 
			
		||||
      int fd= d+lowerdims;
 | 
			
		||||
      assert(coarse->_processors[d]  == fine->_processors[fd]);
 | 
			
		||||
      assert(coarse->_simd_layout[d] == fine->_simd_layout[fd]);
 | 
			
		||||
      assert((fine->_rdimensions[fd] / coarse->_rdimensions[d])* coarse->_rdimensions[d]==fine->_rdimensions[fd]); 
 | 
			
		||||
      assert(((fine->_rdimensions[fd] / coarse->_rdimensions[d])* coarse->_rdimensions[d])==fine->_rdimensions[fd]); 
 | 
			
		||||
 | 
			
		||||
      multiplicity = multiplicity *fine->_rdimensions[fd] / coarse->_rdimensions[d]; 
 | 
			
		||||
    }
 | 
			
		||||
@@ -76,8 +79,6 @@ namespace Grid {
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
 | 
			
		||||
   GridRNGbase() : _uniform{0,1}, _gaussian(0.0,1.0) {};
 | 
			
		||||
 | 
			
		||||
    int _seeded;
 | 
			
		||||
    // One generator per site.
 | 
			
		||||
    // Uniform and Gaussian distributions from these generators.
 | 
			
		||||
@@ -91,13 +92,12 @@ namespace Grid {
 | 
			
		||||
    static const int     RngStateCount = std::mt19937::state_size;
 | 
			
		||||
#endif
 | 
			
		||||
    std::vector<RngEngine>             _generators;
 | 
			
		||||
    std::uniform_real_distribution<double> _uniform;
 | 
			
		||||
    std::normal_distribution<double>       _gaussian;
 | 
			
		||||
    std::vector<std::uniform_real_distribution<RealD> > _uniform;
 | 
			
		||||
    std::vector<std::normal_distribution<RealD> >       _gaussian;
 | 
			
		||||
 | 
			
		||||
    void GetState(std::vector<RngStateType> & saved,int gen) {
 | 
			
		||||
      saved.resize(RngStateCount);
 | 
			
		||||
      std::stringstream ss;
 | 
			
		||||
      //      std::cout << _generators[gen]<<std::endl;
 | 
			
		||||
      ss<<_generators[gen];
 | 
			
		||||
      ss.seekg(0,ss.beg);
 | 
			
		||||
      for(int i=0;i<RngStateCount;i++){
 | 
			
		||||
@@ -112,7 +112,6 @@ namespace Grid {
 | 
			
		||||
      }
 | 
			
		||||
      ss.seekg(0,ss.beg);
 | 
			
		||||
      ss>>_generators[gen];
 | 
			
		||||
      //      std::cout << _generators[gen]<<std::endl;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -132,12 +131,14 @@ namespace Grid {
 | 
			
		||||
 | 
			
		||||
    GridSerialRNG() : GridRNGbase() {
 | 
			
		||||
      _generators.resize(1);
 | 
			
		||||
      _uniform.resize(1,std::uniform_real_distribution<RealD>{0,1});
 | 
			
		||||
      _gaussian.resize(1,std::normal_distribution<RealD>(0.0,1.0) );
 | 
			
		||||
      _seeded=0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template <class sobj,class distribution> inline void fill(sobj &l,distribution &dist){
 | 
			
		||||
    template <class sobj,class distribution> inline void fill(sobj &l,std::vector<distribution> &dist){
 | 
			
		||||
 | 
			
		||||
      typedef typename sobj::scalar_type scalar_type;
 | 
			
		||||
 
 | 
			
		||||
@@ -145,56 +146,65 @@ namespace Grid {
 | 
			
		||||
 | 
			
		||||
      scalar_type *buf = (scalar_type *) & l;
 | 
			
		||||
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      for(int idx=0;idx<words;idx++){
 | 
			
		||||
	fillScalar(buf[idx],dist,_generators[0]);
 | 
			
		||||
	fillScalar(buf[idx],dist[0],_generators[0]);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <class distribution>  inline void fill(ComplexF &l,distribution &dist){
 | 
			
		||||
      fillScalar(l,dist,_generators[0]);
 | 
			
		||||
    template <class distribution>  inline void fill(ComplexF &l,std::vector<distribution> &dist){
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      fillScalar(l,dist[0],_generators[0]);
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    template <class distribution>  inline void fill(ComplexD &l,distribution &dist){
 | 
			
		||||
      fillScalar(l,dist,_generators[0]);
 | 
			
		||||
    template <class distribution>  inline void fill(ComplexD &l,std::vector<distribution> &dist){
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      fillScalar(l,dist[0],_generators[0]);
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    template <class distribution>  inline void fill(RealF &l,distribution &dist){
 | 
			
		||||
      fillScalar(l,dist,_generators[0]);
 | 
			
		||||
    template <class distribution>  inline void fill(RealF &l,std::vector<distribution> &dist){
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      fillScalar(l,dist[0],_generators[0]);
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    template <class distribution>  inline void fill(RealD &l,distribution &dist){
 | 
			
		||||
      fillScalar(l,dist,_generators[0]);
 | 
			
		||||
    template <class distribution>  inline void fill(RealD &l,std::vector<distribution> &dist){
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      fillScalar(l,dist[0],_generators[0]);
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    // vector fill
 | 
			
		||||
    template <class distribution>  inline void fill(vComplexF &l,distribution &dist){
 | 
			
		||||
    template <class distribution>  inline void fill(vComplexF &l,std::vector<distribution> &dist){
 | 
			
		||||
      RealF *pointer=(RealF *)&l;
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      for(int i=0;i<2*vComplexF::Nsimd();i++){
 | 
			
		||||
	fillScalar(pointer[i],dist,_generators[0]);
 | 
			
		||||
	fillScalar(pointer[i],dist[0],_generators[0]);
 | 
			
		||||
      }
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    template <class distribution>  inline void fill(vComplexD &l,distribution &dist){
 | 
			
		||||
    template <class distribution>  inline void fill(vComplexD &l,std::vector<distribution> &dist){
 | 
			
		||||
      RealD *pointer=(RealD *)&l;
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      for(int i=0;i<2*vComplexD::Nsimd();i++){
 | 
			
		||||
	fillScalar(pointer[i],dist,_generators[0]);
 | 
			
		||||
	fillScalar(pointer[i],dist[0],_generators[0]);
 | 
			
		||||
      }
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    template <class distribution>  inline void fill(vRealF &l,distribution &dist){
 | 
			
		||||
    template <class distribution>  inline void fill(vRealF &l,std::vector<distribution> &dist){
 | 
			
		||||
      RealF *pointer=(RealF *)&l;
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      for(int i=0;i<vRealF::Nsimd();i++){
 | 
			
		||||
	fillScalar(pointer[i],dist,_generators[0]);
 | 
			
		||||
	fillScalar(pointer[i],dist[0],_generators[0]);
 | 
			
		||||
      }
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
    template <class distribution>  inline void fill(vRealD &l,distribution &dist){
 | 
			
		||||
    template <class distribution>  inline void fill(vRealD &l,std::vector<distribution> &dist){
 | 
			
		||||
      RealD *pointer=(RealD *)&l;
 | 
			
		||||
      dist[0].reset();
 | 
			
		||||
      for(int i=0;i<vRealD::Nsimd();i++){
 | 
			
		||||
	fillScalar(pointer[i],dist,_generators[0]);
 | 
			
		||||
	fillScalar(pointer[i],dist[0],_generators[0]);
 | 
			
		||||
      }
 | 
			
		||||
      CartesianCommunicator::BroadcastWorld(0,(void *)&l,sizeof(l));
 | 
			
		||||
    }
 | 
			
		||||
@@ -213,10 +223,6 @@ namespace Grid {
 | 
			
		||||
 | 
			
		||||
  class GridParallelRNG : public GridRNGbase {
 | 
			
		||||
  public:
 | 
			
		||||
    
 | 
			
		||||
    // Uniform and Gaussian distributions from these generators.
 | 
			
		||||
    std::uniform_real_distribution<double> _uniform;
 | 
			
		||||
    std::normal_distribution<double>       _gaussian;
 | 
			
		||||
 | 
			
		||||
    GridBase *_grid;
 | 
			
		||||
    int _vol;
 | 
			
		||||
@@ -228,7 +234,10 @@ namespace Grid {
 | 
			
		||||
    GridParallelRNG(GridBase *grid) : GridRNGbase() {
 | 
			
		||||
      _grid=grid;
 | 
			
		||||
      _vol =_grid->iSites()*_grid->oSites();
 | 
			
		||||
 | 
			
		||||
      _generators.resize(_vol);
 | 
			
		||||
      _uniform.resize(_vol,std::uniform_real_distribution<RealD>{0,1});
 | 
			
		||||
      _gaussian.resize(_vol,std::normal_distribution<RealD>(0.0,1.0) );
 | 
			
		||||
      _seeded=0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -277,7 +286,7 @@ namespace Grid {
 | 
			
		||||
    //void SaveState(const std::string<char> &file);
 | 
			
		||||
    //void LoadState(const std::string<char> &file);
 | 
			
		||||
 | 
			
		||||
    template <class vobj,class distribution> inline void fill(Lattice<vobj> &l,distribution &dist){
 | 
			
		||||
    template <class vobj,class distribution> inline void fill(Lattice<vobj> &l,std::vector<distribution> &dist){
 | 
			
		||||
 | 
			
		||||
      typedef typename vobj::scalar_object scalar_object;
 | 
			
		||||
      typedef typename vobj::scalar_type scalar_type;
 | 
			
		||||
@@ -301,8 +310,9 @@ PARALLEL_FOR_LOOP
 | 
			
		||||
	  for(int si=0;si<Nsimd;si++){
 | 
			
		||||
	    int gdx = generator_idx(ss,si); // index of generator state
 | 
			
		||||
	    scalar_type *pointer = (scalar_type *)&buf[si];
 | 
			
		||||
	    dist[gdx].reset();
 | 
			
		||||
	    for(int idx=0;idx<words;idx++){
 | 
			
		||||
	      fillScalar(pointer[idx],dist,_generators[gdx]);
 | 
			
		||||
	      fillScalar(pointer[idx],dist[gdx],_generators[gdx]);
 | 
			
		||||
	    }
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user