Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
RanluxEngine.cc
Go to the documentation of this file.
1// $Id:$
2// -*- C++ -*-
3//
4// -----------------------------------------------------------------------
5// HEP Random
6// --- RanluxEngine ---
7// class implementation file
8// -----------------------------------------------------------------------
9// This file is part of Geant4 (simulation toolkit for HEP).
10//
11// Ranlux random number generator originally implemented in FORTRAN77
12// by Fred James as part of the MATHLIB HEP library.
13// 'RanluxEngine' is designed to fit into the CLHEP random number
14// class structure.
15
16// ===============================================================
17// Adeyemi Adesanya - Created: 6th November 1995
18// Gabriele Cosmo - Adapted & Revised: 22nd November 1995
19// Adeyemi Adesanya - Added setSeeds() method: 2nd February 1996
20// Gabriele Cosmo - Added flatArray() method: 8th February 1996
21// - Minor corrections: 31st October 1996
22// - Added methods for engine status: 19th November 1996
23// - Fixed bug in setSeeds(): 15th September 1997
24// J.Marraffino - Added stream operators and related constructor.
25// Added automatic seed selection from seed table and
26// engine counter: 14th Feb 1998
27// - Fixed bug: setSeeds() requires a zero terminated
28// array of seeds: 19th Feb 1998
29// Ken Smith - Added conversion operators: 6th Aug 1998
30// J. Marraffino - Remove dependence on hepString class 13 May 1999
31// M. Fischler - In restore, checkFile for file not found 03 Dec 2004
32// M. Fischler - Methods put, getfor instance save/restore 12/8/04
33// M. Fischler - split get() into tag validation and
34// getState() for anonymous restores 12/27/04
35// M. Fischler - put/get for vectors of ulongs 3/14/05
36// M. Fischler - State-saving using only ints, for portability 4/12/05
37//
38// ===============================================================
39
40#include "CLHEP/Random/Random.h"
43#include <string.h> // for strcmp
44#include <cstdlib> // for std::abs(int)
45
46namespace CLHEP {
47
48
49static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
50
51std::string RanluxEngine::name() const {return "RanluxEngine";}
52
53// Number of instances with automatic seed selection
54int RanluxEngine::numEngines = 0;
55
56// Maximum index into the seed table
57int RanluxEngine::maxIndex = 215;
58
59RanluxEngine::RanluxEngine(long seed, int lux)
61{
62 long seedlist[2]={0,0};
63
64 luxury = lux;
65 setSeed(seed, luxury);
66
67 // setSeeds() wants a zero terminated array!
68 seedlist[0]=theSeed;
69 seedlist[1]=0;
70 setSeeds(seedlist, luxury);
71}
72
75{
76 long seed;
77 long seedlist[2]={0,0};
78
79 luxury = 3;
80 int cycle = std::abs(int(numEngines/maxIndex));
81 int curIndex = std::abs(int(numEngines%maxIndex));
82 numEngines +=1;
83 long mask = ((cycle & 0x007fffff) << 8);
84 HepRandom::getTheTableSeeds( seedlist, curIndex );
85 seed = seedlist[0]^mask;
86 setSeed(seed, luxury);
87
88 // setSeeds() wants a zero terminated array!
89 seedlist[0]=theSeed;
90 seedlist[1]=0;
91 setSeeds(seedlist, luxury);
92}
93
94RanluxEngine::RanluxEngine(int rowIndex, int colIndex, int lux)
96{
97 long seed;
98 long seedlist[2]={0,0};
99
100 luxury = lux;
101 int cycle = std::abs(int(rowIndex/maxIndex));
102 int row = std::abs(int(rowIndex%maxIndex));
103 int col = std::abs(int(colIndex%2));
104 long mask = (( cycle & 0x000007ff ) << 20 );
105 HepRandom::getTheTableSeeds( seedlist, row );
106 seed = ( seedlist[col] )^mask;
107 setSeed(seed, luxury);
108
109 // setSeeds() wants a zero terminated array!
110 seedlist[0]=theSeed;
111 seedlist[1]=0;
112 setSeeds(seedlist, luxury);
113}
114
115RanluxEngine::RanluxEngine( std::istream& is )
117{
118 is >> *this;
119}
120
122
123void RanluxEngine::setSeed(long seed, int lux) {
124
125// The initialisation is carried out using a Multiplicative
126// Congruential generator using formula constants of L'Ecuyer
127// as described in "A review of pseudorandom number generators"
128// (Fred James) published in Computer Physics Communications 60 (1990)
129// pages 329-344
130
131 const int ecuyer_a = 53668;
132 const int ecuyer_b = 40014;
133 const int ecuyer_c = 12211;
134 const int ecuyer_d = 2147483563;
135
136 const int lux_levels[5] = {0,24,73,199,365};
137
138 long int_seed_table[24];
139 long next_seed = seed;
140 long k_multiple;
141 int i;
142
143// number of additional random numbers that need to be 'thrown away'
144// every 24 numbers is set using luxury level variable.
145
146 theSeed = seed;
147 if( (lux > 4)||(lux < 0) ){
148 if(lux >= 24){
149 nskip = lux - 24;
150 }else{
151 nskip = lux_levels[3]; // corresponds to default luxury level
152 }
153 }else{
154 luxury = lux;
155 nskip = lux_levels[luxury];
156 }
157
158
159 for(i = 0;i != 24;i++){
160 k_multiple = next_seed / ecuyer_a;
161 next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
162 - k_multiple * ecuyer_c ;
163 if(next_seed < 0)next_seed += ecuyer_d;
164 int_seed_table[i] = next_seed % int_modulus;
165 }
166
167 for(i = 0;i != 24;i++)
168 float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
169
170 i_lag = 23;
171 j_lag = 9;
172 carry = 0. ;
173
174 if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
175
176 count24 = 0;
177}
178
179void RanluxEngine::setSeeds(const long *seeds, int lux) {
180
181 const int ecuyer_a = 53668;
182 const int ecuyer_b = 40014;
183 const int ecuyer_c = 12211;
184 const int ecuyer_d = 2147483563;
185
186 const int lux_levels[5] = {0,24,73,199,365};
187 int i;
188 long int_seed_table[24];
189 long k_multiple,next_seed;
190 const long *seedptr;
191
192 theSeeds = seeds;
193 seedptr = seeds;
194
195 if(seeds == 0){
196 setSeed(theSeed,lux);
197 theSeeds = &theSeed;
198 return;
199 }
200
201 theSeed = *seeds;
202
203// number of additional random numbers that need to be 'thrown away'
204// every 24 numbers is set using luxury level variable.
205
206 if( (lux > 4)||(lux < 0) ){
207 if(lux >= 24){
208 nskip = lux - 24;
209 }else{
210 nskip = lux_levels[3]; // corresponds to default luxury level
211 }
212 }else{
213 luxury = lux;
214 nskip = lux_levels[luxury];
215 }
216
217 for( i = 0;(i != 24)&&(*seedptr != 0);i++){
218 int_seed_table[i] = *seedptr % int_modulus;
219 seedptr++;
220 }
221
222 if(i != 24){
223 next_seed = int_seed_table[i-1];
224 for(;i != 24;i++){
225 k_multiple = next_seed / ecuyer_a;
226 next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
227 - k_multiple * ecuyer_c ;
228 if(next_seed < 0)next_seed += ecuyer_d;
229 int_seed_table[i] = next_seed % int_modulus;
230 }
231 }
232
233 for(i = 0;i != 24;i++)
234 float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
235
236 i_lag = 23;
237 j_lag = 9;
238 carry = 0. ;
239
240 if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
241
242 count24 = 0;
243}
244
245void RanluxEngine::saveStatus( const char filename[] ) const
246{
247 std::ofstream outFile( filename, std::ios::out ) ;
248 if (!outFile.bad()) {
249 outFile << "Uvec\n";
250 std::vector<unsigned long> v = put();
251 for (unsigned int i=0; i<v.size(); ++i) {
252 outFile << v[i] << "\n";
253 }
254 }
255}
256
257void RanluxEngine::restoreStatus( const char filename[] )
258{
259 std::ifstream inFile( filename, std::ios::in);
260 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
261 std::cerr << " -- Engine state remains unchanged\n";
262 return;
263 }
264 if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
265 std::vector<unsigned long> v;
266 unsigned long xin;
267 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
268 inFile >> xin;
269 if (!inFile) {
270 inFile.clear(std::ios::badbit | inFile.rdstate());
271 std::cerr << "\nRanluxEngine state (vector) description improper."
272 << "\nrestoreStatus has failed."
273 << "\nInput stream is probably mispositioned now." << std::endl;
274 return;
275 }
276 v.push_back(xin);
277 }
278 getState(v);
279 return;
280 }
281
282 if (!inFile.bad() && !inFile.eof()) {
283// inFile >> theSeed; removed -- encompased by possibleKeywordInput
284 for (int i=0; i<24; ++i)
285 inFile >> float_seed_table[i];
286 inFile >> i_lag; inFile >> j_lag;
287 inFile >> carry; inFile >> count24;
288 inFile >> luxury; inFile >> nskip;
289 }
290}
291
293{
294 std::cout << std::endl;
295 std::cout << "--------- Ranlux engine status ---------" << std::endl;
296 std::cout << " Initial seed = " << theSeed << std::endl;
297 std::cout << " float_seed_table[] = ";
298 for (int i=0; i<24; ++i)
299 std::cout << float_seed_table[i] << " ";
300 std::cout << std::endl;
301 std::cout << " i_lag = " << i_lag << ", j_lag = " << j_lag << std::endl;
302 std::cout << " carry = " << carry << ", count24 = " << count24 << std::endl;
303 std::cout << " luxury = " << luxury << " nskip = " << nskip << std::endl;
304 std::cout << "----------------------------------------" << std::endl;
305}
306
308
309 float next_random;
310 float uni;
311 int i;
312
313 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
314 if(uni < 0. ){
315 uni += 1.0;
316 carry = mantissa_bit_24();
317 }else{
318 carry = 0.;
319 }
320
321 float_seed_table[i_lag] = uni;
322 i_lag --;
323 j_lag --;
324 if(i_lag < 0) i_lag = 23;
325 if(j_lag < 0) j_lag = 23;
326
327 if( uni < mantissa_bit_12() ){
328 uni += mantissa_bit_24() * float_seed_table[j_lag];
329 if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
330 }
331 next_random = uni;
332 count24 ++;
333
334// every 24th number generation, several random numbers are generated
335// and wasted depending upon the luxury level.
336
337 if(count24 == 24 ){
338 count24 = 0;
339 for( i = 0; i != nskip ; i++){
340 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
341 if(uni < 0. ){
342 uni += 1.0;
343 carry = mantissa_bit_24();
344 }else{
345 carry = 0.;
346 }
347 float_seed_table[i_lag] = uni;
348 i_lag --;
349 j_lag --;
350 if(i_lag < 0)i_lag = 23;
351 if(j_lag < 0) j_lag = 23;
352 }
353 }
354 return (double) next_random;
355}
356
357void RanluxEngine::flatArray(const int size, double* vect)
358{
359 float next_random;
360 float uni;
361 int i;
362 int index;
363
364 for (index=0; index<size; ++index) {
365 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
366 if(uni < 0. ){
367 uni += 1.0;
368 carry = mantissa_bit_24();
369 }else{
370 carry = 0.;
371 }
372
373 float_seed_table[i_lag] = uni;
374 i_lag --;
375 j_lag --;
376 if(i_lag < 0) i_lag = 23;
377 if(j_lag < 0) j_lag = 23;
378
379 if( uni < mantissa_bit_12() ){
380 uni += mantissa_bit_24() * float_seed_table[j_lag];
381 if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
382 }
383 next_random = uni;
384 vect[index] = (double)next_random;
385 count24 ++;
386
387// every 24th number generation, several random numbers are generated
388// and wasted depending upon the luxury level.
389
390 if(count24 == 24 ){
391 count24 = 0;
392 for( i = 0; i != nskip ; i++){
393 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
394 if(uni < 0. ){
395 uni += 1.0;
396 carry = mantissa_bit_24();
397 }else{
398 carry = 0.;
399 }
400 float_seed_table[i_lag] = uni;
401 i_lag --;
402 j_lag --;
403 if(i_lag < 0)i_lag = 23;
404 if(j_lag < 0) j_lag = 23;
405 }
406 }
407 }
408}
409
410RanluxEngine::operator unsigned int() {
411 return ((unsigned int)(flat() * exponent_bit_32()) & 0xffffffff) |
412 (((unsigned int)(float_seed_table[i_lag]*exponent_bit_32())>>16) & 0xff);
413 // needed because Ranlux doesn't fill all bits of the double
414 // which therefore doesn't fill all bits of the integer.
415}
416
417std::ostream & RanluxEngine::put ( std::ostream& os ) const
418{
419 char beginMarker[] = "RanluxEngine-begin";
420 os << beginMarker << "\nUvec\n";
421 std::vector<unsigned long> v = put();
422 for (unsigned int i=0; i<v.size(); ++i) {
423 os << v[i] << "\n";
424 }
425 return os;
426}
427
428std::vector<unsigned long> RanluxEngine::put () const {
429 std::vector<unsigned long> v;
430 v.push_back (engineIDulong<RanluxEngine>());
431 for (int i=0; i<24; ++i) {
432 v.push_back
433 (static_cast<unsigned long>(float_seed_table[i]/mantissa_bit_24()));
434 }
435 v.push_back(static_cast<unsigned long>(i_lag));
436 v.push_back(static_cast<unsigned long>(j_lag));
437 v.push_back(static_cast<unsigned long>(carry/mantissa_bit_24()));
438 v.push_back(static_cast<unsigned long>(count24));
439 v.push_back(static_cast<unsigned long>(luxury));
440 v.push_back(static_cast<unsigned long>(nskip));
441 return v;
442}
443
444std::istream & RanluxEngine::get ( std::istream& is )
445{
446 char beginMarker [MarkerLen];
447 is >> std::ws;
448 is.width(MarkerLen); // causes the next read to the char* to be <=
449 // that many bytes, INCLUDING A TERMINATION \0
450 // (Stroustrup, section 21.3.2)
451 is >> beginMarker;
452 if (strcmp(beginMarker,"RanluxEngine-begin")) {
453 is.clear(std::ios::badbit | is.rdstate());
454 std::cerr << "\nInput stream mispositioned or"
455 << "\nRanluxEngine state description missing or"
456 << "\nwrong engine type found." << std::endl;
457 return is;
458 }
459 return getState(is);
460}
461
462std::string RanluxEngine::beginTag ( ) {
463 return "RanluxEngine-begin";
464}
465
466std::istream & RanluxEngine::getState ( std::istream& is )
467{
468 if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
469 std::vector<unsigned long> v;
470 unsigned long uu;
471 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
472 is >> uu;
473 if (!is) {
474 is.clear(std::ios::badbit | is.rdstate());
475 std::cerr << "\nRanluxEngine state (vector) description improper."
476 << "\ngetState() has failed."
477 << "\nInput stream is probably mispositioned now." << std::endl;
478 return is;
479 }
480 v.push_back(uu);
481 }
482 getState(v);
483 return (is);
484 }
485
486// is >> theSeed; Removed, encompassed by possibleKeywordInput()
487
488 char endMarker [MarkerLen];
489 for (int i=0; i<24; ++i) {
490 is >> float_seed_table[i];
491 }
492 is >> i_lag; is >> j_lag;
493 is >> carry; is >> count24;
494 is >> luxury; is >> nskip;
495 is >> std::ws;
496 is.width(MarkerLen);
497 is >> endMarker;
498 if (strcmp(endMarker,"RanluxEngine-end")) {
499 is.clear(std::ios::badbit | is.rdstate());
500 std::cerr << "\nRanluxEngine state description incomplete."
501 << "\nInput stream is probably mispositioned now." << std::endl;
502 return is;
503 }
504 return is;
505}
506
507bool RanluxEngine::get (const std::vector<unsigned long> & v) {
508 if ((v[0] & 0xffffffffUL) != engineIDulong<RanluxEngine>()) {
509 std::cerr <<
510 "\nRanluxEngine get:state vector has wrong ID word - state unchanged\n";
511 return false;
512 }
513 return getState(v);
514}
515
516bool RanluxEngine::getState (const std::vector<unsigned long> & v) {
517 if (v.size() != VECTOR_STATE_SIZE ) {
518 std::cerr <<
519 "\nRanluxEngine get:state vector has wrong length - state unchanged\n";
520 return false;
521 }
522 for (int i=0; i<24; ++i) {
523 float_seed_table[i] = v[i+1]*mantissa_bit_24();
524 }
525 i_lag = v[25];
526 j_lag = v[26];
527 carry = v[27]*mantissa_bit_24();
528 count24 = v[28];
529 luxury = v[29];
530 nskip = v[30];
531 return true;
532}
533
534} // namespace CLHEP
static double mantissa_bit_12()
static bool checkFile(std::istream &file, const std::string &filename, const std::string &classname, const std::string &methodname)
Definition: RandomEngine.cc:45
static double mantissa_bit_24()
static void getTheTableSeeds(long *seeds, int index)
Definition: Random.cc:151
static const unsigned int VECTOR_STATE_SIZE
Definition: RanluxEngine.h:108
void flatArray(const int size, double *vect)
std::string name() const
Definition: RanluxEngine.cc:51
virtual std::istream & getState(std::istream &is)
void saveStatus(const char filename[]="Ranlux.conf") const
std::vector< unsigned long > put() const
void setSeeds(const long *seeds, int lux=3)
static std::string beginTag()
virtual std::istream & get(std::istream &is)
void showStatus() const
void setSeed(long seed, int lux=3)
void restoreStatus(const char filename[]="Ranlux.conf")
static std::string engineName()
Definition: RanluxEngine.h:102
Definition: DoubConv.h:17
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:167