StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RanluxEngine.cc
1 /***************************************************************************
2  *
3  * $Id: RanluxEngine.cc,v 1.5 2016/01/22 17:10:50 smirnovd Exp $
4  *
5  * Author: Original code from CLHEP by G. Cosmo
6  * modified for SCL bl
7  ***************************************************************************
8  *
9  * Description:
10  * -----------------------------------------------------------------------
11  * HEP Random
12  * --- RanluxEngine ---
13  * class implementation file
14  * -----------------------------------------------------------------------
15  * This file is part of Geant4 (simulation toolkit for HEP).
16  *
17  * Ranlux random number generator originally implemented in FORTRAN77
18  * by Fred James as part of the MATHLIB HEP library.
19  * 'RanluxEngine' is designed to fit into the CLHEP random number
20  * class structure.
21  *
22  ***************************************************************************
23  *
24  * $Log: RanluxEngine.cc,v $
25  * Revision 1.5 2016/01/22 17:10:50 smirnovd
26  * StarClassLibrary: Removed deprecated storage class specifier 'register'
27  *
28  * This keyword is deprecated since C++11 and serves no purpose
29  *
30  * "
31  * The register specifier is only allowed for objects declared at block scope and
32  * in function parameter lists. It indicates automatic storage duration, which is
33  * the default for these kinds of declarations. Additionally, the presence of this
34  * keyword may be used as a hint for the optimizer to store the value of this
35  * variable in a CPU register.
36  * "
37  *
38  * Revision 1.4 2012/06/11 15:29:26 fisyak
39  * std namespace
40  *
41  * Revision 1.3 2003/09/02 17:59:34 perev
42  * gcc 3.2 updates + WarnOff
43  *
44  * Revision 1.2 1999/12/07 23:43:04 ullrich
45  * Modified to get rid of warnings on Linux.
46  *
47  * Revision 1.1 1999/01/30 03:59:01 fisyak
48  * Root Version of StarClassLibrary
49  *
50  * Revision 1.1 1999/01/23 00:29:12 ullrich
51  * Initial Revision
52  *
53  **************************************************************************/
54 #include "RanluxEngine.h"
55 
56 RanluxEngine::RanluxEngine(long seed, HepInt lux)
57 : int_modulus(0x1000000),
58  mantissa_bit_24((HepFloat) ::pow(0.5,24.)),
59  mantissa_bit_12((HepFloat) ::pow(0.5,12.))
60 {
61  luxury = lux;
62  setSeed(seed, luxury);
63  setSeeds(&theSeed, luxury);
64 }
65 
66 RanluxEngine::~RanluxEngine() {}
67 
68 RanluxEngine::RanluxEngine(const RanluxEngine &p)
69 : int_modulus(0x1000000),
70  mantissa_bit_24((HepFloat) ::pow(0.5,24.)),
71  mantissa_bit_12((HepFloat) ::pow(0.5,12.))
72 {
73  if ((this != &p) && (&p)) {
74  theSeed = p.getSeed();
75  setSeeds(&theSeed, p.luxury);
76  for (HepInt i=0; i<24; ++i)
77  float_seed_table[i] = p.float_seed_table[i];
78  nskip = p.nskip;
79  luxury = p.luxury;
80  i_lag = p.i_lag; j_lag = p.j_lag;
81  carry = p.carry;
82  count24 = p.count24;
83  }
84 }
85 
86 RanluxEngine & RanluxEngine::operator = (const RanluxEngine &p)
87 {
88  if ((this != &p) && (&p)) {
89  theSeed = p.getSeed();
90  setSeeds(&theSeed, p.luxury);
91  for (HepInt i=0; i<24; ++i)
92  float_seed_table[i] = p.float_seed_table[i];
93  nskip = p.nskip;
94  luxury = p.luxury;
95  i_lag = p.i_lag; j_lag = p.j_lag;
96  carry = p.carry;
97  count24 = p.count24;
98  }
99  return *this;
100 }
101 
102 void RanluxEngine::setSeed(long seed, HepInt lux) {
103 
104 // The initialisation is carried out using a Multiplicative
105 // Congruential generator using formula constants of L'Ecuyer
106 // as described in "A review of pseudorandom number generators"
107 // (Fred James) published in Computer Physics Communications 60 (1990)
108 // pages 329-344
109 
110  const HepInt ecuyer_a = 53668;
111  const HepInt ecuyer_b = 40014;
112  const HepInt ecuyer_c = 12211;
113  const HepInt ecuyer_d = 2147483563;
114 
115  const HepInt lux_levels[5] = {0,24,73,199,365};
116 
117  long int_seed_table[24];
118  long next_seed = seed;
119  long k_multiple;
120  HepInt i;
121 
122 // number of additional random numbers that need to be 'thrown away'
123 // every 24 numbers is set using luxury level variable.
124 
125  theSeed = seed;
126  if( (lux > 4)||(lux < 0) ){
127  if(lux >= 24){
128  nskip = lux - 24;
129  }else{
130  nskip = lux_levels[3]; // corresponds to default luxury level
131  }
132  }else{
133  luxury = lux;
134  nskip = lux_levels[luxury];
135  }
136 
137 
138  for(i = 0;i != 24;i++){
139  k_multiple = next_seed / ecuyer_a;
140  next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
141  - k_multiple * ecuyer_c ;
142  if(next_seed < 0)next_seed += ecuyer_d;
143  int_seed_table[i] = next_seed % int_modulus;
144  }
145 
146  for(i = 0;i != 24;i++)
147  float_seed_table[i] = int_seed_table[i] * mantissa_bit_24;
148 
149  i_lag = 23;
150  j_lag = 9;
151  carry = 0. ;
152 
153  if( float_seed_table[23] == 0. ) carry = mantissa_bit_24;
154 
155  count24 = 0;
156 }
157 
158 void RanluxEngine::setSeeds(const long *seeds, HepInt lux) {
159 
160  const HepInt ecuyer_a = 53668;
161  const HepInt ecuyer_b = 40014;
162  const HepInt ecuyer_c = 12211;
163  const HepInt ecuyer_d = 2147483563;
164 
165  const HepInt lux_levels[5] = {0,24,73,199,365};
166  HepInt i;
167  long int_seed_table[24];
168  long k_multiple,next_seed;
169  const long *seedptr;
170 
171  theSeeds = seeds;
172  seedptr = seeds;
173 
174  if(seeds == 0){
175  setSeed(theSeed,lux);
176  theSeeds = &theSeed;
177  return;
178  }
179 
180  theSeed = *seeds;
181 
182 // number of additional random numbers that need to be 'thrown away'
183 // every 24 numbers is set using luxury level variable.
184 
185  if( (lux > 4)||(lux < 0) ){
186  if(lux >= 24){
187  nskip = lux - 24;
188  }else{
189  nskip = lux_levels[3]; // corresponds to default luxury level
190  }
191  }else{
192  luxury = lux;
193  nskip = lux_levels[luxury];
194  }
195 
196  for( i = 0;(i != 24)&&(*seedptr != 0);i++){
197  int_seed_table[i] = *seedptr % int_modulus;
198  seedptr++;
199  }
200 
201  if(i != 24){
202  next_seed = int_seed_table[i-1];
203  for(;i != 24;i++){
204  k_multiple = next_seed / ecuyer_a;
205  next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
206  - k_multiple * ecuyer_c ;
207  if(next_seed < 0)next_seed += ecuyer_d;
208  int_seed_table[i] = next_seed % int_modulus;
209  }
210  }
211 
212  for(i = 0;i != 24;i++)
213  float_seed_table[i] = int_seed_table[i] * mantissa_bit_24;
214 
215  i_lag = 23;
216  j_lag = 9;
217  carry = 0. ;
218 
219  if( float_seed_table[23] == 0. ) carry = mantissa_bit_24;
220 
221  count24 = 0;
222 }
223 
224 void RanluxEngine::saveStatus() const
225 {
226  ofstream outFile("Ranlux.conf", std::ios::out ) ;
227 
228  if (!outFile.bad()) {
229  outFile << theSeed << endl;
230  for (HepInt i=0; i<24; ++i)
231  outFile << float_seed_table[i] << " ";
232  outFile << endl;
233  outFile << i_lag << " " << j_lag << endl;
234  outFile << carry << " " << count24 << endl;
235  }
236 }
237 
238 void RanluxEngine::restoreStatus()
239 {
240  ifstream inFile("Ranlux.conf", std::ios::in);
241 
242  if (!inFile.bad() && !inFile.eof()) {
243  inFile >> theSeed;
244  for (HepInt i=0; i<24; ++i)
245  inFile >> float_seed_table[i];
246  inFile >> i_lag; inFile >> j_lag;
247  inFile >> carry; inFile >> count24;
248  }
249 }
250 
251 void RanluxEngine::showStatus() const
252 {
253  cout << endl;
254  cout << "--------- Ranlux engine status ---------" << endl;
255  cout << " Initial seed = " << theSeed << endl;
256  cout << " float_seed_table[] = ";
257  for (HepInt i=0; i<24; ++i)
258  cout << float_seed_table[i] << " ";
259  cout << endl;
260  cout << " i_lag = " << i_lag << ", j_lag = " << j_lag << endl;
261  cout << " carry = " << carry << ", count24 = " << count24 << endl;
262  cout << "----------------------------------------" << endl;
263 }
264 
265 HepDouble RanluxEngine::flat() {
266 
267  HepFloat next_random;
268  HepFloat uni;
269  HepInt i;
270 
271  uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
272  if(uni < 0. ){
273  uni += 1.0;
274  carry = mantissa_bit_24;
275  }else{
276  carry = 0.;
277  }
278 
279  float_seed_table[i_lag] = uni;
280  i_lag --;
281  j_lag --;
282  if(i_lag < 0) i_lag = 23;
283  if(j_lag < 0) j_lag = 23;
284 
285  if( uni < mantissa_bit_12 ){
286  uni += mantissa_bit_24 * float_seed_table[j_lag];
287  if( uni == 0) uni = mantissa_bit_24 * mantissa_bit_24;
288  }
289  next_random = uni;
290  count24 ++;
291 
292 // every 24th number generation, several random numbers are generated
293 // and wasted depending upon the luxury level.
294 
295  if(count24 == 24 ){
296  count24 = 0;
297  for( i = 0; i != nskip ; i++){
298  uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
299  if(uni < 0. ){
300  uni += 1.0;
301  carry = mantissa_bit_24;
302  }else{
303  carry = 0.;
304  }
305  float_seed_table[i_lag] = uni;
306  i_lag --;
307  j_lag --;
308  if(i_lag < 0)i_lag = 23;
309  if(j_lag < 0) j_lag = 23;
310  }
311  }
312  return (HepDouble) next_random;
313 }
314 
315 void RanluxEngine::flatArray(const HepInt size, HepDouble* vect)
316 {
317  HepFloat next_random;
318  HepFloat uni;
319  HepInt i;
320  HepInt index;
321 
322  for (index=0; index<size; ++index) {
323  uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
324  if(uni < 0. ){
325  uni += 1.0;
326  carry = mantissa_bit_24;
327  }else{
328  carry = 0.;
329  }
330 
331  float_seed_table[i_lag] = uni;
332  i_lag --;
333  j_lag --;
334  if(i_lag < 0) i_lag = 23;
335  if(j_lag < 0) j_lag = 23;
336 
337  if( uni < mantissa_bit_12 ){
338  uni += mantissa_bit_24 * float_seed_table[j_lag];
339  if( uni == 0) uni = mantissa_bit_24 * mantissa_bit_24;
340  }
341  next_random = uni;
342  vect[index] = (HepDouble)next_random;
343  count24 ++;
344 
345 // every 24th number generation, several random numbers are generated
346 // and wasted depending upon the luxury level.
347 
348  if(count24 == 24 ){
349  count24 = 0;
350  for( i = 0; i != nskip ; i++){
351  uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
352  if(uni < 0. ){
353  uni += 1.0;
354  carry = mantissa_bit_24;
355  }else{
356  carry = 0.;
357  }
358  float_seed_table[i_lag] = uni;
359  i_lag --;
360  j_lag --;
361  if(i_lag < 0)i_lag = 23;
362  if(j_lag < 0) j_lag = 23;
363  }
364  }
365  }
366 }
367 
368 void
369 #ifndef ST_NO_TEMPLATE_DEF_ARGS
370 RanluxEngine::flatArray(vector<HepDouble>& vec)
371 #else
372 RanluxEngine::flatArray(vector<HepDouble,allocator<HepDouble> >& vec)
373 #endif
374 {
375  HepFloat next_random;
376  HepFloat uni;
377  HepInt i;
378 
379  for (unsigned int index=0; index<vec.size(); ++index) {
380  uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
381  if(uni < 0. ){
382  uni += 1.0;
383  carry = mantissa_bit_24;
384  }else{
385  carry = 0.;
386  }
387 
388  float_seed_table[i_lag] = uni;
389  i_lag --;
390  j_lag --;
391  if(i_lag < 0) i_lag = 23;
392  if(j_lag < 0) j_lag = 23;
393 
394  if( uni < mantissa_bit_12 ){
395  uni += mantissa_bit_24 * float_seed_table[j_lag];
396  if( uni == 0) uni = mantissa_bit_24 * mantissa_bit_24;
397  }
398  next_random = uni;
399  vec[index] = (HepDouble)next_random;
400  count24 ++;
401 
402 // every 24th number generation, several random numbers are generated
403 // and wasted depending upon the luxury level.
404 
405  if(count24 == 24 ){
406  count24 = 0;
407  for( i = 0; i != nskip ; i++){
408  uni = float_seed_table[j_lag] - float_seed_table[i_lag] - carry;
409  if(uni < 0. ){
410  uni += 1.0;
411  carry = mantissa_bit_24;
412  }else{
413  carry = 0.;
414  }
415  float_seed_table[i_lag] = uni;
416  i_lag --;
417  j_lag --;
418  if(i_lag < 0)i_lag = 23;
419  if(j_lag < 0) j_lag = 23;
420  }
421  }
422  }
423 }