Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MTwistEngine.cc
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// -----------------------------------------------------------------------
4// HEP Random
5// --- MTwistEngine ---
6// class implementation file
7// -----------------------------------------------------------------------
8// A "fast, compact, huge-period generator" based on M. Matsumoto and
9// T. Nishimura, "Mersenne Twister: A 623-dimensionally equidistributed
10// uniform pseudorandom number generator", to appear in ACM Trans. on
11// Modeling and Computer Simulation. It is a twisted GFSR generator
12// with a Mersenne-prime period of 2^19937-1, uniform on open interval (0,1)
13// =======================================================================
14// Ken Smith - Started initial draft: 14th Jul 1998
15// - Optimized to get std::pow() out of flat() method
16// - Added conversion operators: 6th Aug 1998
17// J. Marraffino - Added some explicit casts to deal with
18// machines where sizeof(int) != sizeof(long) 22 Aug 1998
19// M. Fischler - Modified constructors such that no two
20// seeds will match sequences, no single/double
21// seeds will match, explicit seeds give
22// determined results, and default will not
23// match any of the above or other defaults.
24// - Modified use of the various exponents of 2
25// to avoid per-instance space overhead and
26// correct the rounding procedure 16 Sep 1998
27// J. Marraffino - Remove dependence on hepString class 13 May 1999
28// M. Fischler - In restore, checkFile for file not found 03 Dec 2004
29// M. Fischler - Methods for distrib. instacne save/restore 12/8/04
30// M. Fischler - split get() into tag validation and
31// getState() for anonymous restores 12/27/04
32// M. Fischler - put/get for vectors of ulongs 3/14/05
33// M. Fischler - State-saving using only ints, for portability 4/12/05
34// M. Fischler - Improved seeding in setSeed (Savanah bug #17479) 11/15/06
35// - (Possible optimization - now that the seeding is improved,
36// is it still necessary for ctor to "warm up" by discarding
37// 2000 iterations?)
38//
39// =======================================================================
40
41#include "CLHEP/Random/Random.h"
45
46#include <atomic>
47#include <cmath>
48#include <iostream>
49#include <string.h> // for strcmp
50#include <vector>
51
52namespace CLHEP {
53
54namespace {
55 // Number of instances with automatic seed selection
56 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
57
58 // Maximum index into the seed table
59 const int maxIndex = 215;
60}
61
62static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
63
64std::string MTwistEngine::name() const {return "MTwistEngine";}
65
68{
69 int numEngines = numberOfEngines++;
70 int cycle = std::abs(int(numEngines/maxIndex));
71 int curIndex = std::abs(int(numEngines%maxIndex));
72 long mask = ((cycle & 0x007fffff) << 8);
73 long seedlist[2];
74 HepRandom::getTheTableSeeds( seedlist, curIndex );
75 seedlist[0] = (seedlist[0])^mask;
76 seedlist[1] = 0;
77 setSeeds( seedlist, numEngines );
78 count624=0;
79
80 for( int i=0; i < 2000; ++i ) flat(); // Warm up just a bit
81}
82
85{
86 long seedlist[2]={seed,17587};
87 setSeeds( seedlist, 0 );
88 count624=0;
89 for( int i=0; i < 2000; ++i ) flat(); // Warm up just a bit
90}
91
92MTwistEngine::MTwistEngine(int rowIndex, int colIndex)
94{
95 int cycle = std::abs(int(rowIndex/maxIndex));
96 int row = std::abs(int(rowIndex%maxIndex));
97 int col = std::abs(int(colIndex%2));
98 long mask = (( cycle & 0x000007ff ) << 20 );
99 long seedlist[2];
100 HepRandom::getTheTableSeeds( seedlist, row );
101 seedlist[0] = (seedlist[col])^mask;
102 seedlist[1] = 690691;
103 setSeeds(seedlist, 4444772);
104 count624=0;
105 for( int i=0; i < 2000; ++i ) flat(); // Warm up just a bit
106}
107
108MTwistEngine::MTwistEngine( std::istream& is )
110{
111 is >> *this;
112}
113
115
117 unsigned int y;
118
119 if( count624 >= N ) {
120 int i;
121
122 for( i=0; i < NminusM; ++i ) {
123 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
124 mt[i] = mt[i+M] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
125 }
126
127 for( ; i < N-1 ; ++i ) {
128 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
129 mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
130 }
131
132 y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
133 mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
134
135 count624 = 0;
136 }
137
138 y = mt[count624];
139 y ^= ( y >> 11);
140 y ^= ((y << 7 ) & 0x9d2c5680);
141 y ^= ((y << 15) & 0xefc60000);
142 y ^= ( y >> 18);
143
144 return y * twoToMinus_32() + // Scale to range
145 (mt[count624++] >> 11) * twoToMinus_53() + // fill remaining bits
146 nearlyTwoToMinus_54(); // make sure non-zero
147}
148
149void MTwistEngine::flatArray( const int size, double *vect ) {
150 for( int i=0; i < size; ++i) vect[i] = flat();
151}
152
153void MTwistEngine::setSeed(long seed, int k) {
154
155 // MF 11/15/06 - Change seeding algorithm to a newer one recommended
156 // by Matsumoto: The original algorithm was
157 // mt[i] = (69069 * mt[i-1]) & 0xffffffff and this gives
158 // problems when the seed bit pattern has lots of zeros
159 // (for example, 0x08000000). Savanah bug #17479.
160
161 theSeed = seed ? seed : 4357;
162 int mti;
163 const int N1=624;
164 mt[0] = (unsigned int) (theSeed&0xffffffffUL);
165 for (mti=1; mti<N1; mti++) {
166 mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
167 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
168 /* In the previous versions, MSBs of the seed affect */
169 /* only MSBs of the array mt[]. */
170 /* 2002/01/09 modified by Makoto Matsumoto */
171 mt[mti] &= 0xffffffffUL;
172 /* for >32 bit machines */
173 }
174 for( int i=1; i < 624; ++i ) {
175 mt[i] ^= k; // MF 9/16/98: distinguish starting points
176 }
177 // MF 11/15/06 This distinction of starting points based on values of k
178 // is kept even though the seeding algorithm itself is improved.
179}
180
181void MTwistEngine::setSeeds(const long *seeds, int k) {
182 setSeed( (*seeds ? *seeds : 43571346), k );
183 int i;
184 for( i=1; i < 624; ++i ) {
185 mt[i] = ( seeds[1] + mt[i] ) & 0xffffffff; // MF 9/16/98
186 }
187 theSeeds = seeds;
188}
189
190void MTwistEngine::saveStatus( const char filename[] ) const
191{
192 std::ofstream outFile( filename, std::ios::out ) ;
193 if (!outFile.bad()) {
194 outFile << theSeed << std::endl;
195 for (int i=0; i<624; ++i) outFile <<std::setprecision(20) << mt[i] << " ";
196 outFile << std::endl;
197 outFile << count624 << std::endl;
198 }
199}
200
201void MTwistEngine::restoreStatus( const char filename[] )
202{
203 std::ifstream inFile( filename, std::ios::in);
204 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
205 std::cerr << " -- Engine state remains unchanged\n";
206 return;
207 }
208
209 if (!inFile.bad() && !inFile.eof()) {
210 inFile >> theSeed;
211 for (int i=0; i<624; ++i) inFile >> mt[i];
212 inFile >> count624;
213 }
214}
215
217{
218 std::cout << std::endl;
219 std::cout << "--------- MTwist engine status ---------" << std::endl;
220 std::cout << std::setprecision(20);
221 std::cout << " Initial seed = " << theSeed << std::endl;
222 std::cout << " Current index = " << count624 << std::endl;
223 std::cout << " Array status mt[] = " << std::endl;
224 // 2014/06/06 L Garren
225 // the final line has 4 elements, not 5
226 for (int i=0; i<620; i+=5) {
227 std::cout << mt[i] << " " << mt[i+1] << " " << mt[i+2] << " "
228 << mt[i+3] << " " << mt[i+4] << "\n";
229 }
230 std::cout << mt[620] << " " << mt[621] << " " << mt[622] << " "
231 << mt[623] << std::endl;
232 std::cout << "----------------------------------------" << std::endl;
233}
234
235MTwistEngine::operator double() {
236 return flat();
237}
238
239MTwistEngine::operator float() {
240 unsigned int y;
241
242 if( count624 >= N ) {
243 int i;
244
245 for( i=0; i < NminusM; ++i ) {
246 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
247 mt[i] = mt[i+M] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
248 }
249
250 for( ; i < N-1 ; ++i ) {
251 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
252 mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
253 }
254
255 y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
256 mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
257
258 count624 = 0;
259 }
260
261 y = mt[count624++];
262 y ^= ( y >> 11);
263 y ^= ((y << 7 ) & 0x9d2c5680);
264 y ^= ((y << 15) & 0xefc60000);
265 y ^= ( y >> 18);
266
267 return (float)(y * twoToMinus_32());
268}
269
270MTwistEngine::operator unsigned int() {
271 unsigned int y;
272
273 if( count624 >= N ) {
274 int i;
275
276 for( i=0; i < NminusM; ++i ) {
277 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
278 mt[i] = mt[i+M] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
279 }
280
281 for( ; i < N-1 ; ++i ) {
282 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff);
283 mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
284 }
285
286 y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff);
287 mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 );
288
289 count624 = 0;
290 }
291
292 y = mt[count624++];
293 y ^= ( y >> 11);
294 y ^= ((y << 7 ) & 0x9d2c5680);
295 y ^= ((y << 15) & 0xefc60000);
296 y ^= ( y >> 18);
297
298 return y;
299}
300
301std::ostream & MTwistEngine::put ( std::ostream& os ) const
302{
303 char beginMarker[] = "MTwistEngine-begin";
304 char endMarker[] = "MTwistEngine-end";
305
306 int pr = os.precision(20);
307 os << " " << beginMarker << " ";
308 os << theSeed << " ";
309 for (int i=0; i<624; ++i) {
310 os << mt[i] << "\n";
311 }
312 os << count624 << " ";
313 os << endMarker << "\n";
314 os.precision(pr);
315 return os;
316}
317
318std::vector<unsigned long> MTwistEngine::put () const {
319 std::vector<unsigned long> v;
320 v.push_back (engineIDulong<MTwistEngine>());
321 for (int i=0; i<624; ++i) {
322 v.push_back(static_cast<unsigned long>(mt[i]));
323 }
324 v.push_back(count624);
325 return v;
326}
327
328std::istream & MTwistEngine::get ( std::istream& is )
329{
330 char beginMarker [MarkerLen];
331 is >> std::ws;
332 is.width(MarkerLen); // causes the next read to the char* to be <=
333 // that many bytes, INCLUDING A TERMINATION \0
334 // (Stroustrup, section 21.3.2)
335 is >> beginMarker;
336 if (strcmp(beginMarker,"MTwistEngine-begin")) {
337 is.clear(std::ios::badbit | is.rdstate());
338 std::cerr << "\nInput stream mispositioned or"
339 << "\nMTwistEngine state description missing or"
340 << "\nwrong engine type found." << std::endl;
341 return is;
342 }
343 return getState(is);
344}
345
346std::string MTwistEngine::beginTag ( ) {
347 return "MTwistEngine-begin";
348}
349
350std::istream & MTwistEngine::getState ( std::istream& is )
351{
352 char endMarker [MarkerLen];
353 is >> theSeed;
354 for (int i=0; i<624; ++i) is >> mt[i];
355 is >> count624;
356 is >> std::ws;
357 is.width(MarkerLen);
358 is >> endMarker;
359 if (strcmp(endMarker,"MTwistEngine-end")) {
360 is.clear(std::ios::badbit | is.rdstate());
361 std::cerr << "\nMTwistEngine state description incomplete."
362 << "\nInput stream is probably mispositioned now." << std::endl;
363 return is;
364 }
365 return is;
366}
367
368bool MTwistEngine::get (const std::vector<unsigned long> & v) {
369 if ((v[0] & 0xffffffffUL) != engineIDulong<MTwistEngine>()) {
370 std::cerr <<
371 "\nMTwistEngine get:state vector has wrong ID word - state unchanged\n";
372 return false;
373 }
374 return getState(v);
375}
376
377bool MTwistEngine::getState (const std::vector<unsigned long> & v) {
378 if (v.size() != VECTOR_STATE_SIZE ) {
379 std::cerr <<
380 "\nMTwistEngine get:state vector has wrong length - state unchanged\n";
381 return false;
382 }
383 for (int i=0; i<624; ++i) {
384 mt[i]=v[i+1];
385 }
386 count624 = v[625];
387 return true;
388}
389
390} // namespace CLHEP
#define M(row, col)
#define CLHEP_ATOMIC_INT_TYPE
Definition: atomic_int.h:14
static double twoToMinus_32()
static double twoToMinus_53()
static double nearlyTwoToMinus_54()
static bool checkFile(std::istream &file, const std::string &filename, const std::string &classname, const std::string &methodname)
Definition: RandomEngine.cc:47
static void getTheTableSeeds(long *seeds, int index)
Definition: Random.cc:254
virtual std::istream & get(std::istream &is)
virtual std::istream & getState(std::istream &is)
void flatArray(const int size, double *vect)
void restoreStatus(const char filename[]="MTwist.conf")
static std::string engineName()
Definition: MTwistEngine.h:77
void setSeeds(const long *seeds, int)
void showStatus() const
void saveStatus(const char filename[]="MTwist.conf") const
std::vector< unsigned long > put() const
std::string name() const
Definition: MTwistEngine.cc:64
static const unsigned int VECTOR_STATE_SIZE
Definition: MTwistEngine.h:83
void setSeed(long seed, int)
static std::string beginTag()
#define N
Definition: crc32.c:56
Definition: DoubConv.h:17