1 // $Id: RandGauss.cc,v 1.6 2010/06/16 17:24:53 garren Exp $
2 // -*- C++ -*-
3 //
4 // -----------------------------------------------------------------------
5 // HEP Random
6 // --- RandGauss ---
7 // class implementation file
8 // -----------------------------------------------------------------------
9 // This file is part of Geant4 (simulation toolkit for HEP).
10
11 // =======================================================================
12 // Gabriele Cosmo - Created: 5th September 1995
13 // - Added methods to shoot arrays: 28th July 1997
14 // J.Marraffino - Added default arguments as attributes and
15 // operator() with arguments. Introduced method normal()
16 // for computation in fire(): 16th Feb 1998
17 // Gabriele Cosmo - Relocated static data from HepRandom: 5th Jan 1999
18 // M Fischler - Copy constructor should supply right engine to HepRandom:
19 // 1/26/00.
20 // M Fischler - Workaround for problem of non-reproducing saveEngineStatus
21 // by saving cached gaussian. March 2000.
22 // M Fischler - Avoiding hang when file not found in restoreEngineStatus
23 // 12/3/04
24 // M Fischler - put and get to/from streams 12/8/04
25 // M Fischler - save and restore dist to streams 12/20/04
26 // M Fischler - put/get to/from streams uses pairs of ulongs when
27 // storing doubles avoid problems with precision.
28 // Similarly for saveEngineStatus and RestoreEngineStatus
29 // and for save/restore distState
30 // Care was taken that old-form output can still be read back.
31 // 4/14/05
32 //
33 // =======================================================================
34
35 #include "CLHEP/Random/defs.h"
36 #include "CLHEP/Random/RandGauss.h"
37 #include "CLHEP/Random/DoubConv.hh"
38 #include <string.h> // for strcmp
39 #include <cmath> // for std::log()
40
41 namespace CLHEP {
42
name() const43 std::string RandGauss::name() const {return "RandGauss";}
engine()44 HepRandomEngine & RandGauss::engine() {return *localEngine;}
45
46 // Initialisation of static data
47 CLHEP_THREAD_LOCAL bool RandGauss::set_st = false;
48 CLHEP_THREAD_LOCAL double RandGauss::nextGauss_st = 0.0;
49
~RandGauss()50 RandGauss::~RandGauss() {
51 }
52
operator ()()53 double RandGauss::operator()() {
54 return fire( defaultMean, defaultStdDev );
55 }
56
operator ()(double mean,double stdDev)57 double RandGauss::operator()( double mean, double stdDev ) {
58 return fire( mean, stdDev );
59 }
60
61 // implement static methods dealing with static data here
getFlag()62 bool RandGauss::getFlag() {return set_st;}
63
setFlag(bool val)64 void RandGauss::setFlag( bool val ) {set_st = val;}
65
getVal()66 double RandGauss::getVal() {return nextGauss_st;}
67
setVal(double nextVal)68 void RandGauss::setVal( double nextVal ) {nextGauss_st = nextVal;}
69
shoot()70 double RandGauss::shoot()
71 {
72 // Gaussian random numbers are generated two at the time, so every other
73 // time this is called we just return a number generated the time before.
74
75 if ( getFlag() ) {
76 setFlag(false);
77 double x = getVal();
78 return x;
79 // return getVal();
80 }
81
82 double r;
83 double v1,v2,fac,val;
84 HepRandomEngine* anEngine = HepRandom::getTheEngine();
85
86 do {
87 v1 = 2.0 * anEngine->flat() - 1.0;
88 v2 = 2.0 * anEngine->flat() - 1.0;
89 r = v1*v1 + v2*v2;
90 } while ( r > 1.0 );
91
92 fac = std::sqrt(-2.0*std::log(r)/r);
93 val = v1*fac;
94 setVal(val);
95 setFlag(true);
96 return v2*fac;
97 }
98
shootArray(const int size,double * vect,double mean,double stdDev)99 void RandGauss::shootArray( const int size, double* vect,
100 double mean, double stdDev )
101 {
102 for( double* v = vect; v != vect + size; ++v )
103 *v = shoot(mean,stdDev);
104 }
105
shoot(HepRandomEngine * anEngine)106 double RandGauss::shoot( HepRandomEngine* anEngine )
107 {
108 // Gaussian random numbers are generated two at the time, so every other
109 // time this is called we just return a number generated the time before.
110
111 if ( getFlag() ) {
112 setFlag(false);
113 return getVal();
114 }
115
116 double r;
117 double v1,v2,fac,val;
118
119 do {
120 v1 = 2.0 * anEngine->flat() - 1.0;
121 v2 = 2.0 * anEngine->flat() - 1.0;
122 r = v1*v1 + v2*v2;
123 } while ( r > 1.0 );
124
125 fac = std::sqrt( -2.0*std::log(r)/r);
126 val = v1*fac;
127 setVal(val);
128 setFlag(true);
129 return v2*fac;
130 }
131
shootArray(HepRandomEngine * anEngine,const int size,double * vect,double mean,double stdDev)132 void RandGauss::shootArray( HepRandomEngine* anEngine,
133 const int size, double* vect,
134 double mean, double stdDev )
135 {
136 for( double* v = vect; v != vect + size; ++v )
137 *v = shoot(anEngine,mean,stdDev);
138 }
139
normal()140 double RandGauss::normal()
141 {
142 // Gaussian random numbers are generated two at the time, so every other
143 // time this is called we just return a number generated the time before.
144
145 if ( set ) {
146 set = false;
147 return nextGauss;
148 }
149
150 double r;
151 double v1,v2,fac,val;
152
153 do {
154 v1 = 2.0 * localEngine->flat() - 1.0;
155 v2 = 2.0 * localEngine->flat() - 1.0;
156 r = v1*v1 + v2*v2;
157 } while ( r > 1.0 );
158
159 fac = std::sqrt(-2.0*std::log(r)/r);
160 val = v1*fac;
161 nextGauss = val;
162 set = true;
163 return v2*fac;
164 }
165
fireArray(const int size,double * vect)166 void RandGauss::fireArray( const int size, double* vect)
167 {
168 for( double* v = vect; v != vect + size; ++v )
169 *v = fire( defaultMean, defaultStdDev );
170 }
171
fireArray(const int size,double * vect,double mean,double stdDev)172 void RandGauss::fireArray( const int size, double* vect,
173 double mean, double stdDev )
174 {
175 for( double* v = vect; v != vect + size; ++v )
176 *v = fire( mean, stdDev );
177 }
178
saveEngineStatus(const char filename[])179 void RandGauss::saveEngineStatus ( const char filename[] ) {
180
181 // First save the engine status just like the base class would do:
182 getTheEngine()->saveStatus( filename );
183
184 // Now append the cached variate, if any:
185
186 std::ofstream outfile ( filename, std::ios::app );
187
188 if ( getFlag() ) {
189 std::vector<unsigned long> t(2);
190 t = DoubConv::dto2longs(getVal());
191 outfile << "RANDGAUSS CACHED_GAUSSIAN: Uvec "
192 << getVal() << " " << t[0] << " " << t[1] << "\n";
193 } else {
194 outfile << "RANDGAUSS NO_CACHED_GAUSSIAN: 0 \n" ;
195 }
196
197 } // saveEngineStatus
198
restoreEngineStatus(const char filename[])199 void RandGauss::restoreEngineStatus( const char filename[] ) {
200
201 // First restore the engine status just like the base class would do:
202 getTheEngine()->restoreStatus( filename );
203
204 // Now find the line describing the cached variate:
205
206 std::ifstream infile ( filename, std::ios::in );
207 if (!infile) return;
208
209 char inputword[] = "NO_KEYWORD "; // leaves room for 14 characters plus \0
210 while (true) {
211 infile.width(13);
212 infile >> inputword;
213 if (strcmp(inputword,"RANDGAUSS")==0) break;
214 if (infile.eof()) break;
215 // If the file ends without the RANDGAUSS line, that means this
216 // was a file produced by an earlier version of RandGauss. We will
217 // replicated the old behavior in that case: set_st is cleared.
218 }
219
220 // Then read and use the caching info:
221
222 if (strcmp(inputword,"RANDGAUSS")==0) {
223 char setword[40]; // the longest, staticFirstUnusedBit: has length 21
224 infile.width(39);
225 infile >> setword; // setword should be CACHED_GAUSSIAN:
226 if (strcmp(setword,"CACHED_GAUSSIAN:") ==0) {
227 if (possibleKeywordInput(infile, "Uvec", nextGauss_st)) {
228 std::vector<unsigned long> t(2);
229 infile >> nextGauss_st >> t[0] >> t[1];
230 nextGauss_st = DoubConv::longs2double(t);
231 }
232 // is >> nextGauss_st encompassed by possibleKeywordInput
233 setFlag(true);
234 } else {
235 setFlag(false);
236 infile >> nextGauss_st; // because a 0 will have been output
237 }
238 } else {
239 setFlag(false);
240 }
241
242 } // restoreEngineStatus
243
244 // Save and restore to/from streams
245
put(std::ostream & os) const246 std::ostream & RandGauss::put ( std::ostream & os ) const {
247 os << name() << "\n";
248 int prec = os.precision(20);
249 std::vector<unsigned long> t(2);
250 os << "Uvec\n";
251 t = DoubConv::dto2longs(defaultMean);
252 os << defaultMean << " " << t[0] << " " << t[1] << "\n";
253 t = DoubConv::dto2longs(defaultStdDev);
254 os << defaultStdDev << " " << t[0] << " " << t[1] << "\n";
255 if ( set ) {
256 t = DoubConv::dto2longs(nextGauss);
257 os << "nextGauss " << nextGauss << " " << t[0] << " " << t[1] << "\n";
258 #ifdef TRACE_IO
259 std::cout << "put(): nextGauss = " << nextGauss << "\n";
260 #endif
261 } else {
262 #ifdef TRACE_IO
263 std::cout << "put(): No nextGauss \n";
264 #endif
265 os << "no_cached_nextGauss \n";
266 }
267 os.precision(prec);
268 return os;
269 } // put
270
get(std::istream & is)271 std::istream & RandGauss::get ( std::istream & is ) {
272 std::string inName;
273 is >> inName;
274 if (inName != name()) {
275 is.clear(std::ios::badbit | is.rdstate());
276 std::cerr << "Mismatch when expecting to read state of a "
277 << name() << " distribution\n"
278 << "Name found was " << inName
279 << "\nistream is left in the badbit state\n";
280 return is;
281 }
282 std::string c1;
283 std::string c2;
284 if (possibleKeywordInput(is, "Uvec", c1)) {
285 std::vector<unsigned long> t(2);
286 is >> defaultMean >> t[0] >> t[1]; defaultMean = DoubConv::longs2double(t);
287 is >> defaultStdDev>>t[0]>>t[1]; defaultStdDev = DoubConv::longs2double(t);
288 std::string ng;
289 is >> ng;
290 set = false;
291 #ifdef TRACE_IO
292 if (ng != "nextGauss")
293 std::cout << "get(): ng = " << ng << "\n";
294 #endif
295 if (ng == "nextGauss") {
296 is >> nextGauss >> t[0] >> t[1]; nextGauss = DoubConv::longs2double(t);
297 #ifdef TRACE_IO
298 std::cout << "get(): nextGauss read back as " << nextGauss << "\n";
299 #endif
300 set = true;
301 }
302 return is;
303 }
304 // is >> c1 encompassed by possibleKeywordInput
305 is >> defaultMean >> c2 >> defaultStdDev;
306 if ( (!is) || (c1 != "Mean:") || (c2 != "Sigma:") ) {
307 std::cerr << "i/o problem while expecting to read state of a "
308 << name() << " distribution\n"
309 << "default mean and/or sigma could not be read\n";
310 return is;
311 }
312 is >> c1 >> c2 >> nextGauss;
313 if ( (!is) || (c1 != "RANDGAUSS") ) {
314 is.clear(std::ios::badbit | is.rdstate());
315 std::cerr << "Failure when reading caching state of RandGauss\n";
316 return is;
317 }
318 if (c2 == "CACHED_GAUSSIAN:") {
319 set = true;
320 } else if (c2 == "NO_CACHED_GAUSSIAN:") {
321 set = false;
322 } else {
323 is.clear(std::ios::badbit | is.rdstate());
324 std::cerr << "Unexpected caching state keyword of RandGauss:" << c2
325 << "\nistream is left in the badbit state\n";
326 }
327 return is;
328 } // get
329
330 // Static save and restore to/from streams
331
saveDistState(std::ostream & os)332 std::ostream & RandGauss::saveDistState ( std::ostream & os ) {
333 int prec = os.precision(20);
334 std::vector<unsigned long> t(2);
335 os << distributionName() << "\n";
336 os << "Uvec\n";
337 if ( getFlag() ) {
338 t = DoubConv::dto2longs(getVal());
339 os << "nextGauss_st " << getVal() << " " << t[0] << " " << t[1] << "\n";
340 } else {
341 os << "no_cached_nextGauss_st \n";
342 }
343 os.precision(prec);
344 return os;
345 }
346
restoreDistState(std::istream & is)347 std::istream & RandGauss::restoreDistState ( std::istream & is ) {
348 std::string inName;
349 is >> inName;
350 if (inName != distributionName()) {
351 is.clear(std::ios::badbit | is.rdstate());
352 std::cerr << "Mismatch when expecting to read static state of a "
353 << distributionName() << " distribution\n"
354 << "Name found was " << inName
355 << "\nistream is left in the badbit state\n";
356 return is;
357 }
358 std::string c1;
359 std::string c2;
360 if (possibleKeywordInput(is, "Uvec", c1)) {
361 std::vector<unsigned long> t(2);
362 std::string ng;
363 is >> ng;
364 setFlag (false);
365 if (ng == "nextGauss_st") {
366 is >> nextGauss_st >> t[0] >> t[1];
367 nextGauss_st = DoubConv::longs2double(t);
368 setFlag (true);
369 }
370 return is;
371 }
372 // is >> c1 encompassed by possibleKeywordInput
373 is >> c2 >> nextGauss_st;
374 if ( (!is) || (c1 != "RANDGAUSS") ) {
375 is.clear(std::ios::badbit | is.rdstate());
376 std::cerr << "Failure when reading caching state of static RandGauss\n";
377 return is;
378 }
379 if (c2 == "CACHED_GAUSSIAN:") {
380 setFlag(true);
381 } else if (c2 == "NO_CACHED_GAUSSIAN:") {
382 setFlag(false);
383 } else {
384 is.clear(std::ios::badbit | is.rdstate());
385 std::cerr << "Unexpected caching state keyword of static RandGauss:" << c2
386 << "\nistream is left in the badbit state\n";
387 }
388 return is;
389 }
390
saveFullState(std::ostream & os)391 std::ostream & RandGauss::saveFullState ( std::ostream & os ) {
392 HepRandom::saveFullState(os);
393 saveDistState(os);
394 return os;
395 }
396
restoreFullState(std::istream & is)397 std::istream & RandGauss::restoreFullState ( std::istream & is ) {
398 HepRandom::restoreFullState(is);
399 restoreDistState(is);
400 return is;
401 }
402
403 } // namespace CLHEP
404
405