Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "Random.h" 23 : #include <cmath> 24 : #include <cstdlib> 25 : #include <sstream> 26 : #include <iostream> 27 : #include <iterator> 28 : #include <functional> 29 : 30 : namespace PLMD { 31 : 32 : const double Random::fact=5.9604644775390625e-8; /* 1 / 2^24 */ 33 : const double Random::EPS=3.0e-16; 34 : const double Random::AM=1.0/IM; 35 : const double Random::RNMX=(1.0-EPS); // 1.0-EPS; 36 : const std::string Random::noname="noname"; 37 : 38 808830 : Random::Random(const std::string & name): 39 808830 : switchGaussian(false), 40 808830 : saveGaussian(0.0), 41 : // this is required because if a Random object is created during 42 : // initialization than Random::noname could still be initialized. 43 : // In practice: without this it is not possible to declare 44 : // a static Random object without enforcing the order of the 45 : // static constructors. 46 808830 : name(&name!=&noname?name:"noname") 47 : { 48 808830 : iy=0; 49 26691390 : for(unsigned i=0; i<NTAB; i++) iv[i]=0; 50 808830 : setSeed(0); 51 808830 : } 52 : 53 809870 : void Random::setSeed(int idum_) { 54 809870 : if(idum_>0) idum_=-idum_; 55 809870 : idum=idum_; 56 809870 : incPrec=false; 57 809870 : } 58 : 59 1553149 : double Random::RandU01 () 60 : { 61 1553149 : if (incPrec) 62 1 : return U01d(); 63 : else 64 1553148 : return U01(); 65 : } 66 : 67 : 68 2 : double Random::U01d () 69 : { 70 : double u; 71 2 : u = U01(); 72 2 : u += U01() * fact; 73 2 : return (u < 1.0) ? u : (u - 1.0); 74 : } 75 : 76 5568098 : double Random::U01() { 77 : int j,k; 78 : double temp; 79 5568098 : if (idum <= 0 || !iy) { 80 1637 : if (-idum < 1) idum=1; 81 795 : else idum = -idum; 82 67117 : for (j=NTAB+7; j>=0; j--) { 83 65480 : k=idum/IQ; 84 65480 : idum=IA*(idum-k*IQ)-IR*k; 85 65480 : if (idum < 0) idum += IM; 86 65480 : if (j < NTAB) iv[j] = idum; 87 : } 88 1637 : iy=iv[0]; 89 : } 90 5568098 : k=idum/IQ; 91 5568098 : idum=IA*(idum-k*IQ)-IR*k; 92 5568098 : if (idum < 0) idum += IM; 93 5568098 : j=iy/NDIV; 94 5568098 : iy=iv[j]; 95 5568098 : iv[j] = idum; 96 5568098 : if ((temp=AM*iy) > RNMX) return RNMX; 97 5568098 : else return temp; 98 : } 99 : 100 1 : void Random::WriteStateFull(std::ostream & out)const { 101 : out<<name<<std::endl; 102 1 : out<<idum<<" "<<iy; 103 33 : for(int i=0; i<NTAB; i++) { 104 32 : out<<" "<<iv[i]; 105 : }; 106 1 : out<<" "<<switchGaussian; 107 1 : out<<" "<<saveGaussian; 108 : out<<std::endl; 109 1 : } 110 : 111 0 : void Random::ReadStateFull (std::istream & in) { 112 0 : getline(in,name); 113 0 : in>>idum>>iy; 114 0 : for (int i = 0; i < NTAB; i++) in>>iv[i]; 115 0 : in>>switchGaussian; 116 0 : in>>saveGaussian; 117 0 : } 118 : 119 2 : void Random::toString(std::string & str)const { 120 2 : std::ostringstream ostr; 121 2 : ostr<<idum<<"|"<<iy; 122 66 : for(int i=0; i<NTAB; i++) { 123 64 : ostr<<"|"<<iv[i]; 124 : }; 125 2 : str=ostr.str(); 126 2 : } 127 : 128 2 : void Random::fromString(const std::string & str) { 129 2 : std::string s=str; 130 425 : for(unsigned i=0; i<s.length(); i++) if(s[i]=='|') s[i]=' '; 131 2 : std::istringstream istr(s.c_str()); 132 2 : istr>>idum>>iy; 133 66 : for (int i = 0; i < NTAB; i++) istr>>iv[i]; 134 4 : } 135 : 136 : // This allows to have the same stream of random numbers 137 : // with different compilers: 138 : #ifdef __INTEL_COMPILER 139 : #pragma intel optimization_level 0 140 : #endif 141 : 142 1219087 : double Random::Gaussian() { 143 : double v1,v2,rsq; 144 1219087 : if(switchGaussian) { 145 609517 : switchGaussian=false; 146 609517 : return saveGaussian; 147 : } 148 : while(true) { 149 775900 : v1=2.0*RandU01()-1.0; 150 775900 : v2=2.0*RandU01()-1.0; 151 775900 : rsq=v1*v1+v2*v2; 152 775900 : if(rsq<1.0 && rsq>0.0) break; 153 : } 154 609570 : double fac=std::sqrt(-2.*std::log(rsq)/rsq); 155 609570 : saveGaussian=v1*fac; 156 609570 : switchGaussian=true; 157 609570 : return v2*fac; 158 : } 159 : 160 2 : void Random::Shuffle(std::vector<unsigned>& vec) { 161 : std::iterator_traits<std::vector<unsigned>::iterator >::difference_type i, n; 162 : n = vec.end() - vec.begin(); 163 6 : for(i=n-1; i>0; --i) { 164 4 : std::swap(vec[i], vec[(int)round(RandU01() * IM) % i]); 165 : } 166 2 : } 167 : 168 : 169 : }