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