RanluxEngine.cc

Go to the documentation of this file.
00001 // $Id:$
00002 // -*- C++ -*-
00003 //
00004 // -----------------------------------------------------------------------
00005 //                             HEP Random
00006 //                        --- RanluxEngine ---
00007 //                      class implementation file
00008 // -----------------------------------------------------------------------
00009 // This file is part of Geant4 (simulation toolkit for HEP).
00010 //
00011 // Ranlux random number generator originally implemented in FORTRAN77
00012 // by Fred James as part of the MATHLIB HEP library.
00013 // 'RanluxEngine' is designed to fit into the CLHEP random number
00014 // class structure.
00015 
00016 // ===============================================================
00017 // Adeyemi Adesanya - Created: 6th November 1995
00018 // Gabriele Cosmo - Adapted & Revised: 22nd November 1995
00019 // Adeyemi Adesanya - Added setSeeds() method: 2nd February 1996
00020 // Gabriele Cosmo - Added flatArray() method: 8th February 1996
00021 //                - Minor corrections: 31st October 1996
00022 //                - Added methods for engine status: 19th November 1996
00023 //                - Fixed bug in setSeeds(): 15th September 1997
00024 // J.Marraffino   - Added stream operators and related constructor.
00025 //                  Added automatic seed selection from seed table and
00026 //                  engine counter: 14th Feb 1998
00027 //                - Fixed bug: setSeeds() requires a zero terminated
00028 //                  array of seeds: 19th Feb 1998
00029 // Ken Smith      - Added conversion operators:  6th Aug 1998
00030 // J. Marraffino  - Remove dependence on hepString class  13 May 1999
00031 // M. Fischler    - In restore, checkFile for file not found    03 Dec 2004
00032 // M. Fischler    - Methods put, getfor instance save/restore       12/8/04    
00033 // M. Fischler    - split get() into tag validation and 
00034 //                  getState() for anonymous restores           12/27/04    
00035 // M. Fischler    - put/get for vectors of ulongs               3/14/05
00036 // M. Fischler    - State-saving using only ints, for portability 4/12/05
00037 //
00038 // ===============================================================
00039 
00040 #include "CLHEP/Random/Random.h"
00041 #include "CLHEP/Random/RanluxEngine.h"
00042 #include "CLHEP/Random/engineIDulong.h"
00043 #include <string.h>     // for strcmp
00044 #include <cstdlib>      // for std::abs(int)
00045 
00046 namespace CLHEP {
00047 
00048 
00049 static const int MarkerLen = 64; // Enough room to hold a begin or end marker. 
00050 
00051 std::string RanluxEngine::name() const {return "RanluxEngine";}
00052 
00053 // Number of instances with automatic seed selection
00054 int RanluxEngine::numEngines = 0;
00055 
00056 // Maximum index into the seed table
00057 int RanluxEngine::maxIndex = 215;
00058 
00059 RanluxEngine::RanluxEngine(long seed, int lux)
00060 : HepRandomEngine()
00061 {
00062    long seedlist[2]={0,0};
00063 
00064    luxury = lux;
00065    setSeed(seed, luxury);
00066    
00067    // setSeeds() wants a zero terminated array!
00068    seedlist[0]=theSeed;
00069    seedlist[1]=0;
00070    setSeeds(seedlist, luxury);
00071 }
00072 
00073 RanluxEngine::RanluxEngine()
00074 : HepRandomEngine()
00075 {
00076    long seed;
00077    long seedlist[2]={0,0};
00078 
00079    luxury = 3;
00080    int cycle = std::abs(int(numEngines/maxIndex));
00081    int curIndex = std::abs(int(numEngines%maxIndex));
00082    numEngines +=1;
00083    long mask = ((cycle & 0x007fffff) << 8);
00084    HepRandom::getTheTableSeeds( seedlist, curIndex );
00085    seed = seedlist[0]^mask;
00086    setSeed(seed, luxury);
00087    
00088    // setSeeds() wants a zero terminated array!
00089    seedlist[0]=theSeed;
00090    seedlist[1]=0;
00091    setSeeds(seedlist, luxury);
00092 }
00093 
00094 RanluxEngine::RanluxEngine(int rowIndex, int colIndex, int lux)
00095 : HepRandomEngine()
00096 {
00097    long seed;
00098    long seedlist[2]={0,0};
00099 
00100    luxury = lux;
00101    int cycle = std::abs(int(rowIndex/maxIndex));
00102    int row = std::abs(int(rowIndex%maxIndex));
00103    int col = std::abs(int(colIndex%2));
00104    long mask = (( cycle & 0x000007ff ) << 20 );
00105    HepRandom::getTheTableSeeds( seedlist, row );
00106    seed = ( seedlist[col] )^mask;
00107    setSeed(seed, luxury);
00108    
00109    // setSeeds() wants a zero terminated array!
00110    seedlist[0]=theSeed;
00111    seedlist[1]=0;
00112    setSeeds(seedlist, luxury);
00113 }
00114 
00115 RanluxEngine::RanluxEngine( std::istream& is )
00116 : HepRandomEngine()
00117 {
00118   is >> *this;
00119 }
00120 
00121 RanluxEngine::~RanluxEngine() {}
00122 
00123 void RanluxEngine::setSeed(long seed, int lux) {
00124 
00125 // The initialisation is carried out using a Multiplicative
00126 // Congruential generator using formula constants of L'Ecuyer 
00127 // as described in "A review of pseudorandom number generators"
00128 // (Fred James) published in Computer Physics Communications 60 (1990)
00129 // pages 329-344
00130 
00131   const int ecuyer_a = 53668;
00132   const int ecuyer_b = 40014;
00133   const int ecuyer_c = 12211;
00134   const int ecuyer_d = 2147483563;
00135 
00136   const int lux_levels[5] = {0,24,73,199,365};  
00137 
00138   long int_seed_table[24];
00139   long next_seed = seed;
00140   long k_multiple;
00141   int i;
00142   
00143 // number of additional random numbers that need to be 'thrown away'
00144 // every 24 numbers is set using luxury level variable.
00145 
00146   theSeed = seed;
00147   if( (lux > 4)||(lux < 0) ){
00148      if(lux >= 24){
00149         nskip = lux - 24;
00150      }else{
00151         nskip = lux_levels[3]; // corresponds to default luxury level
00152      }
00153   }else{
00154      luxury = lux;
00155      nskip = lux_levels[luxury];
00156   }
00157 
00158    
00159   for(i = 0;i != 24;i++){
00160      k_multiple = next_seed / ecuyer_a;
00161      next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a) 
00162      - k_multiple * ecuyer_c ;
00163      if(next_seed < 0)next_seed += ecuyer_d;
00164      int_seed_table[i] = next_seed % int_modulus;
00165   }     
00166 
00167   for(i = 0;i != 24;i++)
00168     float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
00169 
00170   i_lag = 23;
00171   j_lag = 9;
00172   carry = 0. ;
00173 
00174   if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
00175   
00176   count24 = 0;
00177 }
00178 
00179 void RanluxEngine::setSeeds(const long *seeds, int lux) {
00180 
00181    const int ecuyer_a = 53668;
00182    const int ecuyer_b = 40014;
00183    const int ecuyer_c = 12211;
00184    const int ecuyer_d = 2147483563;
00185 
00186    const int lux_levels[5] = {0,24,73,199,365};
00187    int i;
00188    long int_seed_table[24];
00189    long k_multiple,next_seed;
00190    const long *seedptr; 
00191 
00192    theSeeds = seeds;
00193    seedptr  = seeds;
00194  
00195    if(seeds == 0){
00196       setSeed(theSeed,lux);
00197       theSeeds = &theSeed;
00198       return;
00199    }
00200 
00201    theSeed = *seeds;
00202 
00203 // number of additional random numbers that need to be 'thrown away'
00204 // every 24 numbers is set using luxury level variable.
00205 
00206   if( (lux > 4)||(lux < 0) ){
00207      if(lux >= 24){
00208         nskip = lux - 24;
00209      }else{
00210         nskip = lux_levels[3]; // corresponds to default luxury level
00211      }
00212   }else{
00213      luxury = lux;
00214      nskip = lux_levels[luxury];
00215   }
00216       
00217   for( i = 0;(i != 24)&&(*seedptr != 0);i++){
00218       int_seed_table[i] = *seedptr % int_modulus;
00219       seedptr++;
00220   }                    
00221 
00222   if(i != 24){
00223      next_seed = int_seed_table[i-1];
00224      for(;i != 24;i++){
00225         k_multiple = next_seed / ecuyer_a;
00226         next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a) 
00227         - k_multiple * ecuyer_c ;
00228         if(next_seed < 0)next_seed += ecuyer_d;
00229         int_seed_table[i] = next_seed % int_modulus;
00230      }          
00231   }
00232 
00233   for(i = 0;i != 24;i++)
00234     float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
00235 
00236   i_lag = 23;
00237   j_lag = 9;
00238   carry = 0. ;
00239 
00240   if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
00241   
00242   count24 = 0;
00243 }
00244 
00245 void RanluxEngine::saveStatus( const char filename[] ) const
00246 {
00247    std::ofstream outFile( filename, std::ios::out ) ;
00248   if (!outFile.bad()) {
00249     outFile << "Uvec\n";
00250     std::vector<unsigned long> v = put();
00251     for (unsigned int i=0; i<v.size(); ++i) {
00252       outFile << v[i] << "\n";
00253     }
00254   }
00255 }
00256 
00257 void RanluxEngine::restoreStatus( const char filename[] )
00258 {
00259    std::ifstream inFile( filename, std::ios::in);
00260    if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
00261      std::cerr << "  -- Engine state remains unchanged\n";
00262      return;
00263    }
00264   if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
00265     std::vector<unsigned long> v;
00266     unsigned long xin;
00267     for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
00268       inFile >> xin;
00269       if (!inFile) {
00270         inFile.clear(std::ios::badbit | inFile.rdstate());
00271         std::cerr << "\nRanluxEngine state (vector) description improper."
00272                << "\nrestoreStatus has failed."
00273                << "\nInput stream is probably mispositioned now." << std::endl;
00274         return;
00275       }
00276       v.push_back(xin);
00277     }
00278     getState(v);
00279     return;
00280   }
00281 
00282    if (!inFile.bad() && !inFile.eof()) {
00283 //     inFile >> theSeed;  removed -- encompased by possibleKeywordInput
00284      for (int i=0; i<24; ++i)
00285        inFile >> float_seed_table[i];
00286      inFile >> i_lag; inFile >> j_lag;
00287      inFile >> carry; inFile >> count24;
00288      inFile >> luxury; inFile >> nskip;
00289    }
00290 }
00291 
00292 void RanluxEngine::showStatus() const
00293 {
00294    std::cout << std::endl;
00295    std::cout << "--------- Ranlux engine status ---------" << std::endl;
00296    std::cout << " Initial seed = " << theSeed << std::endl;
00297    std::cout << " float_seed_table[] = ";
00298    for (int i=0; i<24; ++i)
00299      std::cout << float_seed_table[i] << " ";
00300    std::cout << std::endl;
00301    std::cout << " i_lag = " << i_lag << ", j_lag = " << j_lag << std::endl;
00302    std::cout << " carry = " << carry << ", count24 = " << count24 << std::endl;
00303    std::cout << " luxury = " << luxury << " nskip = " << nskip << std::endl;
00304    std::cout << "----------------------------------------" << std::endl;
00305 }
00306 
00307 double RanluxEngine::flat() {
00308 
00309   float next_random;
00310   float uni;
00311   int i;
00312 
00313   uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
00314   if(uni < 0. ){
00315      uni += 1.0;
00316      carry = mantissa_bit_24();
00317   }else{
00318      carry = 0.;
00319   }
00320 
00321   float_seed_table[i_lag] = uni;
00322   i_lag --;
00323   j_lag --;
00324   if(i_lag < 0) i_lag = 23;
00325   if(j_lag < 0) j_lag = 23;
00326 
00327   if( uni < mantissa_bit_12() ){
00328      uni += mantissa_bit_24() * float_seed_table[j_lag];
00329      if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
00330   }
00331   next_random = uni;
00332   count24 ++;
00333 
00334 // every 24th number generation, several random numbers are generated
00335 // and wasted depending upon the luxury level.
00336 
00337   if(count24 == 24 ){
00338      count24 = 0;
00339      for( i = 0; i != nskip ; i++){
00340          uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
00341          if(uni < 0. ){
00342             uni += 1.0;
00343             carry = mantissa_bit_24();
00344          }else{
00345             carry = 0.;
00346          }
00347          float_seed_table[i_lag] = uni;
00348          i_lag --;
00349          j_lag --;
00350          if(i_lag < 0)i_lag = 23;
00351          if(j_lag < 0) j_lag = 23;
00352       }
00353   } 
00354   return (double) next_random;
00355 }
00356 
00357 void RanluxEngine::flatArray(const int size, double* vect)
00358 {
00359   float next_random;
00360   float uni;
00361   int i;
00362   int index;
00363 
00364   for (index=0; index<size; ++index) {
00365     uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
00366     if(uni < 0. ){
00367        uni += 1.0;
00368        carry = mantissa_bit_24();
00369     }else{
00370        carry = 0.;
00371     }
00372 
00373     float_seed_table[i_lag] = uni;
00374     i_lag --;
00375     j_lag --;
00376     if(i_lag < 0) i_lag = 23;
00377     if(j_lag < 0) j_lag = 23;
00378 
00379     if( uni < mantissa_bit_12() ){
00380        uni += mantissa_bit_24() * float_seed_table[j_lag];
00381        if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
00382     }
00383     next_random = uni;
00384     vect[index] = (double)next_random;
00385     count24 ++;
00386 
00387 // every 24th number generation, several random numbers are generated
00388 // and wasted depending upon the luxury level.
00389 
00390     if(count24 == 24 ){
00391        count24 = 0;
00392        for( i = 0; i != nskip ; i++){
00393            uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
00394            if(uni < 0. ){
00395               uni += 1.0;
00396               carry = mantissa_bit_24();
00397            }else{
00398               carry = 0.;
00399            }
00400            float_seed_table[i_lag] = uni;
00401            i_lag --;
00402            j_lag --;
00403            if(i_lag < 0)i_lag = 23;
00404            if(j_lag < 0) j_lag = 23;
00405         }
00406     }
00407   }
00408 } 
00409 
00410 RanluxEngine::operator unsigned int() {
00411    return ((unsigned int)(flat() * exponent_bit_32()) & 0xffffffff) |
00412          (((unsigned int)(float_seed_table[i_lag]*exponent_bit_32())>>16) & 0xff);
00413    // needed because Ranlux doesn't fill all bits of the double
00414    // which therefore doesn't fill all bits of the integer.
00415 }
00416 
00417 std::ostream & RanluxEngine::put ( std::ostream& os ) const
00418 {
00419    char beginMarker[] = "RanluxEngine-begin";
00420   os << beginMarker << "\nUvec\n";
00421   std::vector<unsigned long> v = put();
00422   for (unsigned int i=0; i<v.size(); ++i) {
00423      os <<  v[i] <<  "\n";
00424   }
00425   return os;  
00426 }
00427 
00428 std::vector<unsigned long> RanluxEngine::put () const {
00429   std::vector<unsigned long> v;
00430   v.push_back (engineIDulong<RanluxEngine>());
00431   for (int i=0; i<24; ++i) {
00432     v.push_back
00433         (static_cast<unsigned long>(float_seed_table[i]/mantissa_bit_24()));
00434   }
00435   v.push_back(static_cast<unsigned long>(i_lag));
00436   v.push_back(static_cast<unsigned long>(j_lag));
00437   v.push_back(static_cast<unsigned long>(carry/mantissa_bit_24()));
00438   v.push_back(static_cast<unsigned long>(count24));
00439   v.push_back(static_cast<unsigned long>(luxury));
00440   v.push_back(static_cast<unsigned long>(nskip));
00441   return v;
00442 }
00443 
00444 std::istream & RanluxEngine::get ( std::istream& is )
00445 {
00446   char beginMarker [MarkerLen];
00447   is >> std::ws;
00448   is.width(MarkerLen);  // causes the next read to the char* to be <=
00449                         // that many bytes, INCLUDING A TERMINATION \0 
00450                         // (Stroustrup, section 21.3.2)
00451   is >> beginMarker;
00452   if (strcmp(beginMarker,"RanluxEngine-begin")) {
00453      is.clear(std::ios::badbit | is.rdstate());
00454      std::cerr << "\nInput stream mispositioned or"
00455                << "\nRanluxEngine state description missing or"
00456                << "\nwrong engine type found." << std::endl;
00457      return is;
00458   }
00459   return getState(is);
00460 }
00461 
00462 std::string RanluxEngine::beginTag ( )  { 
00463   return "RanluxEngine-begin"; 
00464 }
00465 
00466 std::istream & RanluxEngine::getState ( std::istream& is )
00467 {
00468   if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
00469     std::vector<unsigned long> v;
00470     unsigned long uu;
00471     for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
00472       is >> uu;
00473       if (!is) {
00474         is.clear(std::ios::badbit | is.rdstate());
00475         std::cerr << "\nRanluxEngine state (vector) description improper."
00476                 << "\ngetState() has failed."
00477                << "\nInput stream is probably mispositioned now." << std::endl;
00478         return is;
00479       }
00480       v.push_back(uu);
00481     }
00482     getState(v);
00483     return (is);
00484   }
00485 
00486 //  is >> theSeed;  Removed, encompassed by possibleKeywordInput()
00487 
00488   char endMarker   [MarkerLen];
00489   for (int i=0; i<24; ++i) {
00490      is >> float_seed_table[i];
00491   }
00492   is >> i_lag; is >>  j_lag;
00493   is >> carry; is >> count24;
00494   is >> luxury; is >> nskip;
00495   is >> std::ws;
00496   is.width(MarkerLen);  
00497   is >> endMarker;
00498   if (strcmp(endMarker,"RanluxEngine-end")) {
00499      is.clear(std::ios::badbit | is.rdstate());
00500      std::cerr << "\nRanluxEngine state description incomplete."
00501                << "\nInput stream is probably mispositioned now." << std::endl;
00502      return is;
00503   }
00504   return is;
00505 }
00506 
00507 bool RanluxEngine::get (const std::vector<unsigned long> & v) {
00508   if ((v[0] & 0xffffffffUL) != engineIDulong<RanluxEngine>()) {
00509     std::cerr << 
00510         "\nRanluxEngine get:state vector has wrong ID word - state unchanged\n";
00511     return false;
00512   }
00513   return getState(v);
00514 }
00515 
00516 bool RanluxEngine::getState (const std::vector<unsigned long> & v) {
00517   if (v.size() != VECTOR_STATE_SIZE ) {
00518     std::cerr << 
00519         "\nRanluxEngine get:state vector has wrong length - state unchanged\n";
00520     return false;
00521   }
00522   for (int i=0; i<24; ++i) {
00523     float_seed_table[i] = v[i+1]*mantissa_bit_24();
00524   }
00525   i_lag    = v[25];
00526   j_lag    = v[26];
00527   carry    = v[27]*mantissa_bit_24();
00528   count24  = v[28];
00529   luxury   = v[29];
00530   nskip    = v[30];
00531   return true;
00532 }
00533 
00534 }  // namespace CLHEP

Generated on Mon May 27 17:50:34 2013 for Geant4 by  doxygen 1.4.7