CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
RanluxEngine.cc
Go to the documentation of this file.
1//
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/defs.h"
41#include "CLHEP/Random/Random.h"
42#include "CLHEP/Random/RanluxEngine.h"
43#include "CLHEP/Random/engineIDulong.h"
44#include "CLHEP/Utility/atomic_int.h"
45
46#include <atomic>
47#include <cstdlib> // for std::abs(int)
48#include <iostream>
49#include <string.h> // for strcmp
50#include <string>
51#include <vector>
52
53#ifdef TRACE_IO
54 #include "CLHEP/Random/DoubConv.h"
55 bool flat_trace = false;
56#endif
57
58namespace CLHEP {
59
60namespace {
61 // Number of instances with automatic seed selection
62 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
63
64 // Maximum index into the seed table
65 const int maxIndex = 215;
66}
67
68static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
69
70std::string RanluxEngine::name() const {return "RanluxEngine";}
71
72RanluxEngine::RanluxEngine(long seed, int lux)
74{
75 long seedlist[2]={0,0};
76
77 luxury = lux;
78 setSeed(seed, luxury);
79
80 // setSeeds() wants a zero terminated array!
81 seedlist[0]=theSeed;
82 seedlist[1]=0;
83 setSeeds(seedlist, luxury);
84}
85
88{
89 long seed;
90 long seedlist[2]={0,0};
91
92 luxury = 3;
93 int numEngines = numberOfEngines++;
94 int cycle = std::abs(int(numEngines/maxIndex));
95 int curIndex = std::abs(int(numEngines%maxIndex));
96
97 long mask = ((cycle & 0x007fffff) << 8);
98 HepRandom::getTheTableSeeds( seedlist, curIndex );
99 seed = seedlist[0]^mask;
100 setSeed(seed, luxury);
101
102 // setSeeds() wants a zero terminated array!
103 seedlist[0]=theSeed;
104 seedlist[1]=0;
105 setSeeds(seedlist, luxury);
106}
107
108RanluxEngine::RanluxEngine(int rowIndex, int colIndex, int lux)
110{
111 long seed;
112 long seedlist[2]={0,0};
113
114 luxury = lux;
115 int cycle = std::abs(int(rowIndex/maxIndex));
116 int row = std::abs(int(rowIndex%maxIndex));
117 int col = std::abs(int(colIndex%2));
118 long mask = (( cycle & 0x000007ff ) << 20 );
119 HepRandom::getTheTableSeeds( seedlist, row );
120 seed = ( seedlist[col] )^mask;
121 setSeed(seed, luxury);
122
123 // setSeeds() wants a zero terminated array!
124 seedlist[0]=theSeed;
125 seedlist[1]=0;
126 setSeeds(seedlist, luxury);
127}
128
129RanluxEngine::RanluxEngine( std::istream& is )
131{
132 is >> *this;
133}
134
136
137void RanluxEngine::setSeed(long seed, int lux) {
138
139// The initialisation is carried out using a Multiplicative
140// Congruential generator using formula constants of L'Ecuyer
141// as described in "A review of pseudorandom number generators"
142// (Fred James) published in Computer Physics Communications 60 (1990)
143// pages 329-344
144
145 const int ecuyer_a = 53668;
146 const int ecuyer_b = 40014;
147 const int ecuyer_c = 12211;
148 const int ecuyer_d = 2147483563;
149
150 const int lux_levels[5] = {0,24,73,199,365};
151
152 long int_seed_table[24];
153 long next_seed = seed;
154 long k_multiple;
155 int i;
156
157// number of additional random numbers that need to be 'thrown away'
158// every 24 numbers is set using luxury level variable.
159
160 theSeed = seed;
161 if( (lux > 4)||(lux < 0) ){
162 if(lux >= 24){
163 nskip = lux - 24;
164 }else{
165 nskip = lux_levels[3]; // corresponds to default luxury level
166 }
167 }else{
168 luxury = lux;
169 nskip = lux_levels[luxury];
170 }
171
172
173 for(i = 0;i != 24;i++){
174 k_multiple = next_seed / ecuyer_a;
175 next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
176 - k_multiple * ecuyer_c ;
177 if(next_seed < 0)next_seed += ecuyer_d;
178 int_seed_table[i] = next_seed % int_modulus;
179 }
180
181 for(i = 0;i != 24;i++)
182 float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
183
184 i_lag = 23;
185 j_lag = 9;
186 carry = 0. ;
187
188 if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
189
190 count24 = 0;
191}
192
193void RanluxEngine::setSeeds(const long *seeds, int lux) {
194
195 const int ecuyer_a = 53668;
196 const int ecuyer_b = 40014;
197 const int ecuyer_c = 12211;
198 const int ecuyer_d = 2147483563;
199
200 const int lux_levels[5] = {0,24,73,199,365};
201 int i;
202 long int_seed_table[24];
203 long k_multiple,next_seed;
204 const long *seedptr;
205
206 theSeeds = seeds;
207 seedptr = seeds;
208
209 if(seeds == 0){
210 setSeed(theSeed,lux);
211 theSeeds = &theSeed;
212 return;
213 }
214
215 theSeed = *seeds;
216
217// number of additional random numbers that need to be 'thrown away'
218// every 24 numbers is set using luxury level variable.
219
220 if( (lux > 4)||(lux < 0) ){
221 if(lux >= 24){
222 nskip = lux - 24;
223 }else{
224 nskip = lux_levels[3]; // corresponds to default luxury level
225 }
226 }else{
227 luxury = lux;
228 nskip = lux_levels[luxury];
229 }
230
231 for( i = 0;(i != 24)&&(*seedptr != 0);i++){
232 int_seed_table[i] = *seedptr % int_modulus;
233 seedptr++;
234 }
235
236 if(i != 24){
237 next_seed = int_seed_table[i-1];
238 for(;i != 24;i++){
239 k_multiple = next_seed / ecuyer_a;
240 next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
241 - k_multiple * ecuyer_c ;
242 if(next_seed < 0)next_seed += ecuyer_d;
243 int_seed_table[i] = next_seed % int_modulus;
244 }
245 }
246
247 for(i = 0;i != 24;i++)
248 float_seed_table[i] = int_seed_table[i] * mantissa_bit_24();
249
250 i_lag = 23;
251 j_lag = 9;
252 carry = 0. ;
253
254 if( float_seed_table[23] == 0. ) carry = mantissa_bit_24();
255
256 count24 = 0;
257}
258
259void RanluxEngine::saveStatus( const char filename[] ) const
260{
261 std::ofstream outFile( filename, std::ios::out ) ;
262 if (!outFile.bad()) {
263 outFile << "Uvec\n";
264 std::vector<unsigned long> v = put();
265 #ifdef TRACE_IO
266 std::cout << "Result of v = put() is:\n";
267 #endif
268 for (unsigned int i=0; i<v.size(); ++i) {
269 outFile << v[i] << "\n";
270 #ifdef TRACE_IO
271 std::cout << v[i] << " ";
272 if (i%6==0) std::cout << "\n";
273 #endif
274 }
275 #ifdef TRACE_IO
276 std::cout << "\n";
277 #endif
278 }
279#ifdef REMOVED
280 if (!outFile.bad()) {
281 outFile << theSeed << std::endl;
282 for (int i=0; i<24; ++i)
283 outFile <<std::setprecision(20) << float_seed_table[i] << " ";
284 outFile << std::endl;
285 outFile << i_lag << " " << j_lag << std::endl;
286 outFile << std::setprecision(20) << carry << " " << count24 << std::endl;
287 outFile << luxury << " " << nskip << std::endl;
288 }
289#endif
290}
291
292void RanluxEngine::restoreStatus( const char filename[] )
293{
294 std::ifstream inFile( filename, std::ios::in);
295 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
296 std::cerr << " -- Engine state remains unchanged\n";
297 return;
298 }
299 if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
300 std::vector<unsigned long> v;
301 unsigned long xin;
302 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
303 inFile >> xin;
304 #ifdef TRACE_IO
305 std::cout << "ivec = " << ivec << " xin = " << xin << " ";
306 if (ivec%3 == 0) std::cout << "\n";
307 #endif
308 if (!inFile) {
309 inFile.clear(std::ios::badbit | inFile.rdstate());
310 std::cerr << "\nRanluxEngine state (vector) description improper."
311 << "\nrestoreStatus has failed."
312 << "\nInput stream is probably mispositioned now." << std::endl;
313 return;
314 }
315 v.push_back(xin);
316 }
317 getState(v);
318 return;
319 }
320
321 if (!inFile.bad() && !inFile.eof()) {
322// inFile >> theSeed; removed -- encompased by possibleKeywordInput
323 for (int i=0; i<24; ++i)
324 inFile >> float_seed_table[i];
325 inFile >> i_lag; inFile >> j_lag;
326 inFile >> carry; inFile >> count24;
327 inFile >> luxury; inFile >> nskip;
328 }
329}
330
332{
333 std::cout << std::endl;
334 std::cout << "--------- Ranlux engine status ---------" << std::endl;
335 std::cout << " Initial seed = " << theSeed << std::endl;
336 std::cout << " float_seed_table[] = ";
337 for (int i=0; i<24; ++i)
338 std::cout << float_seed_table[i] << " ";
339 std::cout << std::endl;
340 std::cout << " i_lag = " << i_lag << ", j_lag = " << j_lag << std::endl;
341 std::cout << " carry = " << carry << ", count24 = " << count24 << std::endl;
342 std::cout << " luxury = " << luxury << " nskip = " << nskip << std::endl;
343 std::cout << "----------------------------------------" << std::endl;
344}
345
347
348 float next_random;
349 float uni;
350 int i;
351
352 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
353 #ifdef TRACE_IO
354 if (flat_trace) {
355 std::cout << "float_seed_table[" << j_lag << "] = "
356 << float_seed_table[j_lag]
357 << " float_seed_table[" << i_lag << "] = " << float_seed_table[i_lag]
358 << " uni = " << uni << "\n";
359 std::cout << float_seed_table[j_lag]
360 << " - " << float_seed_table[i_lag]
361 << " - " << carry << " = "
362 << (double)float_seed_table[j_lag]
363 - (double) float_seed_table[i_lag] - (double)carry
364 << "\n";
365 }
366 #endif
367 if(uni < 0. ){
368 uni += 1.0;
369 carry = mantissa_bit_24();
370 }else{
371 carry = 0.;
372 }
373
374 float_seed_table[i_lag] = uni;
375 i_lag --;
376 j_lag --;
377 if(i_lag < 0) i_lag = 23;
378 if(j_lag < 0) j_lag = 23;
379
380 if( uni < mantissa_bit_12() ){
381 uni += mantissa_bit_24() * float_seed_table[j_lag];
382 if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
383 }
384 next_random = uni;
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 #ifdef TRACE_IO
393 if (flat_trace) {
394 std::cout << "carry = " << carry << "\n";
395 }
396 #endif
397 for( i = 0; i != nskip ; i++){
398 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
399 if(uni < 0. ){
400 uni += 1.0;
401 carry = mantissa_bit_24();
402 }else{
403 carry = 0.;
404 }
405 float_seed_table[i_lag] = uni;
406 #ifdef TRACE_IO
407 if (flat_trace) {
408 double xfst = float_seed_table[i_lag];
409 std::cout << "fst[" << i_lag << "] = "
410 << DoubConv::d2x(xfst) << "\n";
411 }
412 #endif
413 i_lag --;
414 j_lag --;
415 if(i_lag < 0)i_lag = 23;
416 if(j_lag < 0) j_lag = 23;
417 }
418 }
419 #ifdef TRACE_IO
420 if (flat_trace) {
421 std::cout << "next_random = " << next_random << "\n";
422 // flat_trace = false;
423 }
424 #endif
425 return (double) next_random;
426}
427
428void RanluxEngine::flatArray(const int size, double* vect)
429{
430 float next_random;
431 float uni;
432 int i;
433 int index;
434
435 for (index=0; index<size; ++index) {
436 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
437 if(uni < 0. ){
438 uni += 1.0;
439 carry = mantissa_bit_24();
440 }else{
441 carry = 0.;
442 }
443
444 float_seed_table[i_lag] = uni;
445 i_lag --;
446 j_lag --;
447 if(i_lag < 0) i_lag = 23;
448 if(j_lag < 0) j_lag = 23;
449
450 if( uni < mantissa_bit_12() ){
451 uni += mantissa_bit_24() * float_seed_table[j_lag];
452 if( uni == 0) uni = mantissa_bit_24() * mantissa_bit_24();
453 }
454 next_random = uni;
455 vect[index] = (double)next_random;
456 count24 ++;
457
458// every 24th number generation, several random numbers are generated
459// and wasted depending upon the luxury level.
460
461 if(count24 == 24 ){
462 count24 = 0;
463 for( i = 0; i != nskip ; i++){
464 uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
465 if(uni < 0. ){
466 uni += 1.0;
467 carry = mantissa_bit_24();
468 }else{
469 carry = 0.;
470 }
471 float_seed_table[i_lag] = uni;
472 i_lag --;
473 j_lag --;
474 if(i_lag < 0)i_lag = 23;
475 if(j_lag < 0) j_lag = 23;
476 }
477 }
478 }
479}
480
481RanluxEngine::operator double() {
482 return flat();
483}
484
485RanluxEngine::operator float() {
486 return float( flat() );
487}
488
489RanluxEngine::operator unsigned int() {
490 return ((unsigned int)(flat() * exponent_bit_32()) & 0xffffffff) |
491 (((unsigned int)(float_seed_table[i_lag]*exponent_bit_32())>>16) & 0xff);
492 // needed because Ranlux doesn't fill all bits of the double
493 // which therefore doesn't fill all bits of the integer.
494}
495
496std::ostream & RanluxEngine::put ( std::ostream& os ) const
497{
498 char beginMarker[] = "RanluxEngine-begin";
499 os << beginMarker << "\nUvec\n";
500 std::vector<unsigned long> v = put();
501 for (unsigned int i=0; i<v.size(); ++i) {
502 os << v[i] << "\n";
503 }
504 return os;
505#ifdef REMOVED
506 char endMarker[] = "RanluxEngine-end";
507 long pr = os.precision(20);
508 os << " " << beginMarker << " ";
509 os << theSeed << "\n";
510 for (int i=0; i<24; ++i) {
511 os << float_seed_table[i] << "\n";
512 }
513 os << i_lag << " " << j_lag << "\n";
514 os << carry << " " << count24 << " ";
515 os << luxury << " " << nskip << "\n";
516 os << endMarker << "\n";
517 os.precision(pr);
518 return os;
519#endif
520}
521
522std::vector<unsigned long> RanluxEngine::put () const {
523 std::vector<unsigned long> v;
524 v.push_back (engineIDulong<RanluxEngine>());
525 #ifdef TRACE_IO
526 std::cout << "RanluxEngine put: ID is " << v[0] << "\n";
527 #endif
528 for (int i=0; i<24; ++i) {
529 v.push_back
530 (static_cast<unsigned long>(float_seed_table[i]/mantissa_bit_24()));
531 #ifdef TRACE_IO
532 std::cout << "v[" << i+1 << "] = " << v[i+1] <<
533 " float_seed_table[" << i << "] = " << float_seed_table[i] << "\n";
534 #endif
535 }
536 v.push_back(static_cast<unsigned long>(i_lag));
537 v.push_back(static_cast<unsigned long>(j_lag));
538 v.push_back(static_cast<unsigned long>(carry/mantissa_bit_24()));
539 v.push_back(static_cast<unsigned long>(count24));
540 v.push_back(static_cast<unsigned long>(luxury));
541 v.push_back(static_cast<unsigned long>(nskip));
542 #ifdef TRACE_IO
543 std::cout << "i_lag: " << v[25] << " j_lag: " << v[26]
544 << " carry: " << v[27] << "\n";
545 std::cout << "count24: " << v[28] << " luxury: " << v[29]
546 << " nskip: " << v[30] << "\n";
547 #endif
548 #ifdef TRACE_IO
549 flat_trace = true;
550 #endif
551 return v;
552}
553
554std::istream & RanluxEngine::get ( std::istream& is )
555{
556 char beginMarker [MarkerLen];
557 is >> std::ws;
558 is.width(MarkerLen); // causes the next read to the char* to be <=
559 // that many bytes, INCLUDING A TERMINATION \0
560 // (Stroustrup, section 21.3.2)
561 is >> beginMarker;
562 if (strcmp(beginMarker,"RanluxEngine-begin")) {
563 is.clear(std::ios::badbit | is.rdstate());
564 std::cerr << "\nInput stream mispositioned or"
565 << "\nRanluxEngine state description missing or"
566 << "\nwrong engine type found." << std::endl;
567 return is;
568 }
569 return getState(is);
570}
571
572std::string RanluxEngine::beginTag ( ) {
573 return "RanluxEngine-begin";
574}
575
576std::istream & RanluxEngine::getState ( std::istream& is )
577{
578 if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
579 std::vector<unsigned long> v;
580 unsigned long uu;
581 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
582 is >> uu;
583 if (!is) {
584 is.clear(std::ios::badbit | is.rdstate());
585 std::cerr << "\nRanluxEngine state (vector) description improper."
586 << "\ngetState() has failed."
587 << "\nInput stream is probably mispositioned now." << std::endl;
588 return is;
589 }
590 v.push_back(uu);
591 #ifdef TRACE_IO
592 std::cout << "RanluxEngine::getState -- v[" << v.size()-1
593 << "] = " << v[v.size()-1] << "\n";
594 #endif
595 }
596 getState(v);
597 return (is);
598 }
599
600// is >> theSeed; Removed, encompassed by possibleKeywordInput()
601
602 char endMarker [MarkerLen];
603 for (int i=0; i<24; ++i) {
604 is >> float_seed_table[i];
605 }
606 is >> i_lag; is >> j_lag;
607 is >> carry; is >> count24;
608 is >> luxury; is >> nskip;
609 is >> std::ws;
610 is.width(MarkerLen);
611 is >> endMarker;
612 if (strcmp(endMarker,"RanluxEngine-end")) {
613 is.clear(std::ios::badbit | is.rdstate());
614 std::cerr << "\nRanluxEngine state description incomplete."
615 << "\nInput stream is probably mispositioned now." << std::endl;
616 return is;
617 }
618 return is;
619}
620
621bool RanluxEngine::get (const std::vector<unsigned long> & v) {
622 if ((v[0] & 0xffffffffUL) != engineIDulong<RanluxEngine>()) {
623 std::cerr <<
624 "\nRanluxEngine get:state vector has wrong ID word - state unchanged\n";
625 return false;
626 }
627 return getState(v);
628}
629
630bool RanluxEngine::getState (const std::vector<unsigned long> & v) {
631 if (v.size() != VECTOR_STATE_SIZE ) {
632 std::cerr <<
633 "\nRanluxEngine get:state vector has wrong length - state unchanged\n";
634 return false;
635 }
636 for (int i=0; i<24; ++i) {
637 float_seed_table[i] = v[i+1]*mantissa_bit_24();
638 #ifdef TRACE_IO
639 std::cout <<
640 "float_seed_table[" << i << "] = " << float_seed_table[i] << "\n";
641 #endif
642 }
643 i_lag = (int)v[25];
644 j_lag = (int)v[26];
645 carry = v[27]*mantissa_bit_24();
646 count24 = (int)v[28];
647 luxury = (int)v[29];
648 nskip = (int)v[30];
649 #ifdef TRACE_IO
650 std::cout << "i_lag: " << i_lag << " j_lag: " << j_lag
651 << " carry: " << carry << "\n";
652 std::cout << "count24: " << count24 << " luxury: " << luxury
653 << " nskip: " << nskip << "\n";
654
655 #endif
656 #ifdef TRACE_IO
657 flat_trace = true;
658 #endif
659 return true;
660}
661
662} // namespace CLHEP
#define CLHEP_ATOMIC_INT_TYPE
Definition: atomic_int.h:25
static std::string d2x(double d)
Definition: DoubConv.cc:82
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:49
static double mantissa_bit_24()
static void getTheTableSeeds(long *seeds, int index)
Definition: Random.cc:256
static const unsigned int VECTOR_STATE_SIZE
Definition: RanluxEngine.h:111
void flatArray(const int size, double *vect)
std::string name() const
Definition: RanluxEngine.cc:70
void setSeeds(const long *seeds, int lxr=3)
virtual std::istream & getState(std::istream &is)
void saveStatus(const char filename[]="Ranlux.conf") const
std::vector< unsigned long > put() const
static std::string beginTag()
virtual std::istream & get(std::istream &is)
void showStatus() const
void restoreStatus(const char filename[]="Ranlux.conf")
static std::string engineName()
Definition: RanluxEngine.h:105
void setSeed(long seed, int lxr=3)
#define double(obj)
Definition: excDblThrow.cc:32
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:168