Files
geant4/source/externals/clhep/src/RanluxEngine.cc
T
2020-12-04 12:30:43 +01:00

550 lines
15 KiB
C++

// -*- C++ -*-
//
// -----------------------------------------------------------------------
// HEP Random
// --- RanluxEngine ---
// class implementation file
// -----------------------------------------------------------------------
// This file is part of Geant4 (simulation toolkit for HEP).
//
// Ranlux random number generator originally implemented in FORTRAN77
// by Fred James as part of the MATHLIB HEP library.
// 'RanluxEngine' is designed to fit into the CLHEP random number
// class structure.
// ===============================================================
// Adeyemi Adesanya - Created: 6th November 1995
// Gabriele Cosmo - Adapted & Revised: 22nd November 1995
// Adeyemi Adesanya - Added setSeeds() method: 2nd February 1996
// Gabriele Cosmo - Added flatArray() method: 8th February 1996
// - Minor corrections: 31st October 1996
// - Added methods for engine status: 19th November 1996
// - Fixed bug in setSeeds(): 15th September 1997
// J.Marraffino - Added stream operators and related constructor.
// Added automatic seed selection from seed table and
// engine counter: 14th Feb 1998
// - Fixed bug: setSeeds() requires a zero terminated
// array of seeds: 19th Feb 1998
// Ken Smith - Added conversion operators: 6th Aug 1998
// J. Marraffino - Remove dependence on hepString class 13 May 1999
// M. Fischler - In restore, checkFile for file not found 03 Dec 2004
// M. Fischler - Methods put, getfor instance save/restore 12/8/04
// M. Fischler - split get() into tag validation and
// getState() for anonymous restores 12/27/04
// M. Fischler - put/get for vectors of ulongs 3/14/05
// M. Fischler - State-saving using only ints, for portability 4/12/05
//
// ===============================================================
#include "CLHEP/Random/Random.h"
#include "CLHEP/Random/RanluxEngine.h"
#include "CLHEP/Random/engineIDulong.h"
#include "CLHEP/Utility/atomic_int.h"
#include <atomic>
#include <cstdlib> // for std::abs(int)
#include <iostream>
#include <string.h> // for strcmp
#include <string>
#include <vector>
namespace CLHEP {
namespace {
// Number of instances with automatic seed selection
CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
// Maximum index into the seed table
const int maxIndex = 215;
}
static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
std::string RanluxEngine::name() const {return "RanluxEngine";}
RanluxEngine::RanluxEngine(long seed, int lux)
: HepRandomEngine()
{
long seedlist[2]={0,0};
luxury = lux;
setSeed(seed, luxury);
// setSeeds() wants a zero terminated array!
seedlist[0]=theSeed;
seedlist[1]=0;
setSeeds(seedlist, luxury);
}
RanluxEngine::RanluxEngine()
: HepRandomEngine()
{
long seed;
long seedlist[2]={0,0};
luxury = 3;
int numEngines = numberOfEngines++;
int cycle = std::abs(int(numEngines/maxIndex));
int curIndex = std::abs(int(numEngines%maxIndex));
long mask = ((cycle & 0x007fffff) << 8);
HepRandom::getTheTableSeeds( seedlist, curIndex );
seed = seedlist[0]^mask;
setSeed(seed, luxury);
// setSeeds() wants a zero terminated array!
seedlist[0]=theSeed;
seedlist[1]=0;
setSeeds(seedlist, luxury);
}
RanluxEngine::RanluxEngine(int rowIndex, int colIndex, int lux)
: HepRandomEngine()
{
long seed;
long seedlist[2]={0,0};
luxury = lux;
int cycle = std::abs(int(rowIndex/maxIndex));
int row = std::abs(int(rowIndex%maxIndex));
int col = std::abs(int(colIndex%2));
long mask = (( cycle & 0x000007ff ) << 20 );
HepRandom::getTheTableSeeds( seedlist, row );
seed = ( seedlist[col] )^mask;
setSeed(seed, luxury);
// setSeeds() wants a zero terminated array!
seedlist[0]=theSeed;
seedlist[1]=0;
setSeeds(seedlist, luxury);
}
RanluxEngine::RanluxEngine( std::istream& is )
: HepRandomEngine()
{
is >> *this;
}
RanluxEngine::~RanluxEngine() {}
void RanluxEngine::setSeed(long seed, int lux) {
// The initialisation is carried out using a Multiplicative
// Congruential generator using formula constants of L'Ecuyer
// as described in "A review of pseudorandom number generators"
// (Fred James) published in Computer Physics Communications 60 (1990)
// pages 329-344
const int ecuyer_a = 53668;
const int ecuyer_b = 40014;
const int ecuyer_c = 12211;
const int ecuyer_d = 2147483563;
const int lux_levels[5] = {0,24,73,199,365};
long int_seed_table[24];
long next_seed = seed;
long k_multiple;
int i;
// number of additional random numbers that need to be 'thrown away'
// every 24 numbers is set using luxury level variable.
theSeed = seed;
if( (lux > 4)||(lux < 0) ){
if(lux >= 24){
nskip = lux - 24;
}else{
nskip = lux_levels[3]; // corresponds to default luxury level
}
}else{
luxury = lux;
nskip = lux_levels[luxury];
}
for(i = 0;i != 24;i++){
k_multiple = next_seed / ecuyer_a;
next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
- k_multiple * ecuyer_c ;
if(next_seed < 0)next_seed += ecuyer_d;
int_seed_table[i] = next_seed % int_modulus;
}
for(i = 0;i != 24;i++)
float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
i_lag = 23;
j_lag = 9;
carry = 0. ;
if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
count24 = 0;
}
void RanluxEngine::setSeeds(const long *seeds, int lux) {
const int ecuyer_a = 53668;
const int ecuyer_b = 40014;
const int ecuyer_c = 12211;
const int ecuyer_d = 2147483563;
const int lux_levels[5] = {0,24,73,199,365};
int i;
long int_seed_table[24];
long k_multiple,next_seed;
const long *seedptr;
theSeeds = seeds;
seedptr = seeds;
if(seeds == 0){
setSeed(theSeed,lux);
theSeeds = &theSeed;
return;
}
theSeed = *seeds;
// number of additional random numbers that need to be 'thrown away'
// every 24 numbers is set using luxury level variable.
if( (lux > 4)||(lux < 0) ){
if(lux >= 24){
nskip = lux - 24;
}else{
nskip = lux_levels[3]; // corresponds to default luxury level
}
}else{
luxury = lux;
nskip = lux_levels[luxury];
}
for( i = 0;(i != 24)&&(*seedptr != 0);i++){
int_seed_table[i] = *seedptr % int_modulus;
seedptr++;
}
if(i != 24){
next_seed = int_seed_table[i-1];
for(;i != 24;i++){
k_multiple = next_seed / ecuyer_a;
next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
- k_multiple * ecuyer_c ;
if(next_seed < 0)next_seed += ecuyer_d;
int_seed_table[i] = next_seed % int_modulus;
}
}
for(i = 0;i != 24;i++)
float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
i_lag = 23;
j_lag = 9;
carry = 0. ;
if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
count24 = 0;
}
void RanluxEngine::saveStatus( const char filename[] ) const
{
std::ofstream outFile( filename, std::ios::out ) ;
if (!outFile.bad()) {
outFile << "Uvec\n";
std::vector<unsigned long> v = put();
for (unsigned int i=0; i<v.size(); ++i) {
outFile << v[i] << "\n";
}
}
}
void RanluxEngine::restoreStatus( const char filename[] )
{
std::ifstream inFile( filename, std::ios::in);
if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
std::cerr << " -- Engine state remains unchanged\n";
return;
}
if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
std::vector<unsigned long> v;
unsigned long xin;
for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
inFile >> xin;
if (!inFile) {
inFile.clear(std::ios::badbit | inFile.rdstate());
std::cerr << "\nRanluxEngine state (vector) description improper."
<< "\nrestoreStatus has failed."
<< "\nInput stream is probably mispositioned now." << std::endl;
return;
}
v.push_back(xin);
}
getState(v);
return;
}
if (!inFile.bad() && !inFile.eof()) {
// inFile >> theSeed; removed -- encompased by possibleKeywordInput
for (int i=0; i<24; ++i)
inFile >> float_seed_table[i];
inFile >> i_lag; inFile >> j_lag;
inFile >> carry; inFile >> count24;
inFile >> luxury; inFile >> nskip;
}
}
void RanluxEngine::showStatus() const
{
std::cout << std::endl;
std::cout << "--------- Ranlux engine status ---------" << std::endl;
std::cout << " Initial seed = " << theSeed << std::endl;
std::cout << " float_seed_table[] = ";
for (int i=0; i<24; ++i)
std::cout << float_seed_table[i] << " ";
std::cout << std::endl;
std::cout << " i_lag = " << i_lag << ", j_lag = " << j_lag << std::endl;
std::cout << " carry = " << carry << ", count24 = " << count24 << std::endl;
std::cout << " luxury = " << luxury << " nskip = " << nskip << std::endl;
std::cout << "----------------------------------------" << std::endl;
}
double RanluxEngine::flat() {
float next_random;
float uni;
int i;
uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
if(uni < 0. ){
uni += 1.0;
carry = mantissa_bit_24();
}else{
carry = 0.;
}
float_seed_table[i_lag] = uni;
i_lag --;
j_lag --;
if(i_lag < 0) i_lag = 23;
if(j_lag < 0) j_lag = 23;
if( uni < mantissa_bit_12() ){
uni += mantissa_bit_24() * float_seed_table[j_lag];
if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
}
next_random = uni;
count24 ++;
// every 24th number generation, several random numbers are generated
// and wasted depending upon the luxury level.
if(count24 == 24 ){
count24 = 0;
for( i = 0; i != nskip ; i++){
uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
if(uni < 0. ){
uni += 1.0;
carry = mantissa_bit_24();
}else{
carry = 0.;
}
float_seed_table[i_lag] = uni;
i_lag --;
j_lag --;
if(i_lag < 0)i_lag = 23;
if(j_lag < 0) j_lag = 23;
}
}
return (double) next_random;
}
void RanluxEngine::flatArray(const int size, double* vect)
{
float next_random;
float uni;
int i;
int index;
for (index=0; index<size; ++index) {
uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
if(uni < 0. ){
uni += 1.0;
carry = mantissa_bit_24();
}else{
carry = 0.;
}
float_seed_table[i_lag] = uni;
i_lag --;
j_lag --;
if(i_lag < 0) i_lag = 23;
if(j_lag < 0) j_lag = 23;
if( uni < mantissa_bit_12() ){
uni += mantissa_bit_24() * float_seed_table[j_lag];
if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
}
next_random = uni;
vect[index] = (double)next_random;
count24 ++;
// every 24th number generation, several random numbers are generated
// and wasted depending upon the luxury level.
if(count24 == 24 ){
count24 = 0;
for( i = 0; i != nskip ; i++){
uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
if(uni < 0. ){
uni += 1.0;
carry = mantissa_bit_24();
}else{
carry = 0.;
}
float_seed_table[i_lag] = uni;
i_lag --;
j_lag --;
if(i_lag < 0)i_lag = 23;
if(j_lag < 0) j_lag = 23;
}
}
}
}
RanluxEngine::operator double() {
return flat();
}
RanluxEngine::operator float() {
return float( flat() );
}
RanluxEngine::operator unsigned int() {
return ((unsigned int)(flat() * exponent_bit_32()) & 0xffffffff) |
(((unsigned int)(float_seed_table[i_lag]*exponent_bit_32())>>16) & 0xff);
// needed because Ranlux doesn't fill all bits of the double
// which therefore doesn't fill all bits of the integer.
}
std::ostream & RanluxEngine::put ( std::ostream& os ) const
{
char beginMarker[] = "RanluxEngine-begin";
os << beginMarker << "\nUvec\n";
std::vector<unsigned long> v = put();
for (unsigned int i=0; i<v.size(); ++i) {
os << v[i] << "\n";
}
return os;
}
std::vector<unsigned long> RanluxEngine::put () const {
std::vector<unsigned long> v;
v.push_back (engineIDulong<RanluxEngine>());
for (int i=0; i<24; ++i) {
v.push_back
(static_cast<unsigned long>(float_seed_table[i]/mantissa_bit_24()));
}
v.push_back(static_cast<unsigned long>(i_lag));
v.push_back(static_cast<unsigned long>(j_lag));
v.push_back(static_cast<unsigned long>(carry/mantissa_bit_24()));
v.push_back(static_cast<unsigned long>(count24));
v.push_back(static_cast<unsigned long>(luxury));
v.push_back(static_cast<unsigned long>(nskip));
return v;
}
std::istream & RanluxEngine::get ( std::istream& is )
{
char beginMarker [MarkerLen];
is >> std::ws;
is.width(MarkerLen); // causes the next read to the char* to be <=
// that many bytes, INCLUDING A TERMINATION \0
// (Stroustrup, section 21.3.2)
is >> beginMarker;
if (strcmp(beginMarker,"RanluxEngine-begin")) {
is.clear(std::ios::badbit | is.rdstate());
std::cerr << "\nInput stream mispositioned or"
<< "\nRanluxEngine state description missing or"
<< "\nwrong engine type found." << std::endl;
return is;
}
return getState(is);
}
std::string RanluxEngine::beginTag ( ) {
return "RanluxEngine-begin";
}
std::istream & RanluxEngine::getState ( std::istream& is )
{
if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
std::vector<unsigned long> v;
unsigned long uu;
for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
is >> uu;
if (!is) {
is.clear(std::ios::badbit | is.rdstate());
std::cerr << "\nRanluxEngine state (vector) description improper."
<< "\ngetState() has failed."
<< "\nInput stream is probably mispositioned now." << std::endl;
return is;
}
v.push_back(uu);
}
getState(v);
return (is);
}
// is >> theSeed; Removed, encompassed by possibleKeywordInput()
char endMarker [MarkerLen];
for (int i=0; i<24; ++i) {
is >> float_seed_table[i];
}
is >> i_lag; is >> j_lag;
is >> carry; is >> count24;
is >> luxury; is >> nskip;
is >> std::ws;
is.width(MarkerLen);
is >> endMarker;
if (strcmp(endMarker,"RanluxEngine-end")) {
is.clear(std::ios::badbit | is.rdstate());
std::cerr << "\nRanluxEngine state description incomplete."
<< "\nInput stream is probably mispositioned now." << std::endl;
return is;
}
return is;
}
bool RanluxEngine::get (const std::vector<unsigned long> & v) {
if ((v[0] & 0xffffffffUL) != engineIDulong<RanluxEngine>()) {
std::cerr <<
"\nRanluxEngine get:state vector has wrong ID word - state unchanged\n";
return false;
}
return getState(v);
}
bool RanluxEngine::getState (const std::vector<unsigned long> & v) {
if (v.size() != VECTOR_STATE_SIZE ) {
std::cerr <<
"\nRanluxEngine get:state vector has wrong length - state unchanged\n";
return false;
}
for (int i=0; i<24; ++i) {
float_seed_table[i] = v[i+1]*mantissa_bit_24();
}
i_lag = v[25];
j_lag = v[26];
carry = v[27]*mantissa_bit_24();
count24 = v[28];
luxury = v[29];
nskip = v[30];
return true;
}
} // namespace CLHEP