EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_rndm.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ random number generators
5 # Copyright (C) 2015 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Iwan Kawrakow, 2005
25 #
26 # Contributors: Hubert Ho
27 #
28 ###############################################################################
29 */
30 
31 
40 #include "egs_rndm.h"
41 #include "egs_input.h"
42 #include "egs_functions.h"
43 
44 #include <iostream>
45 #include <string>
46 using namespace std;
47 
48 void EGS_RandomGenerator::allocate(int n) {
49  if (n < 1) {
50  egsFatal("Attempt to construct a RNG with n < 1\n");
51  }
52  rarray = new EGS_Float[n];
53  np = n;
54  ip = np;
55 }
56 
57 void EGS_RandomGenerator::copyBaseState(const EGS_RandomGenerator &r) {
58  if (np > 0 && np != r.np) {
59  delete [] rarray;
60  np = 0;
61  }
62  if (np <= 0) {
63  allocate(r.np);
64  }
65  ip = r.ip;
66  have_x = r.have_x;
67  the_x = r.the_x;
68  count = r.count;
69  for (int j=ip; j<np; j++) {
70  rarray[j] = r.rarray[j];
71  }
72 }
73 
74 EGS_RandomGenerator::EGS_RandomGenerator(int n) : count(0), np(0) {
75  allocate(n);
76  have_x = false;
77  for (int j=0; j<np; j++) {
78  rarray[j] = 0;
79  }
80 }
81 
82 bool EGS_RandomGenerator::storeState(ostream &data) {
83  if (!egsStoreI64(data,count)) {
84  return false;
85  }
86  data << " " << np << " " << ip << endl;
87  for (int j=0; j<np; j++) {
88  data << rarray[j] << " ";
89  }
90  data << endl;
91  if (!data.good()) {
92  return false;
93  }
94  return storePrivateState(data);
95 }
96 
97 bool EGS_RandomGenerator::setState(istream &data) {
98  if (!egsGetI64(data,count)) {
99  return false;
100  }
101  int np1;
102  data >> np1 >> ip;
103  if (!data.good() || data.fail() || data.eof()) {
104  return false;
105  }
106  if (np1 < 1) {
107  return false;
108  }
109  if (np1 != np && np > 0) {
110  delete [] rarray;
111  rarray = new EGS_Float [np1];
112  }
113  np = np1;
114  for (int j=0; j<np; j++) {
115  data >> rarray[j];
116  }
117  if (!data.good()) {
118  return false;
119  }
120  return setPrivateState(data);
121 }
122 
123 bool EGS_RandomGenerator::addState(istream &data) {
124  EGS_I64 count_save = count;
125  if (!setState(data)) {
126  return false;
127  }
128  count += count_save;
129  return true;
130 }
131 
137 class EGS_LOCAL EGS_Ranmar : public EGS_RandomGenerator {
138 
139 public:
140 
144  EGS_Ranmar(int ixx=1802, int jxx=9373, int n=128) :
145  EGS_RandomGenerator(n), high_res(false), copy(0) {
146  setState(ixx,jxx);
147  };
148 
150  ix(r.ix), jx(r.jx), c(r.c), iseed1(r.iseed1), iseed2(r.iseed2),
151  high_res(r.high_res) {
152  for (int j=0; j<97; j++) {
153  u[j] = r.u[j];
154  }
155  };
156 
157  ~EGS_Ranmar() {
158  if (copy) {
159  delete copy;
160  }
161  };
162 
165  void fillArray(int n, EGS_Float *array);
166 
168  void describeRNG() const;
169 
171 
172  void setState(EGS_RandomGenerator *r);
173 
174  void saveState();
175  void resetState();
176 
177  int rngSize() const {
178  return baseSize() + 102*sizeof(int);
179  };
180 
181  void setHighResolution(bool hr) {
182  high_res = hr;
183  };
184 
185 protected:
186 
190  bool storePrivateState(ostream &data);
192  bool setPrivateState(istream &data);
193 
194  void set(const EGS_Ranmar &r) {
195  copyBaseState(r);
196  ix = r.ix;
197  jx = r.jx;
198  c = r.c;
199  iseed1 = r.iseed1;
200  iseed2 = r.iseed2;
201  for (int j=0; j<97; j++) {
202  u[j] = r.u[j];
203  }
204  };
205 
206 private:
207 
208  void setState(int ixx, int jxx);
209 
210  int ix, jx, c;
211  int u[97];
212  static int cd, cm;
213  static EGS_Float twom24;
214  int iseed1, iseed2;
215 
216  bool high_res;
217 
218  EGS_Ranmar *copy;
219 
220 };
221 
222 void EGS_Ranmar::saveState() {
223  if (copy) {
224  copy->set(*this);
225  }
226  else {
227  copy = new EGS_Ranmar(*this);
228  }
229  copy->copy = 0;
230 }
231 
232 void EGS_Ranmar::resetState() {
233  if (copy) {
234  EGS_Ranmar *tmp = copy;
235  set(*copy);
236  copy = tmp;
237  }
238 }
239 
240 EGS_RandomGenerator *EGS_Ranmar::getCopy() {
241  EGS_Ranmar *c = new EGS_Ranmar(*this);
242  c->np = 0;
243  c->copy = 0;
244  c->copyBaseState(*this);
245  return c;
246 }
247 
248 void EGS_Ranmar::setState(EGS_RandomGenerator *r) {
249  copyBaseState(*r);
250  EGS_Ranmar *r1 = dynamic_cast<EGS_Ranmar *>(r);
251  if (!r1) {
252  egsFatal("EGS_Ranmar::setState: attampt to set my state by a non EGS_Ranmar RNG!\n");
253  }
254  ix = r1->ix;
255  jx = r1->jx;
256  c = r1->c;
257  iseed1 = r1->iseed1;
258  iseed2 = r1->iseed2;
259  for (int j=0; j<97; j++) {
260  u[j] = r1->u[j];
261  }
262 }
263 
264 bool EGS_Ranmar::storePrivateState(ostream &data) {
265  data << ix << " " << jx << " " << c << " "
266  << iseed1 << " " << iseed2 << " " << high_res << endl;
267  for (int j=0; j<97; j++) {
268  data << u[j] << " ";
269  }
270  data << endl;
271  return data.good();
272 }
273 
274 bool EGS_Ranmar::setPrivateState(istream &data) {
275  data >> ix >> jx >> c >> iseed1 >> iseed2 >> high_res;
276  for (int j=0; j<97; j++) {
277  data >> u[j];
278  }
279  return data.good();
280 }
281 
282 
283 EGS_Float EGS_Ranmar::twom24 = 1./16777216.;
284 int EGS_Ranmar::cd = 7654321;
285 int EGS_Ranmar::cm = 16777213;
286 
288  egsInformation("Random number generator:\n"
289  "============================================\n");
290  egsInformation(" type = ranmar\n");
291  egsInformation(" high resolution = ");
292  if (high_res) {
293  egsInformation("yes\n");
294  }
295  else {
296  egsInformation("no\n");
297  }
298  egsInformation(" initial seeds = %d %d\n",iseed1,iseed2);
299  egsInformation(" numbers used so far = %lld\n",count);
300 }
301 
302 void EGS_Ranmar::setState(int ixx, int jxx) {
303  if (ixx <= 0 || ixx >= 31328) {
304  ixx = 1802;
305  }
306  if (jxx <= 0 || jxx >= 30081) {
307  jxx = 9373;
308  }
309  iseed1 = ixx;
310  iseed2 = jxx;
311  int i = (ixx/177)%177 + 2;
312  int j = ixx%177 + 2;
313  int k = (jxx/169)%178 + 1;
314  int l = jxx%169;
315 
316  for (int ii=0; ii<97; ii++) {
317  int s = 0;
318  int t = 8388608;
319  for (int jj=0; jj<24; jj++) {
320  int m = (((i*j)%179)*k)%179;
321  i = j;
322  j = k;
323  k = m;
324  l = (53*l+1)%169;
325  if ((l*m)%64 >= 32) {
326  s += t;
327  }
328  t /= 2;
329  }
330  u[ii] = s;
331  }
332  c = 362436;
333  ix = 96;
334  jx = 32;
335 }
336 
337 void EGS_Ranmar::fillArray(int n, EGS_Float *array) {
338  for (int ii=0; ii<n; ii++) {
339  register int r = u[ix] - u[jx--];
340 #ifdef MSVC
341  if (r > 16777219) {
342  egsWarning("r = %d\n",r);
343  }
344 #endif
345  if (r < 0) {
346  r += 16777216;
347  }
348  u[ix--] = r;
349  if (ix < 0) {
350  ix = 96;
351  }
352  if (jx < 0) {
353  jx = 96;
354  }
355  c -= cd;
356  if (c < 0) {
357  c+=cm;
358  }
359  r -= c;
360  if (r < 0) {
361  r+=16777216;
362  }
363 #ifdef MSVC
364  if (r > 16777219) {
365  egsWarning("r = %d\n",r);
366  }
367 #endif
368  array[ii] = twom24*r;
369  }
370  if (high_res) {
371  for (int ii=0; ii<n; ii++) {
372  register int r = u[ix] - u[jx--];
373 #ifdef MSVC
374  if (r > 16777219) {
375  egsWarning("r = %d\n",r);
376  }
377 #endif
378  if (r < 0) {
379  r += 16777216;
380  }
381  u[ix--] = r;
382  if (ix < 0) {
383  ix = 96;
384  }
385  if (jx < 0) {
386  jx = 96;
387  }
388  c -= cd;
389  if (c < 0) {
390  c+=cm;
391  }
392  r -= c;
393  if (r < 0) {
394  r+=16777216;
395  }
396 #ifdef MSVC
397  if (r > 16777219) {
398  egsWarning("r = %d\n",r);
399  }
400 #endif
401  array[ii] += twom24*twom24*r;
402  }
403  }
404  count += n;
405 }
406 
407 
409  int sequence) {
410  if (!input) {
411  egsWarning("EGS_RandomGenerator::createRNG: null input?\n");
412  return 0;
413  }
414  EGS_Input *i;
415  bool delete_it = false;
416  if (input->isA("rng definition")) {
417  i = input;
418  }
419  else {
420  i = input->takeInputItem("rng definition");
421  if (!i) {
422  egsWarning("EGS_RandomGenerator::createRNG: no 'RNG definition'"
423  " input\n");
424  return 0;
425  }
426  delete_it = true;
427  }
428  string type;
429  int err = i->getInput("type",type);
430  if (err) {
431  egsWarning("EGS_RandomGenerator::createRNG: no RNG type specified\n"
432  " Assuming ranmar.\n");
433  type = "ranmar";
434  }
435  EGS_RandomGenerator *result;
436  if (i->compare(type,"ranmar")) {
437  vector<int> seeds;
438  err = i->getInput("initial seeds",seeds);
439  EGS_Ranmar *res;
440  if (!err && seeds.size() == 2) {
441  res = new EGS_Ranmar(seeds[0],seeds[1] + sequence);
442  }
443  else {
444  res = new EGS_Ranmar(1802,9373+sequence);
445  }
446  vector<string> hr_options;
447  hr_options.push_back("no");
448  hr_options.push_back("yes");
449  bool hr = i->getInput("high resolution",hr_options,0);
450  res->setHighResolution(hr);
451  result = res;
452  }
453  else {
454  egsWarning("EGS_RandomGenerator::createRNG: unknown RNG type %s\n",
455  type.c_str());
456  result = 0;
457  }
458  if (delete_it) {
459  delete i;
460  }
461  return result;
462 }
463 
465  sequence += 97;
466  int ixx = 33;
467  int iaux = sequence/30081;
468  int jxx = sequence - iaux*30081;
469  if (iaux > 0) {
470  ixx += iaux;
471  if (iaux > 31328) egsFatal("EGS_RandomGenerator::defaultRNG: "
472  "sequence %d is outside of allowed range\n",sequence);
473  }
474  return new EGS_Ranmar(ixx,jxx);
475 }
virtual void resetState()=0
Reset the state to a previously saved state.
bool storePrivateState(ostream &data)
Definition: egs_rndm.cpp:264
bool EGS_EXPORT egsGetI64(istream &data, EGS_I64 &n)
Reads a 64 bit integer from the stream data and assigns it to n. Returns true on success, false on failure.
EGS_I64 count
random number generated so far
Definition: egs_rndm.h:256
EGS_RandomGenerator(int n=128)
Construct a RNG that has an array of n points to hold random numbers.
Definition: egs_rndm.cpp:74
bool isA(const string &key) const
Definition: egs_input.cpp:278
virtual bool setPrivateState(istream &data)=0
Set the state of the RNG object from the data in the input stream data.
bool storeState(ostream &data)
Functions for storing, seting and reseting the state of a RNG object.
Definition: egs_rndm.cpp:82
virtual void saveState()=0
Save the RNG state.
EGS_Input class header file.
bool EGS_EXPORT egsStoreI64(ostream &data, EGS_I64 n)
Writes the 64 bit integer n to the output stream data and returns true on success, false on failure.
int baseSize() const
The memory needed to store the base state.
Definition: egs_rndm.h:290
Global egspp functions header file.
virtual EGS_RandomGenerator * getCopy()=0
Get a copy of the RNG.
virtual bool storePrivateState(ostream &data)=0
Store the state of the RNG to the output stream data.
virtual void fillArray(int n, EGS_Float *array)=0
Fill the array of n elements pointed to by array with random numbers.
void describeRNG() const
Output information about this RNG using egsInformation()
Definition: egs_rndm.cpp:287
Base random number generator class. All random number generators should be derived from this class...
Definition: egs_rndm.h:67
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
virtual int rngSize() const =0
The memory needed to store the rng state.
EGS_RandomGenerator class header file.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
virtual void describeRNG() const
Describe this RNG.
Definition: egs_rndm.h:256
static EGS_RandomGenerator * createRNG(EGS_Input *inp, int sequence=0)
Create a RNG object from the information pointed to by inp and return a pointer to it...
Definition: egs_rndm.cpp:408
bool setPrivateState(istream &data)
Definition: egs_rndm.cpp:274
A ranmar RNG class.
Definition: egs_rndm.cpp:137
void fillArray(int n, EGS_Float *array)
Fill the array pointed to by array with random numbers.
Definition: egs_rndm.cpp:337
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
int ip
pointer to the next rarray element in the sequence
Definition: egs_rndm.h:262
static bool compare(const string &s1, const string &s2)
Definition: egs_input.cpp:1170
static EGS_RandomGenerator * defaultRNG(int sequence=0)
Returns a pointer to the default egspp RNG.
Definition: egs_rndm.cpp:464
int np
size of the array rarray
Definition: egs_rndm.h:261
EGS_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:226
EGS_Float * rarray
array with random numbers of size np.
Definition: egs_rndm.h:263
int getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:338
EGS_Ranmar(int ixx=1802, int jxx=9373, int n=128)
Construct a ranmar RNG using ixx and jxx as the initial seeds.
Definition: egs_rndm.cpp:144
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.