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